Commit 3075d6bf authored by Olena Horal-Koretska's avatar Olena Horal-Koretska

Merge branch '300400-ci_mini_pipeline_gl_dropdown-ff-removal' into 'master'

Remove ci_mini_pipeline_gl_dropdown feature flag [RUN ALL RSPEC] [RUN AS-IF-FOSS]

See merge request gitlab-org/gitlab!53595
parents 6d59fe34 3247bf14
...@@ -12,11 +12,9 @@ ...@@ -12,11 +12,9 @@
* 4. Commit widget * 4. Commit widget
*/ */
import { GlDropdown, GlLoadingIcon, GlTooltipDirective, GlIcon } from '@gitlab/ui'; import { GlDropdown, GlLoadingIcon, GlTooltipDirective, GlIcon } from '@gitlab/ui';
import $ from 'jquery';
import { deprecatedCreateFlash as Flash } from '~/flash'; import { deprecatedCreateFlash as Flash } from '~/flash';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale'; import { __ } from '~/locale';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { PIPELINES_TABLE } from '../../constants'; import { PIPELINES_TABLE } from '../../constants';
import eventHub from '../../event_hub'; import eventHub from '../../event_hub';
import JobItem from '../graph/job_item.vue'; import JobItem from '../graph/job_item.vue';
...@@ -31,19 +29,16 @@ export default { ...@@ -31,19 +29,16 @@ export default {
directives: { directives: {
GlTooltip: GlTooltipDirective, GlTooltip: GlTooltipDirective,
}, },
mixins: [glFeatureFlagsMixin()],
props: { props: {
stage: { stage: {
type: Object, type: Object,
required: true, required: true,
}, },
updateDropdown: { updateDropdown: {
type: Boolean, type: Boolean,
required: false, required: false,
default: false, default: false,
}, },
type: { type: {
type: String, type: String,
required: false, required: false,
...@@ -57,11 +52,6 @@ export default { ...@@ -57,11 +52,6 @@ export default {
}; };
}, },
computed: { computed: {
isCiMiniPipelineGlDropdown() {
// Feature flag ci_mini_pipeline_gl_dropdown
// See more at https://gitlab.com/gitlab-org/gitlab/-/issues/300400
return this.glFeatures?.ciMiniPipelineGlDropdown;
},
triggerButtonClass() { triggerButtonClass() {
return `ci-status-icon-${this.stage.status.group}`; return `ci-status-icon-${this.stage.status.group}`;
}, },
...@@ -76,24 +66,12 @@ export default { ...@@ -76,24 +66,12 @@ export default {
} }
}, },
}, },
updated() {
if (!this.isCiMiniPipelineGlDropdown && this.dropdownContent.length) {
this.stopDropdownClickPropagation();
}
},
methods: { methods: {
onShowDropdown() { onShowDropdown() {
eventHub.$emit('clickedDropdown'); eventHub.$emit('clickedDropdown');
this.isLoading = true; this.isLoading = true;
this.fetchJobs(); this.fetchJobs();
}, },
onClickStage() {
if (!this.isDropdownOpen()) {
eventHub.$emit('clickedDropdown');
this.isLoading = true;
this.fetchJobs();
}
},
fetchJobs() { fetchJobs() {
axios axios
.get(this.stage.dropdown_path) .get(this.stage.dropdown_path)
...@@ -102,133 +80,60 @@ export default { ...@@ -102,133 +80,60 @@ export default {
this.isLoading = false; this.isLoading = false;
}) })
.catch(() => { .catch(() => {
if (this.isCiMiniPipelineGlDropdown) { this.$refs.stageGlDropdown.hide();
this.$refs.stageGlDropdown.hide();
} else {
this.closeDropdown();
}
this.isLoading = false; this.isLoading = false;
Flash(__('Something went wrong on our end.')); Flash(__('Something went wrong on our end.'));
}); });
}, },
/**
* When the user right clicks or cmd/ctrl + click in the job name
* the dropdown should not be closed and the link should open in another tab,
* so we stop propagation of the click event inside the dropdown.
*
* Since this component is rendered multiple times per page we need to guarantee we only
* target the click event of this component.
*
* Note: This should be removed once ci_mini_pipeline_gl_dropdown FF is removed as true.
*/
stopDropdownClickPropagation() {
$(
'.js-builds-dropdown-list button, .js-builds-dropdown-list a.mini-pipeline-graph-dropdown-item',
this.$el,
).on('click', (e) => {
e.stopPropagation();
});
},
closeDropdown() {
if (this.isDropdownOpen()) {
$(this.$refs.dropdown).dropdown('toggle');
}
},
isDropdownOpen() { isDropdownOpen() {
return this.$el.classList.contains('show'); return this.$el.classList.contains('show');
}, },
pipelineActionRequestComplete() { pipelineActionRequestComplete() {
if (this.type === PIPELINES_TABLE) { if (this.type === PIPELINES_TABLE) {
// warn the table to update // warn the pipelines table to update
eventHub.$emit('refreshPipelinesTable'); eventHub.$emit('refreshPipelinesTable');
return; return;
} }
// close the dropdown in mr widget // close the dropdown in MR widget
if (this.isCiMiniPipelineGlDropdown) { this.$refs.stageGlDropdown.hide();
this.$refs.stageGlDropdown.hide();
} else {
$(this.$refs.dropdown).dropdown('toggle');
}
}, },
}, },
}; };
</script> </script>
<template> <template>
<div class="dropdown"> <gl-dropdown
<gl-dropdown ref="stageGlDropdown"
v-if="isCiMiniPipelineGlDropdown" v-gl-tooltip.hover
ref="stageGlDropdown" data-testid="mini-pipeline-graph-dropdown"
v-gl-tooltip.hover :title="stage.title"
data-testid="mini-pipeline-graph-dropdown" variant="link"
:title="stage.title" :lazy="true"
variant="link" :popper-opts="{ placement: 'bottom' }"
:lazy="true" :toggle-class="['mini-pipeline-graph-dropdown-toggle', triggerButtonClass]"
:popper-opts="{ placement: 'bottom' }" menu-class="mini-pipeline-graph-dropdown-menu"
:toggle-class="['mini-pipeline-graph-gl-dropdown-toggle', triggerButtonClass]" @show="onShowDropdown"
menu-class="mini-pipeline-graph-dropdown-menu" >
@show="onShowDropdown" <template #button-content>
> <span class="gl-pointer-events-none">
<template #button-content> <gl-icon :name="borderlessIcon" />
<span class="gl-pointer-events-none"> </span>
<gl-icon :name="borderlessIcon" />
</span>
</template>
<gl-loading-icon v-if="isLoading" />
<ul
v-else
class="js-builds-dropdown-list scrollable-menu"
data-testid="mini-pipeline-graph-dropdown-menu-list"
>
<li v-for="job in dropdownContent" :key="job.id">
<job-item
:dropdown-length="dropdownContent.length"
:job="job"
css-class-job-name="mini-pipeline-graph-dropdown-item"
@pipelineActionRequestComplete="pipelineActionRequestComplete"
/>
</li>
</ul>
</gl-dropdown>
<template v-else>
<button
id="stageDropdown"
ref="dropdown"
v-gl-tooltip.hover
:class="triggerButtonClass"
:title="stage.title"
class="mini-pipeline-graph-dropdown-toggle"
data-testid="mini-pipeline-graph-dropdown-toggle"
data-toggle="dropdown"
data-display="static"
type="button"
aria-haspopup="true"
aria-expanded="false"
@click="onClickStage"
>
<span :aria-label="stage.title" aria-hidden="true" class="gl-pointer-events-none">
<gl-icon :name="borderlessIcon" />
</span>
</button>
<div
class="dropdown-menu mini-pipeline-graph-dropdown-menu js-builds-dropdown-container"
aria-labelledby="stageDropdown"
>
<gl-loading-icon v-if="isLoading" />
<ul v-else class="js-builds-dropdown-list scrollable-menu">
<li v-for="job in dropdownContent" :key="job.id">
<job-item
:dropdown-length="dropdownContent.length"
:job="job"
css-class-job-name="mini-pipeline-graph-dropdown-item"
@pipelineActionRequestComplete="pipelineActionRequestComplete"
/>
</li>
</ul>
</div>
</template> </template>
</div> <gl-loading-icon v-if="isLoading" />
<ul
v-else
class="js-builds-dropdown-list scrollable-menu"
data-testid="mini-pipeline-graph-dropdown-menu-list"
>
<li v-for="job in dropdownContent" :key="job.id">
<job-item
:dropdown-length="dropdownContent.length"
:job="job"
css-class-job-name="mini-pipeline-graph-dropdown-item"
@pipelineActionRequestComplete="pipelineActionRequestComplete"
/>
</li>
</ul>
</gl-dropdown>
</template> </template>
...@@ -67,8 +67,7 @@ ...@@ -67,8 +67,7 @@
// Mini Pipelines // Mini Pipelines
.stage-cell { .stage-cell {
.mini-pipeline-graph-dropdown-toggle, .mini-pipeline-graph-dropdown-toggle {
.mini-pipeline-graph-gl-dropdown-toggle {
svg { svg {
height: $ci-action-icon-size; height: $ci-action-icon-size;
width: $ci-action-icon-size; width: $ci-action-icon-size;
...@@ -138,14 +137,16 @@ ...@@ -138,14 +137,16 @@
} }
} }
// Dropdown button in mini pipeline graph // Commit mini pipeline (HAML)
button.mini-pipeline-graph-dropdown-toggle, button.mini-pipeline-graph-dropdown-toggle,
// As the `mini-pipeline-item` mixin specificity is lower // GlDropdown mini pipeline (Vue)
// than the toggle of dropdown with 'variant="link"' we add // As the `mini-pipeline-item` mixin specificity is lower
// classes ".gl-button.btn-link" to make it more specific. // than the toggle of dropdown with 'variant="link"' we add
// Once FF ci_mini_pipeline_gl_dropdown is removed, the `mini-pipeline-item` // classes ".gl-button.btn-link" to make it more specific
// itself could increase its specificity to simplify this selector // and avoid having the size overriden
button.gl-button.btn-link.mini-pipeline-graph-gl-dropdown-toggle { //
// See https://gitlab.com/gitlab-org/gitlab/-/issues/320737
button.gl-button.btn-link.mini-pipeline-graph-dropdown-toggle {
@include mini-pipeline-item(); @include mini-pipeline-item();
} }
......
...@@ -226,10 +226,6 @@ $tabs-holder-z-index: 250; ...@@ -226,10 +226,6 @@ $tabs-holder-z-index: 250;
} }
} }
.mini-pipeline-graph-dropdown-toggle {
vertical-align: top;
}
.normal { .normal {
flex: 1; flex: 1;
flex-basis: auto; flex-basis: auto;
...@@ -982,15 +978,15 @@ $tabs-holder-z-index: 250; ...@@ -982,15 +978,15 @@ $tabs-holder-z-index: 250;
line-height: initial; line-height: initial;
} }
.mini-pipeline-graph-dropdown-toggle, // GlDropdown mini pipeline (Vue)
.stage-cell .mini-pipeline-graph-dropdown-toggle svg, // As the `mini-pipeline-item` mixin specificity is lower
// As the `mini-pipeline-item` mixin specificity is lower // than the toggle of dropdown with 'variant="link"' we add
// than the toggle of dropdown with 'variant="link"' we add // classes ".gl-button.btn-link" to make it more specific
// classes ".gl-button.btn-link" to make it more specific. // and avoid having the size overriden
// Once FF ci_mini_pipeline_gl_dropdown is removed, the `mini-pipeline-item` //
// itself could increase its specificity to simplify this selector // See https://gitlab.com/gitlab-org/gitlab/-/issues/320737
button.gl-button.btn-link.mini-pipeline-graph-gl-dropdown-toggle, button.gl-button.btn-link.mini-pipeline-graph-dropdown-toggle,
.stage-cell button.gl-button.btn-link.mini-pipeline-graph-gl-dropdown-toggle svg { .stage-cell button.gl-button.btn-link.mini-pipeline-graph-dropdown-toggle svg {
height: $ci-action-icon-size-lg; height: $ci-action-icon-size-lg;
width: $ci-action-icon-size-lg; width: $ci-action-icon-size-lg;
} }
......
...@@ -18,9 +18,6 @@ class Projects::CommitController < Projects::ApplicationController ...@@ -18,9 +18,6 @@ class Projects::CommitController < Projects::ApplicationController
before_action :define_commit_vars, only: [:show, :diff_for_path, :diff_files, :pipelines, :merge_requests] before_action :define_commit_vars, only: [:show, :diff_for_path, :diff_files, :pipelines, :merge_requests]
before_action :define_note_vars, only: [:show, :diff_for_path, :diff_files] before_action :define_note_vars, only: [:show, :diff_for_path, :diff_files]
before_action :authorize_edit_tree!, only: [:revert, :cherry_pick] before_action :authorize_edit_tree!, only: [:revert, :cherry_pick]
before_action only: [:pipelines] do
push_frontend_feature_flag(:ci_mini_pipeline_gl_dropdown, @project, type: :development, default_enabled: :yaml)
end
BRANCH_SEARCH_LIMIT = 1000 BRANCH_SEARCH_LIMIT = 1000
COMMIT_DIFFS_PER_PAGE = 75 COMMIT_DIFFS_PER_PAGE = 75
......
...@@ -44,7 +44,6 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo ...@@ -44,7 +44,6 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
push_frontend_feature_flag(:suggestions_custom_commit, @project, default_enabled: true) push_frontend_feature_flag(:suggestions_custom_commit, @project, default_enabled: true)
push_frontend_feature_flag(:local_file_reviews, default_enabled: :yaml) push_frontend_feature_flag(:local_file_reviews, default_enabled: :yaml)
push_frontend_feature_flag(:paginated_notes, @project, default_enabled: :yaml) push_frontend_feature_flag(:paginated_notes, @project, default_enabled: :yaml)
push_frontend_feature_flag(:ci_mini_pipeline_gl_dropdown, @project, type: :development, default_enabled: :yaml)
record_experiment_user(:invite_members_version_a) record_experiment_user(:invite_members_version_a)
record_experiment_user(:invite_members_version_b) record_experiment_user(:invite_members_version_b)
......
...@@ -17,7 +17,6 @@ class Projects::PipelinesController < Projects::ApplicationController ...@@ -17,7 +17,6 @@ class Projects::PipelinesController < Projects::ApplicationController
push_frontend_feature_flag(:new_pipeline_form, project, default_enabled: :yaml) push_frontend_feature_flag(:new_pipeline_form, project, default_enabled: :yaml)
push_frontend_feature_flag(:graphql_pipeline_details, project, type: :development, default_enabled: :yaml) push_frontend_feature_flag(:graphql_pipeline_details, project, type: :development, default_enabled: :yaml)
push_frontend_feature_flag(:graphql_pipeline_details_users, current_user, type: :development, default_enabled: :yaml) push_frontend_feature_flag(:graphql_pipeline_details_users, current_user, type: :development, default_enabled: :yaml)
push_frontend_feature_flag(:ci_mini_pipeline_gl_dropdown, project, type: :development, default_enabled: :yaml)
push_frontend_feature_flag(:jira_for_vulnerabilities, project, type: :development, default_enabled: :yaml) push_frontend_feature_flag(:jira_for_vulnerabilities, project, type: :development, default_enabled: :yaml)
end end
before_action :ensure_pipeline, only: [:show] before_action :ensure_pipeline, only: [:show]
......
---
name: ci_mini_pipeline_gl_dropdown
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/52821
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/300400
milestone: '13.9'
type: development
group: group::continuous integration
default_enabled: true
...@@ -18,7 +18,6 @@ RSpec.describe 'User adds a merge request to a merge train', :js do ...@@ -18,7 +18,6 @@ RSpec.describe 'User adds a merge request to a merge train', :js do
before do before do
stub_feature_flags(disable_merge_trains: false) stub_feature_flags(disable_merge_trains: false)
stub_feature_flags(ci_mini_pipeline_gl_dropdown: false)
stub_licensed_features(merge_pipelines: true, merge_trains: true) stub_licensed_features(merge_pipelines: true, merge_trains: true)
project.add_maintainer(user) project.add_maintainer(user)
project.update!(merge_pipelines_enabled: true, merge_trains_enabled: true) project.update!(merge_pipelines_enabled: true, merge_trains_enabled: true)
...@@ -70,11 +69,11 @@ RSpec.describe 'User adds a merge request to a merge train', :js do ...@@ -70,11 +69,11 @@ RSpec.describe 'User adds a merge request to a merge train', :js do
end end
it 'displays pipeline control' do it 'displays pipeline control' do
expect(page).to have_selector('[data-testid="mini-pipeline-graph-dropdown-toggle"]') expect(page).to have_selector('[data-testid="mini-pipeline-graph-dropdown"]')
end end
it 'does not allow retry for merge train pipeline' do it 'does not allow retry for merge train pipeline' do
find('[data-testid="mini-pipeline-graph-dropdown-toggle"]').click find('[data-testid="mini-pipeline-graph-dropdown"] .dropdown-toggle').click
page.within '.ci-job-component' do page.within '.ci-job-component' do
expect(page).to have_selector('.ci-status-icon') expect(page).to have_selector('.ci-status-icon')
expect(page).not_to have_selector('.retry') expect(page).not_to have_selector('.retry')
......
...@@ -519,75 +519,58 @@ RSpec.describe 'Pipelines', :js do ...@@ -519,75 +519,58 @@ RSpec.describe 'Pipelines', :js do
end end
end end
shared_examples 'mini pipeline renders' do |ci_mini_pipeline_gl_dropdown_enabled| context 'mini pipeline graph' do
context 'mini pipeline graph' do let!(:build) do
let!(:build) do create(:ci_build, :pending, pipeline: pipeline,
create(:ci_build, :pending, pipeline: pipeline, stage: 'build',
stage: 'build', name: 'build')
name: 'build') end
end
before do dropdown_selector = '[data-testid="mini-pipeline-graph-dropdown"]'
stub_feature_flags(ci_mini_pipeline_gl_dropdown: ci_mini_pipeline_gl_dropdown_enabled)
visit_project_pipelines
end
let_it_be(:dropdown_toggle_selector) do before do
if ci_mini_pipeline_gl_dropdown_enabled visit_project_pipelines
'[data-testid="mini-pipeline-graph-dropdown"] .dropdown-toggle' end
else
'[data-testid="mini-pipeline-graph-dropdown-toggle"]'
end
end
it 'renders a mini pipeline graph' do it 'renders a mini pipeline graph' do
expect(page).to have_selector('[data-testid="widget-mini-pipeline-graph"]') expect(page).to have_selector('[data-testid="widget-mini-pipeline-graph"]')
expect(page).to have_selector(dropdown_toggle_selector) expect(page).to have_selector(dropdown_selector)
end end
context 'when clicking a stage badge' do context 'when clicking a stage badge' do
it 'opens a dropdown' do it 'opens a dropdown' do
find(dropdown_toggle_selector).click find(dropdown_selector).click
expect(page).to have_link build.name expect(page).to have_link build.name
end end
it 'is possible to cancel pending build' do it 'is possible to cancel pending build' do
find(dropdown_toggle_selector).click find(dropdown_selector).click
find('.js-ci-action').click find('.js-ci-action').click
wait_for_requests wait_for_requests
expect(build.reload).to be_canceled expect(build.reload).to be_canceled
end
end end
end
context 'for a failed pipeline' do context 'for a failed pipeline' do
let!(:build) do let!(:build) do
create(:ci_build, :failed, pipeline: pipeline, create(:ci_build, :failed, pipeline: pipeline,
stage: 'build', stage: 'build',
name: 'build') name: 'build')
end end
it 'displays the failure reason' do it 'displays the failure reason' do
find(dropdown_toggle_selector).click find(dropdown_selector).click
within('.js-builds-dropdown-list') do within('.js-builds-dropdown-list') do
build_element = page.find('.mini-pipeline-graph-dropdown-item') build_element = page.find('.mini-pipeline-graph-dropdown-item')
expect(build_element['title']).to eq('build - failed - (unknown failure)') expect(build_element['title']).to eq('build - failed - (unknown failure)')
end
end end
end end
end end
end end
context 'with ci_mini_pipeline_gl_dropdown disabled' do
it_behaves_like "mini pipeline renders", false
end
context 'with ci_mini_pipeline_gl_dropdown enabled' do
it_behaves_like "mini pipeline renders", true
end
context 'with pagination' do context 'with pagination' do
before do before do
allow(Ci::Pipeline).to receive(:default_per_page).and_return(1) allow(Ci::Pipeline).to receive(:default_per_page).and_return(1)
......
...@@ -69,7 +69,8 @@ describe('Pipelines', () => { ...@@ -69,7 +69,8 @@ describe('Pipelines', () => {
const findRunPipelineButton = () => wrapper.findByTestId('run-pipeline-button'); const findRunPipelineButton = () => wrapper.findByTestId('run-pipeline-button');
const findCiLintButton = () => wrapper.findByTestId('ci-lint-button'); const findCiLintButton = () => wrapper.findByTestId('ci-lint-button');
const findCleanCacheButton = () => wrapper.findByTestId('clear-cache-button'); const findCleanCacheButton = () => wrapper.findByTestId('clear-cache-button');
const findStagesDropdown = () => wrapper.findByTestId('mini-pipeline-graph-dropdown-toggle'); const findStagesDropdownToggle = () =>
wrapper.find('[data-testid="mini-pipeline-graph-dropdown"] .dropdown-toggle');
const findPipelineUrlLinks = () => wrapper.findAll('[data-testid="pipeline-url-link"]'); const findPipelineUrlLinks = () => wrapper.findAll('[data-testid="pipeline-url-link"]');
const createComponent = (props = defaultProps) => { const createComponent = (props = defaultProps) => {
...@@ -642,7 +643,7 @@ describe('Pipelines', () => { ...@@ -642,7 +643,7 @@ describe('Pipelines', () => {
// Mock init a polling cycle // Mock init a polling cycle
wrapper.vm.poll.options.notificationCallback(true); wrapper.vm.poll.options.notificationCallback(true);
findStagesDropdown().trigger('click'); findStagesDropdownToggle().trigger('click');
await waitForPromises(); await waitForPromises();
...@@ -652,7 +653,9 @@ describe('Pipelines', () => { ...@@ -652,7 +653,9 @@ describe('Pipelines', () => {
}); });
it('stops polling & restarts polling', async () => { it('stops polling & restarts polling', async () => {
findStagesDropdown().trigger('click'); findStagesDropdownToggle().trigger('click');
await waitForPromises();
expect(cancelMock).not.toHaveBeenCalled(); expect(cancelMock).not.toHaveBeenCalled();
expect(stopMock).toHaveBeenCalled(); expect(stopMock).toHaveBeenCalled();
......
...@@ -153,11 +153,10 @@ describe('Pipelines Table Row', () => { ...@@ -153,11 +153,10 @@ describe('Pipelines Table Row', () => {
}); });
it('should render an icon for each stage', () => { it('should render an icon for each stage', () => {
expect( const stages = wrapper.findAll(
wrapper.findAll( '.table-section:nth-child(5) [data-testid="mini-pipeline-graph-dropdown"]',
'.table-section:nth-child(5) [data-testid="mini-pipeline-graph-dropdown-toggle"]', );
).length, expect(stages).toHaveLength(pipeline.details.stages.length);
).toEqual(pipeline.details.stages.length);
}); });
}); });
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment