diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-03-18 23:02:30 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-03-18 23:02:30 +0300 |
commit | 41fe97390ceddf945f3d967b8fdb3de4c66b7dea (patch) | |
tree | 9c8d89a8624828992f06d892cd2f43818ff5dcc8 /app/assets/javascripts/pipelines/components/pipelines_list | |
parent | 0804d2dc31052fb45a1efecedc8e06ce9bc32862 (diff) |
Add latest changes from gitlab-org/gitlab@14-9-stable-eev14.9.0-rc42
Diffstat (limited to 'app/assets/javascripts/pipelines/components/pipelines_list')
11 files changed, 449 insertions, 594 deletions
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 1ce6654e0e9..0380ba646cc 100644 --- a/app/assets/javascripts/pipelines/components/pipelines_list/empty_state.vue +++ b/app/assets/javascripts/pipelines/components/pipelines_list/empty_state.vue @@ -1,33 +1,15 @@ <script> -import { GlEmptyState, GlButton } from '@gitlab/ui'; -import { startCodeQualityWalkthrough, track } from '~/code_quality_walkthrough/utils'; -import GitlabExperiment from '~/experimentation/components/gitlab_experiment.vue'; -import ExperimentTracking from '~/experimentation/experiment_tracking'; -import { getExperimentData } from '~/experimentation/utils'; -import { helpPagePath } from '~/helpers/help_page_helper'; +import { GlEmptyState } from '@gitlab/ui'; import { s__ } from '~/locale'; import PipelinesCiTemplates from './pipelines_ci_templates.vue'; export default { i18n: { - title: s__('Pipelines|Build with confidence'), - description: s__(`Pipelines|GitLab CI/CD can automatically build, - test, and deploy your code. Let GitLab take care of time - consuming tasks, so you can spend more time creating.`), - aboutRunnersBtnText: s__('Pipelines|Learn about Runners'), - installRunnersBtnText: s__('Pipelines|Install GitLab Runners'), - codeQualityTitle: s__('Pipelines|Improve code quality with GitLab CI/CD'), - codeQualityDescription: s__(`Pipelines|To keep your codebase simple, - readable, and accessible to contributors, use GitLab CI/CD - to analyze your code quality with every push to your project.`), - codeQualityBtnText: s__('Pipelines|Add a code quality job'), noCiDescription: s__('Pipelines|This project is not currently set up to run pipelines.'), }, name: 'PipelinesEmptyState', components: { GlEmptyState, - GlButton, - GitlabExperiment, PipelinesCiTemplates, }, props: { @@ -39,88 +21,26 @@ export default { type: Boolean, required: true, }, - codeQualityPagePath: { - type: String, - required: false, - default: null, - }, ciRunnerSettingsPath: { type: String, required: false, default: null, }, - }, - computed: { - ciHelpPagePath() { - return helpPagePath('ci/quick_start/index.md'); - }, - isCodeQualityExperimentActive() { - return this.canSetCi && Boolean(getExperimentData('code_quality_walkthrough')); - }, - isCiRunnerTemplatesExperimentActive() { - return this.canSetCi && Boolean(getExperimentData('ci_runner_templates')); - }, - }, - mounted() { - startCodeQualityWalkthrough(); - }, - methods: { - trackClick() { - track('cta_clicked'); - }, - trackCiRunnerTemplatesClick(action) { - const tracking = new ExperimentTracking('ci_runner_templates'); - tracking.event(action); + anyRunnersAvailable: { + type: Boolean, + required: false, + default: true, }, }, }; </script> <template> <div> - <gitlab-experiment v-if="isCodeQualityExperimentActive" name="code_quality_walkthrough"> - <template #control><pipelines-ci-templates /></template> - <template #candidate> - <gl-empty-state - :title="$options.i18n.codeQualityTitle" - :svg-path="emptyStateSvgPath" - :description="$options.i18n.codeQualityDescription" - > - <template #actions> - <gl-button :href="codeQualityPagePath" variant="confirm" @click="trackClick()"> - {{ $options.i18n.codeQualityBtnText }} - </gl-button> - </template> - </gl-empty-state> - </template> - </gitlab-experiment> - <gitlab-experiment v-else-if="isCiRunnerTemplatesExperimentActive" name="ci_runner_templates"> - <template #control><pipelines-ci-templates /></template> - <template #candidate> - <gl-empty-state - :title="$options.i18n.title" - :svg-path="emptyStateSvgPath" - :description="$options.i18n.description" - > - <template #actions> - <gl-button - :href="ciRunnerSettingsPath" - variant="confirm" - @click="trackCiRunnerTemplatesClick('install_runners_button_clicked')" - > - {{ $options.i18n.installRunnersBtnText }} - </gl-button> - <gl-button - :href="ciHelpPagePath" - variant="default" - @click="trackCiRunnerTemplatesClick('learn_button_clicked')" - > - {{ $options.i18n.aboutRunnersBtnText }} - </gl-button> - </template> - </gl-empty-state> - </template> - </gitlab-experiment> - <pipelines-ci-templates v-else-if="canSetCi" /> + <pipelines-ci-templates + v-if="canSetCi" + :ci-runner-settings-path="ciRunnerSettingsPath" + :any-runners-available="anyRunnersAvailable" + /> <gl-empty-state v-else title="" diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_labels.vue b/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_labels.vue new file mode 100644 index 00000000000..40b2454b8c1 --- /dev/null +++ b/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_labels.vue @@ -0,0 +1,170 @@ +<script> +import { GlLink, GlPopover, GlSprintf, GlTooltipDirective, GlBadge } from '@gitlab/ui'; +import { helpPagePath } from '~/helpers/help_page_helper'; +import { SCHEDULE_ORIGIN } from '../../constants'; + +export default { + components: { + GlBadge, + GlLink, + GlPopover, + GlSprintf, + }, + directives: { + GlTooltip: GlTooltipDirective, + }, + inject: { + targetProjectFullPath: { + default: '', + }, + }, + props: { + pipeline: { + type: Object, + required: true, + }, + pipelineScheduleUrl: { + type: String, + required: true, + }, + }, + computed: { + isScheduled() { + return this.pipeline.source === SCHEDULE_ORIGIN; + }, + isInFork() { + return Boolean( + this.targetProjectFullPath && + this.pipeline?.project?.full_path !== `/${this.targetProjectFullPath}`, + ); + }, + autoDevopsTagId() { + return `pipeline-url-autodevops-${this.pipeline.id}`; + }, + autoDevopsHelpPath() { + return helpPagePath('topics/autodevops/index.md'); + }, + }, +}; +</script> +<template> + <div class="label-container gl-mt-1"> + <gl-badge + v-if="isScheduled" + v-gl-tooltip + :href="pipelineScheduleUrl" + target="__blank" + :title="__('This pipeline was triggered by a schedule.')" + variant="info" + size="sm" + data-testid="pipeline-url-scheduled" + >{{ __('Scheduled') }}</gl-badge + > + <gl-badge + v-if="pipeline.flags.latest" + v-gl-tooltip + :title="__('Latest pipeline for the most recent commit on this branch')" + variant="success" + size="sm" + data-testid="pipeline-url-latest" + >{{ __('latest') }}</gl-badge + > + <gl-badge + v-if="pipeline.flags.merge_train_pipeline" + 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.', + ) + " + variant="info" + size="sm" + data-testid="pipeline-url-train" + >{{ s__('Pipeline|merge train') }}</gl-badge + > + <gl-badge + v-if="pipeline.flags.yaml_errors" + v-gl-tooltip + :title="pipeline.yaml_errors" + variant="danger" + size="sm" + data-testid="pipeline-url-yaml" + >{{ __('yaml invalid') }}</gl-badge + > + <gl-badge + v-if="pipeline.flags.failure_reason" + v-gl-tooltip + :title="pipeline.failure_reason" + variant="danger" + size="sm" + data-testid="pipeline-url-failure" + >{{ __('error') }}</gl-badge + > + <template v-if="pipeline.flags.auto_devops"> + <gl-link + :id="autoDevopsTagId" + tabindex="0" + data-testid="pipeline-url-autodevops" + role="button" + > + <gl-badge variant="info" size="sm"> + {{ __('Auto DevOps') }} + </gl-badge> + </gl-link> + <gl-popover :target="autoDevopsTagId" triggers="focus" placement="top"> + <template #title> + <div class="gl-font-weight-normal gl-line-height-normal"> + <gl-sprintf + :message=" + __( + 'This pipeline makes use of a predefined CI/CD configuration enabled by %{strongStart}Auto DevOps.%{strongEnd}', + ) + " + > + <template #strong="{ content }"> + <b>{{ content }}</b> + </template> + </gl-sprintf> + </div> + </template> + <gl-link + :href="autoDevopsHelpPath" + data-testid="pipeline-url-autodevops-link" + target="_blank" + > + {{ __('Learn more about Auto DevOps') }} + </gl-link> + </gl-popover> + </template> + + <gl-badge + v-if="pipeline.flags.stuck" + variant="warning" + size="sm" + data-testid="pipeline-url-stuck" + >{{ __('stuck') }}</gl-badge + > + <gl-badge + v-if="pipeline.flags.detached_merge_request_pipeline" + v-gl-tooltip + :title=" + s__( + `Pipeline|This pipeline ran on the contents of this merge request's source branch, not the target branch.`, + ) + " + variant="info" + size="sm" + data-testid="pipeline-url-detached" + >{{ s__('Pipeline|merge request') }}</gl-badge + > + <gl-badge + v-if="isInFork" + v-gl-tooltip + :title="__('Pipeline ran in fork of project')" + variant="info" + size="sm" + data-testid="pipeline-url-fork" + >{{ __('fork') }}</gl-badge + > + </div> +</template> 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 7c78abae77f..1dcbd77a92d 100644 --- a/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_url.vue +++ b/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_url.vue @@ -1,29 +1,20 @@ <script> -import { GlIcon, GlLink, GlPopover, GlSprintf, GlTooltipDirective, GlBadge } from '@gitlab/ui'; -import { __, sprintf } from '~/locale'; -import { helpPagePath } from '~/helpers/help_page_helper'; -import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; +import { GlIcon, GlLink, GlTooltipDirective } from '@gitlab/ui'; +import { __ } from '~/locale'; import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue'; -import { SCHEDULE_ORIGIN, ICONS } from '../../constants'; +import { ICONS } from '../../constants'; +import PipelineLabels from './pipeline_labels.vue'; export default { components: { GlIcon, GlLink, - GlPopover, - GlSprintf, - GlBadge, + PipelineLabels, TooltipOnTruncate, }, directives: { GlTooltip: GlTooltipDirective, }, - mixins: [glFeatureFlagMixin()], - inject: { - targetProjectFullPath: { - default: '', - }, - }, props: { pipeline: { type: Object, @@ -37,27 +28,8 @@ export default { type: String, required: true, }, - viewType: { - type: String, - required: true, - }, }, computed: { - isScheduled() { - return this.pipeline.source === SCHEDULE_ORIGIN; - }, - isInFork() { - return Boolean( - this.targetProjectFullPath && - this.pipeline?.project?.full_path !== `/${this.targetProjectFullPath}`, - ); - }, - autoDevopsTagId() { - return `pipeline-url-autodevops-${this.pipeline.id}`; - }, - autoDevopsHelpPath() { - return helpPagePath('topics/autodevops/index.md'); - }, mergeRequestRef() { return this.pipeline?.merge_request; }, @@ -139,205 +111,66 @@ export default { commitTitle() { return this.pipeline?.commit?.title; }, - hasAuthor() { - return ( - this.commitAuthor?.avatar_url && this.commitAuthor?.path && this.commitAuthor?.username - ); - }, - userImageAltDescription() { - return this.commitAuthor?.username - ? sprintf(__("%{username}'s avatar"), { username: this.commitAuthor.username }) - : null; - }, - rearrangePipelinesTable() { - return this.glFeatures?.rearrangePipelinesTable; - }, }, }; </script> <template> <div class="pipeline-tags" data-testid="pipeline-url-table-cell"> - <template v-if="rearrangePipelinesTable"> - <div class="commit-title gl-mb-2" data-testid="commit-title-container"> - <span v-if="commitTitle" class="gl-display-flex"> - <tooltip-on-truncate :title="commitTitle" class="flex-truncate-child gl-flex-grow-1"> - <gl-link - :href="commitUrl" - class="commit-row-message gl-text-gray-900" - data-testid="commit-title" - >{{ commitTitle }}</gl-link - > - </tooltip-on-truncate> - </span> - <span v-else>{{ __("Can't find HEAD commit for this branch") }}</span> - </div> - <div class="gl-mb-2"> - <gl-link - :href="pipeline.path" - class="gl-text-decoration-underline gl-text-blue-600!" - data-testid="pipeline-url-link" - data-qa-selector="pipeline_url_link" - > - #{{ pipeline[pipelineKey] }} - </gl-link> - <!--Commit row--> - <div class="icon-container gl-display-inline-block"> - <gl-icon - v-gl-tooltip - :name="commitIcon" - :title="commitIconTooltipTitle" - data-testid="commit-icon-type" - /> - </div> - <tooltip-on-truncate :title="tooltipTitle" truncate-target="child" placement="top"> + <div class="commit-title gl-mb-2" data-testid="commit-title-container"> + <span v-if="commitTitle" class="gl-display-flex"> + <tooltip-on-truncate :title="commitTitle" class="gl-flex-grow-1 gl-text-truncate"> <gl-link - v-if="mergeRequestRef" - :href="mergeRequestRef.path" - class="ref-name" - data-testid="merge-request-ref" - >{{ mergeRequestRef.iid }}</gl-link + :href="commitUrl" + class="commit-row-message gl-text-gray-900" + data-testid="commit-title" + >{{ commitTitle }}</gl-link > - <gl-link v-else :href="refUrl" class="ref-name" data-testid="commit-ref-name">{{ - commitRef.name - }}</gl-link> </tooltip-on-truncate> + </span> + <span v-else>{{ __("Can't find HEAD commit for this branch") }}</span> + </div> + <div class="gl-mb-2"> + <gl-link + :href="pipeline.path" + class="gl-text-decoration-underline gl-text-blue-600! gl-mr-3" + data-testid="pipeline-url-link" + data-qa-selector="pipeline_url_link" + > + #{{ pipeline[pipelineKey] }} + </gl-link> + <!--Commit row--> + <div class="icon-container gl-display-inline-block gl-mr-1"> <gl-icon v-gl-tooltip - name="commit" - class="commit-icon" - :title="__('Commit')" - data-testid="commit-icon" + :name="commitIcon" + :title="commitIconTooltipTitle" + data-testid="commit-icon-type" /> - - <gl-link :href="commitUrl" class="commit-sha mr-0" data-testid="commit-short-sha">{{ - commitShortSha - }}</gl-link> - <!--End of commit row--> </div> - </template> - <gl-link - v-if="!rearrangePipelinesTable" - :href="pipeline.path" - class="gl-text-decoration-underline" - data-testid="pipeline-url-link" - data-qa-selector="pipeline_url_link" - > - #{{ pipeline[pipelineKey] }} - </gl-link> - <div class="label-container gl-mt-1"> - <gl-badge - v-if="isScheduled" - v-gl-tooltip - :href="pipelineScheduleUrl" - target="__blank" - :title="__('This pipeline was triggered by a schedule.')" - variant="info" - size="sm" - data-testid="pipeline-url-scheduled" - >{{ __('Scheduled') }}</gl-badge - > - <gl-badge - v-if="pipeline.flags.latest" - v-gl-tooltip - :title="__('Latest pipeline for the most recent commit on this branch')" - variant="success" - size="sm" - data-testid="pipeline-url-latest" - >{{ __('latest') }}</gl-badge - > - <gl-badge - v-if="pipeline.flags.merge_train_pipeline" - v-gl-tooltip - :title="__('This is a merge train pipeline')" - variant="info" - size="sm" - data-testid="pipeline-url-train" - >{{ __('train') }}</gl-badge - > - <gl-badge - v-if="pipeline.flags.yaml_errors" - v-gl-tooltip - :title="pipeline.yaml_errors" - variant="danger" - size="sm" - data-testid="pipeline-url-yaml" - >{{ __('yaml invalid') }}</gl-badge - > - <gl-badge - v-if="pipeline.flags.failure_reason" - v-gl-tooltip - :title="pipeline.failure_reason" - variant="danger" - size="sm" - data-testid="pipeline-url-failure" - >{{ __('error') }}</gl-badge - > - <template v-if="pipeline.flags.auto_devops"> + <tooltip-on-truncate :title="tooltipTitle" truncate-target="child" placement="top"> <gl-link - :id="autoDevopsTagId" - tabindex="0" - data-testid="pipeline-url-autodevops" - role="button" + v-if="mergeRequestRef" + :href="mergeRequestRef.path" + class="ref-name gl-mr-3" + data-testid="merge-request-ref" + >{{ mergeRequestRef.iid }}</gl-link > - <gl-badge variant="info" size="sm"> - {{ __('Auto DevOps') }} - </gl-badge> - </gl-link> - <gl-popover :target="autoDevopsTagId" triggers="focus" placement="top"> - <template #title> - <div class="gl-font-weight-normal gl-line-height-normal"> - <gl-sprintf - :message=" - __( - 'This pipeline makes use of a predefined CI/CD configuration enabled by %{strongStart}Auto DevOps.%{strongEnd}', - ) - " - > - <template #strong="{ content }"> - <b>{{ content }}</b> - </template> - </gl-sprintf> - </div> - </template> - <gl-link - :href="autoDevopsHelpPath" - data-testid="pipeline-url-autodevops-link" - target="_blank" - > - {{ __('Learn more about Auto DevOps') }} - </gl-link> - </gl-popover> - </template> - - <gl-badge - v-if="pipeline.flags.stuck" - variant="warning" - size="sm" - data-testid="pipeline-url-stuck" - >{{ __('stuck') }}</gl-badge - > - <gl-badge - v-if="pipeline.flags.detached_merge_request_pipeline" - v-gl-tooltip - :title=" - __( - 'Merge request pipelines are configured. A detached pipeline runs in the context of the merge request, and not against the merged result. Learn more in the documentation for merge request pipelines.', - ) - " - variant="info" - size="sm" - data-testid="pipeline-url-detached" - >{{ __('detached') }}</gl-badge - > - <gl-badge - v-if="isInFork" + <gl-link v-else :href="refUrl" class="ref-name gl-mr-3" data-testid="commit-ref-name">{{ + commitRef.name + }}</gl-link> + </tooltip-on-truncate> + <gl-icon v-gl-tooltip - :title="__('Pipeline ran in fork of project')" - variant="info" - size="sm" - data-testid="pipeline-url-fork" - >{{ __('fork') }}</gl-badge - > + name="commit" + class="commit-icon gl-mr-1" + :title="__('Commit')" + data-testid="commit-icon" + /> + <gl-link :href="commitUrl" class="commit-sha mr-0" data-testid="commit-short-sha">{{ + commitShortSha + }}</gl-link> + <!--End of commit row--> </div> + <pipeline-labels :pipeline-schedule-url="pipelineScheduleUrl" :pipeline="pipeline" /> </div> </template> diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines.vue b/app/assets/javascripts/pipelines/components/pipelines_list/pipelines.vue index e7ff5449331..db9dc74863d 100644 --- a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines.vue +++ b/app/assets/javascripts/pipelines/components/pipelines_list/pipelines.vue @@ -98,19 +98,24 @@ export default { type: String, required: true, }, + defaultBranchName: { + type: String, + required: false, + default: null, + }, params: { type: Object, required: true, }, - codeQualityPagePath: { + ciRunnerSettingsPath: { type: String, required: false, default: null, }, - ciRunnerSettingsPath: { - type: String, + anyRunnersAvailable: { + type: Boolean, required: false, - default: null, + default: true, }, }, data() { @@ -347,6 +352,7 @@ export default { <pipelines-filtered-search class="gl-display-flex gl-flex-grow-1 gl-mr-4" :project-id="projectId" + :default-branch-name="defaultBranchName" :params="validatedParams" @filterPipelines="filterPipelines" /> @@ -380,8 +386,8 @@ export default { v-else-if="stateToRender === $options.stateMap.emptyState" :empty-state-svg-path="emptyStateSvgPath" :can-set-ci="canCreatePipeline" - :code-quality-page-path="codeQualityPagePath" :ci-runner-settings-path="ciRunnerSettingsPath" + :any-runners-available="anyRunnersAvailable" /> <gl-empty-state diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_ci_templates.vue b/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_ci_templates.vue index 83f6356f31a..d50229e47c4 100644 --- a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_ci_templates.vue +++ b/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_ci_templates.vue @@ -1,8 +1,19 @@ <script> -import { GlAvatar, GlButton, GlCard, GlSprintf } from '@gitlab/ui'; +import { GlAvatar, GlButton, GlCard, GlSprintf, GlIcon, GlLink } from '@gitlab/ui'; import { mergeUrlParams } from '~/lib/utils/url_utility'; -import { s__, sprintf } from '~/locale'; -import { STARTER_TEMPLATE_NAME } from '~/pipeline_editor/constants'; +import { sprintf } from '~/locale'; +import { + STARTER_TEMPLATE_NAME, + RUNNERS_AVAILABILITY_SECTION_EXPERIMENT_NAME, + RUNNERS_SETTINGS_LINK_CLICKED_EVENT, + RUNNERS_DOCUMENTATION_LINK_CLICKED_EVENT, + RUNNERS_SETTINGS_BUTTON_CLICKED_EVENT, + I18N, +} from '~/pipeline_editor/constants'; +import { helpPagePath } from '~/helpers/help_page_helper'; +import GitlabExperiment from '~/experimentation/components/gitlab_experiment.vue'; +import ExperimentTracking from '~/experimentation/experiment_tracking'; +import { isExperimentVariant } from '~/experimentation/utils'; import Tracking from '~/tracking'; export default { @@ -11,39 +22,37 @@ export default { GlButton, GlCard, GlSprintf, + GlIcon, + GlLink, + GitlabExperiment, }, mixins: [Tracking.mixin()], STARTER_TEMPLATE_NAME, - i18n: { - cta: s__('Pipelines|Use template'), - testTemplates: { - title: s__('Pipelines|Use a sample CI/CD template'), - subtitle: s__( - 'Pipelines|Use a sample %{codeStart}.gitlab-ci.yml%{codeEnd} template file to explore how CI/CD works.', - ), - gettingStarted: { - title: s__('Pipelines|Get started with GitLab CI/CD'), - description: s__( - 'Pipelines|Get familiar with GitLab CI/CD syntax by starting with a basic 3 stage CI/CD pipeline.', - ), - }, + RUNNERS_AVAILABILITY_SECTION_EXPERIMENT_NAME, + RUNNERS_SETTINGS_LINK_CLICKED_EVENT, + RUNNERS_DOCUMENTATION_LINK_CLICKED_EVENT, + RUNNERS_SETTINGS_BUTTON_CLICKED_EVENT, + I18N, + inject: ['pipelineEditorPath', 'suggestedCiTemplates'], + props: { + ciRunnerSettingsPath: { + type: String, + required: false, + default: null, }, - templates: { - title: s__('Pipelines|Use a CI/CD template'), - subtitle: s__( - "Pipelines|Use a template based on your project's language or framework to get started with GitLab CI/CD.", - ), - description: s__('Pipelines|CI/CD template to test and deploy your %{name} project.'), + anyRunnersAvailable: { + type: Boolean, + required: false, + default: true, }, }, - 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.templates.description, { name }), + description: sprintf(this.$options.I18N.templates.description, { name }), }; }); @@ -53,39 +62,104 @@ export default { { template: STARTER_TEMPLATE_NAME }, this.pipelineEditorPath, ), + tracker: null, }; }, + computed: { + sharedRunnersHelpPagePath() { + return helpPagePath('ci/runners/runners_scope', { anchor: 'shared-runners' }); + }, + runnersAvailabilitySectionExperimentEnabled() { + return isExperimentVariant(RUNNERS_AVAILABILITY_SECTION_EXPERIMENT_NAME); + }, + }, + created() { + this.tracker = new ExperimentTracking(RUNNERS_AVAILABILITY_SECTION_EXPERIMENT_NAME); + }, methods: { trackEvent(template) { this.track('template_clicked', { label: template, }); }, + trackExperimentEvent(action) { + this.tracker.event(action); + }, }, }; </script> <template> <div> - <h2 class="gl-font-size-h2 gl-text-gray-900">{{ $options.i18n.testTemplates.title }}</h2> - <p class="gl-text-gray-800 gl-mb-6"> - <gl-sprintf :message="$options.i18n.testTemplates.subtitle"> - <template #code="{ content }"> - <code>{{ content }}</code> - </template> - </gl-sprintf> - </p> + <h2 class="gl-font-size-h2 gl-text-gray-900">{{ $options.I18N.title }}</h2> - <div class="row gl-mb-8"> - <div class="col-12"> + <gitlab-experiment :name="$options.RUNNERS_AVAILABILITY_SECTION_EXPERIMENT_NAME"> + <template #candidate> + <div v-if="anyRunnersAvailable"> + <h2 class="gl-font-base gl-text-gray-900"> + <gl-icon name="check-circle-filled" class="gl-text-green-500 gl-mr-2" :size="12" /> + {{ $options.I18N.runners.title }} + </h2> + <p class="gl-text-gray-800 gl-mb-6"> + <gl-sprintf :message="$options.I18N.runners.subtitle"> + <template #settingsLink="{ content }"> + <gl-link + data-testid="settings-link" + :href="ciRunnerSettingsPath" + @click="trackExperimentEvent($options.RUNNERS_SETTINGS_LINK_CLICKED_EVENT)" + >{{ content }}</gl-link + > + </template> + <template #docsLink="{ content }"> + <gl-link + data-testid="documentation-link" + :href="sharedRunnersHelpPagePath" + @click="trackExperimentEvent($options.RUNNERS_DOCUMENTATION_LINK_CLICKED_EVENT)" + >{{ content }}</gl-link + > + </template> + </gl-sprintf> + </p> + </div> + + <div v-else> + <h2 class="gl-font-base gl-text-gray-900"> + <gl-icon name="warning-solid" class="gl-text-red-600 gl-mr-2" :size="14" /> + {{ $options.I18N.noRunners.title }} + </h2> + <p class="gl-text-gray-800 gl-mb-6">{{ $options.I18N.noRunners.subtitle }}</p> + <gl-button + data-testid="settings-button" + category="primary" + variant="confirm" + :href="ciRunnerSettingsPath" + @click="trackExperimentEvent($options.RUNNERS_SETTINGS_BUTTON_CLICKED_EVENT)" + > + {{ $options.I18N.noRunners.cta }} + </gl-button> + </div> + </template> + </gitlab-experiment> + + <template v-if="!runnersAvailabilitySectionExperimentEnabled || anyRunnersAvailable"> + <h2 class="gl-font-lg gl-text-gray-900">{{ $options.I18N.learnBasics.title }}</h2> + <p class="gl-text-gray-800 gl-mb-6"> + <gl-sprintf :message="$options.I18N.learnBasics.subtitle"> + <template #code="{ content }"> + <code>{{ content }}</code> + </template> + </gl-sprintf> + </p> + + <div class="gl-lg-w-25p gl-lg-pr-5 gl-mb-8"> <gl-card> <div class="gl-flex-direction-row"> <div class="gl-py-5"><gl-emoji class="gl-font-size-h2-xl" data-name="wave" /></div> <div class="gl-mb-3"> - <strong class="gl-text-gray-800 gl-mb-2">{{ - $options.i18n.testTemplates.gettingStarted.title - }}</strong> + <strong class="gl-text-gray-800 gl-mb-2"> + {{ $options.I18N.learnBasics.gettingStarted.title }} + </strong> </div> - <p class="gl-font-sm">{{ $options.i18n.testTemplates.gettingStarted.description }}</p> + <p class="gl-font-sm">{{ $options.I18N.learnBasics.gettingStarted.description }}</p> </div> <gl-button @@ -95,51 +169,51 @@ export default { data-testid="test-template-link" @click="trackEvent($options.STARTER_TEMPLATE_NAME)" > - {{ $options.i18n.cta }} + {{ $options.I18N.learnBasics.gettingStarted.cta }} </gl-button> </gl-card> </div> - </div> - <h2 class="gl-font-size-h2 gl-text-gray-900">{{ $options.i18n.templates.title }}</h2> - <p class="gl-text-gray-800 gl-mb-6">{{ $options.i18n.templates.subtitle }}</p> + <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="64" - class="gl-mr-6 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> + <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> - <p class="gl-mb-0 gl-font-sm" data-testid="template-description"> - {{ template.description }} - </p> </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> - <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> + </li> + </ul> + </template> </div> </template> diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_commit.vue b/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_commit.vue deleted file mode 100644 index cc676883c1d..00000000000 --- a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_commit.vue +++ /dev/null @@ -1,85 +0,0 @@ -<script> -import { CHILD_VIEW } from '~/pipelines/constants'; -import CommitComponent from '~/vue_shared/components/commit.vue'; - -export default { - components: { - CommitComponent, - }, - props: { - pipeline: { - type: Object, - required: true, - }, - viewType: { - type: String, - required: true, - }, - }, - computed: { - commitAuthor() { - let commitAuthorInformation; - - if (!this.pipeline || !this.pipeline.commit) { - return null; - } - - // 1. person who is an author of a commit might be a GitLab user - if (this.pipeline.commit.author) { - // 2. if person who is an author of a commit is a GitLab user - // they can have a GitLab avatar - if (this.pipeline.commit.author.avatar_url) { - commitAuthorInformation = this.pipeline.commit.author; - - // 3. If GitLab user does not have avatar, they might have a Gravatar - } else if (this.pipeline.commit.author_gravatar_url) { - commitAuthorInformation = { - ...this.pipeline.commit.author, - avatar_url: this.pipeline.commit.author_gravatar_url, - }; - } - // 4. If committer is not a GitLab User, they can have a Gravatar - } else { - commitAuthorInformation = { - avatar_url: this.pipeline.commit.author_gravatar_url, - path: `mailto:${this.pipeline.commit.author_email}`, - username: this.pipeline.commit.author_name, - }; - } - - return commitAuthorInformation; - }, - commitTag() { - return this.pipeline?.ref?.tag; - }, - commitRef() { - return this.pipeline?.ref; - }, - commitUrl() { - return this.pipeline?.commit?.commit_path; - }, - commitShortSha() { - return this.pipeline?.commit?.short_id; - }, - commitTitle() { - return this.pipeline?.commit?.title; - }, - isChildView() { - return this.viewType === CHILD_VIEW; - }, - }, -}; -</script> - -<template> - <commit-component - :tag="commitTag" - :commit-ref="commitRef" - :commit-url="commitUrl" - :merge-request-ref="pipeline.merge_request" - :short-sha="commitShortSha" - :title="commitTitle" - :author="commitAuthor" - :show-ref-info="!isChildView" - /> -</template> diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_filtered_search.vue b/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_filtered_search.vue index 2dfdaa0ea28..4d28545a035 100644 --- a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_filtered_search.vue +++ b/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_filtered_search.vue @@ -24,6 +24,11 @@ export default { type: String, required: true, }, + defaultBranchName: { + type: String, + required: false, + default: null, + }, params: { type: Object, required: true, @@ -57,6 +62,7 @@ export default { token: PipelineBranchNameToken, operators: OPERATOR_IS_ONLY, projectId: this.projectId, + defaultBranchName: this.defaultBranchName, disabled: this.selectedTypes.includes(this.$options.tagType), }, { diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_status_badge.vue b/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_status_badge.vue index 54901c2d13f..e765a8cd86c 100644 --- a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_status_badge.vue +++ b/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_status_badge.vue @@ -1,18 +1,13 @@ <script> -import CodeQualityWalkthrough from '~/code_quality_walkthrough/components/step.vue'; -import { PIPELINE_STATUSES } from '~/code_quality_walkthrough/constants'; import { CHILD_VIEW } from '~/pipelines/constants'; import CiBadge from '~/vue_shared/components/ci_badge_link.vue'; -import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import PipelinesTimeago from './time_ago.vue'; export default { components: { - CodeQualityWalkthrough, CiBadge, PipelinesTimeago, }, - mixins: [glFeatureFlagsMixin()], props: { pipeline: { type: Object, @@ -30,23 +25,6 @@ export default { isChildView() { return this.viewType === CHILD_VIEW; }, - shouldRenderCodeQualityWalkthrough() { - return Object.values(PIPELINE_STATUSES).includes(this.pipelineStatus.group); - }, - codeQualityStep() { - const prefix = [PIPELINE_STATUSES.successWithWarnings, PIPELINE_STATUSES.failed].includes( - this.pipelineStatus.group, - ) - ? 'failed' - : this.pipelineStatus.group; - return `${prefix}_pipeline`; - }, - codeQualityBuildPath() { - return this.pipeline?.details?.code_quality_build_path; - }, - rearrangePipelinesTable() { - return this.glFeatures?.rearrangePipelinesTable; - }, }, }; </script> @@ -54,18 +32,12 @@ export default { <template> <div> <ci-badge - id="js-code-quality-walkthrough" class="gl-mb-3" :status="pipelineStatus" :show-text="!isChildView" :icon-classes="'gl-vertical-align-middle!'" data-qa-selector="pipeline_commit_status" /> - <pipelines-timeago v-if="rearrangePipelinesTable" class="gl-mt-3" :pipeline="pipeline" /> - <code-quality-walkthrough - v-if="shouldRenderCodeQualityWalkthrough" - :step="codeQualityStep" - :link="codeQualityBuildPath" - /> + <pipelines-timeago class="gl-mt-3" :pipeline="pipeline" /> </div> </template> 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 9919a18cb99..6f0e67e1ae0 100644 --- a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table.vue +++ b/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table.vue @@ -1,16 +1,13 @@ <script> import { GlTableLite, GlTooltipDirective } from '@gitlab/ui'; import { s__, __ } from '~/locale'; -import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import eventHub from '../../event_hub'; import PipelineMiniGraph from './pipeline_mini_graph.vue'; import PipelineOperations from './pipeline_operations.vue'; import PipelineStopModal from './pipeline_stop_modal.vue'; import PipelineTriggerer from './pipeline_triggerer.vue'; import PipelineUrl from './pipeline_url.vue'; -import PipelinesCommit from './pipelines_commit.vue'; import PipelinesStatusBadge from './pipelines_status_badge.vue'; -import PipelinesTimeago from './time_ago.vue'; const DEFAULT_TD_CLASS = 'gl-p-5!'; const HIDE_TD_ON_MOBILE = 'gl-display-none! gl-lg-display-table-cell!'; @@ -22,19 +19,57 @@ export default { GlTableLite, LinkedPipelinesMiniList: () => import('ee_component/vue_shared/components/linked_pipelines_mini_list.vue'), - PipelinesCommit, PipelineMiniGraph, PipelineOperations, PipelinesStatusBadge, PipelineStopModal, - PipelinesTimeago, PipelineTriggerer, PipelineUrl, }, + tableFields: [ + { + key: 'status', + label: s__('Pipeline|Status'), + thClass: DEFAULT_TH_CLASSES, + columnClass: 'gl-w-15p', + tdClass: DEFAULT_TD_CLASS, + thAttr: { 'data-testid': 'status-th' }, + }, + { + key: 'pipeline', + label: __('Pipeline'), + thClass: DEFAULT_TH_CLASSES, + tdClass: `${DEFAULT_TD_CLASS}`, + columnClass: 'gl-w-30p', + thAttr: { 'data-testid': 'pipeline-th' }, + }, + { + key: 'triggerer', + label: s__('Pipeline|Triggerer'), + thClass: DEFAULT_TH_CLASSES, + tdClass: `${DEFAULT_TD_CLASS} ${HIDE_TD_ON_MOBILE}`, + columnClass: 'gl-w-10p', + thAttr: { 'data-testid': 'triggerer-th' }, + }, + { + key: 'stages', + label: s__('Pipeline|Stages'), + thClass: DEFAULT_TH_CLASSES, + tdClass: DEFAULT_TD_CLASS, + columnClass: 'gl-w-quarter', + thAttr: { 'data-testid': 'stages-th' }, + }, + { + key: 'actions', + thClass: DEFAULT_TH_CLASSES, + tdClass: DEFAULT_TD_CLASS, + columnClass: 'gl-w-15p', + thAttr: { 'data-testid': 'actions-th' }, + }, + ], directives: { GlTooltip: GlTooltipDirective, }, - mixins: [glFeatureFlagMixin()], props: { pipelines: { type: Array, @@ -67,76 +102,6 @@ export default { cancelingPipeline: null, }; }, - computed: { - tableFields() { - const fields = [ - { - key: 'status', - label: s__('Pipeline|Status'), - thClass: DEFAULT_TH_CLASSES, - columnClass: this.rearrangePipelinesTable ? 'gl-w-15p' : 'gl-w-10p', - tdClass: DEFAULT_TD_CLASS, - thAttr: { 'data-testid': 'status-th' }, - }, - { - key: 'pipeline', - label: this.rearrangePipelinesTable ? __('Pipeline') : this.pipelineKeyOption.label, - thClass: DEFAULT_TH_CLASSES, - tdClass: this.rearrangePipelinesTable - ? `${DEFAULT_TD_CLASS}` - : `${DEFAULT_TD_CLASS} ${HIDE_TD_ON_MOBILE}`, - columnClass: this.rearrangePipelinesTable ? 'gl-w-30p' : 'gl-w-10p', - thAttr: { 'data-testid': 'pipeline-th' }, - }, - { - key: 'triggerer', - label: s__('Pipeline|Triggerer'), - thClass: DEFAULT_TH_CLASSES, - tdClass: `${DEFAULT_TD_CLASS} ${HIDE_TD_ON_MOBILE}`, - columnClass: 'gl-w-10p', - thAttr: { 'data-testid': 'triggerer-th' }, - }, - { - key: 'commit', - label: s__('Pipeline|Commit'), - thClass: DEFAULT_TH_CLASSES, - tdClass: DEFAULT_TD_CLASS, - columnClass: 'gl-w-20p', - thAttr: { 'data-testid': 'commit-th' }, - }, - { - key: 'stages', - label: s__('Pipeline|Stages'), - thClass: DEFAULT_TH_CLASSES, - tdClass: DEFAULT_TD_CLASS, - columnClass: 'gl-w-quarter', - thAttr: { 'data-testid': 'stages-th' }, - }, - { - key: 'timeago', - label: s__('Pipeline|Duration'), - thClass: DEFAULT_TH_CLASSES, - tdClass: DEFAULT_TD_CLASS, - columnClass: this.rearrangePipelinesTable ? 'gl-w-5p' : 'gl-w-15p', - thAttr: { 'data-testid': 'timeago-th' }, - }, - { - key: 'actions', - thClass: DEFAULT_TH_CLASSES, - tdClass: DEFAULT_TD_CLASS, - columnClass: 'gl-w-15p', - thAttr: { 'data-testid': 'actions-th' }, - }, - ]; - - return !this.rearrangePipelinesTable - ? fields - : fields.filter((field) => !['commit', 'timeago'].includes(field.key)); - }, - rearrangePipelinesTable() { - return this.glFeatures?.rearrangePipelinesTable; - }, - }, watch: { pipelines() { this.cancelingPipeline = null; @@ -167,7 +132,7 @@ export default { <template> <div class="ci-table"> <gl-table-lite - :fields="tableFields" + :fields="$options.tableFields" :items="pipelines" tbody-tr-class="commit" :tbody-tr-attr="{ 'data-testid': 'pipeline-table-row' }" @@ -192,7 +157,6 @@ export default { :pipeline="item" :pipeline-schedule-url="pipelineScheduleUrl" :pipeline-key="pipelineKeyOption.key" - :view-type="viewType" /> </template> @@ -200,10 +164,6 @@ export default { <pipeline-triggerer :pipeline="item" /> </template> - <template #cell(commit)="{ item }"> - <pipelines-commit :pipeline="item" :view-type="viewType" /> - </template> - <template #cell(stages)="{ item }"> <div class="stage-cell"> <!-- This empty div should be removed, see https://gitlab.com/gitlab-org/gitlab/-/issues/323488 --> @@ -229,10 +189,6 @@ export default { </div> </template> - <template #cell(timeago)="{ item }"> - <pipelines-timeago :pipeline="item" /> - </template> - <template #cell(actions)="{ item }"> <pipeline-operations :pipeline="item" :canceling-pipeline="cancelingPipeline" /> </template> 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 c45e3f24567..cde963e4051 100644 --- a/app/assets/javascripts/pipelines/components/pipelines_list/time_ago.vue +++ b/app/assets/javascripts/pipelines/components/pipelines_list/time_ago.vue @@ -1,6 +1,5 @@ <script> import { GlIcon, GlTooltipDirective } from '@gitlab/ui'; -import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import timeagoMixin from '~/vue_shared/mixins/timeago'; export default { @@ -8,7 +7,7 @@ export default { GlTooltip: GlTooltipDirective, }, components: { GlIcon }, - mixins: [timeagoMixin, glFeatureFlagMixin()], + mixins: [timeagoMixin], props: { pipeline: { type: Object, @@ -54,14 +53,11 @@ export default { showSkipped() { return !this.duration && !this.finishedTime && this.skipped; }, - shouldDisplayAsBlock() { - return this.glFeatures?.rearrangePipelinesTable; - }, }, }; </script> <template> - <div class="{ 'gl-display-block': shouldDisplayAsBlock }"> + <div class="gl-display-block"> <span v-if="showInProgress" data-testid="pipeline-in-progress"> <gl-icon v-if="stuck" name="warning" class="gl-mr-2" :size="12" data-testid="warning-icon" /> <gl-icon diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/tokens/pipeline_branch_name_token.vue b/app/assets/javascripts/pipelines/components/pipelines_list/tokens/pipeline_branch_name_token.vue index 5409e68cdc4..1db2898b72a 100644 --- a/app/assets/javascripts/pipelines/components/pipelines_list/tokens/pipeline_branch_name_token.vue +++ b/app/assets/javascripts/pipelines/components/pipelines_list/tokens/pipeline_branch_name_token.vue @@ -35,6 +35,13 @@ export default { Api.branches(this.config.projectId, searchterm) .then(({ data }) => { this.branches = data.map((branch) => branch.name); + if (!searchterm && this.config.defaultBranchName) { + // Shift the default branch to the top of the list + this.branches = this.branches.filter( + (branch) => branch !== this.config.defaultBranchName, + ); + this.branches.unshift(this.config.defaultBranchName); + } this.loading = false; }) .catch((err) => { |