Commit bb0453f3 authored by Coung Ngo's avatar Coung Ngo

Remove `vue_issue_header` feature flag

Remove the `vue_issue_header` feature flag now that it has been
defaulted to on with no major errors. This commit also removes
unused Haml templates now that we've converted from Haml to Vue.
parent 355cc7e6
......@@ -286,7 +286,6 @@ linters:
- 'app/views/shared/hook_logs/_content.html.haml'
- 'app/views/shared/issuable/_assignees.html.haml'
- 'app/views/shared/issuable/_board_create_list_dropdown.html.haml'
- 'app/views/shared/issuable/_close_reopen_report_toggle.html.haml'
- 'app/views/shared/issuable/_form.html.haml'
- 'app/views/shared/issuable/_search_bar.html.haml'
- 'app/views/shared/issuable/_sidebar.html.haml'
......
......@@ -44,7 +44,6 @@ class Projects::IssuesController < Projects::ApplicationController
push_frontend_feature_flag(:vue_issuable_sidebar, project.group)
push_frontend_feature_flag(:tribute_autocomplete, @project)
push_frontend_feature_flag(:vue_issuables_list, project)
push_frontend_feature_flag(:vue_issue_header, @project, default_enabled: true)
end
before_action only: :show do
......
......@@ -2,6 +2,7 @@
- can_update_merge_request = can?(current_user, :update_merge_request, @merge_request)
- can_reopen_merge_request = can?(current_user, :reopen_merge_request, @merge_request)
- state_human_name, state_icon_name = state_name_with_icon(@merge_request)
- are_close_and_open_buttons_hidden = issuable_button_hidden?(@merge_request, true) && issuable_button_hidden?(@merge_request, false)
- if @merge_request.closed_without_fork?
.gl-alert.gl-alert-danger.gl-mb-5
......@@ -46,4 +47,7 @@
- if can_update_merge_request
= link_to 'Edit', edit_project_merge_request_path(@project, @merge_request), class: "d-none d-md-block btn gl-button btn-grouped js-issuable-edit qa-edit-button"
= render 'shared/issuable/close_reopen_button', issuable: @merge_request, can_update: can_update_merge_request, can_reopen: can_reopen_merge_request
- if can_update_merge_request && !are_close_and_open_buttons_hidden
= render 'shared/issuable/close_reopen_draft_report_toggle', issuable: @merge_request
- elsif !@merge_request.merged?
= link_to _('Report abuse'), new_abuse_report_path(user_id: @merge_request.author.id, ref_url: issuable_url(@merge_request)), class: 'd-none d-md-block btn btn-grouped btn-close-color', title: _('Report abuse')
- is_current_user = issuable_author_is_current_user(issuable)
- display_issuable_type = issuable_display_type(issuable)
- are_close_and_open_buttons_hidden = issuable_button_hidden?(issuable, true) && issuable_button_hidden?(issuable, false)
- add_blocked_class = false
- if defined? warn_before_close
- add_blocked_class = warn_before_close
- if is_current_user && !issuable.is_a?(MergeRequest)
- if can_update
%button{ class: "d-none d-md-block btn btn-grouped btn-close js-btn-issue-action #{issuable_button_visibility(issuable, true)} #{(add_blocked_class ? 'btn-issue-blocked' : '')}",
data: { remote: 'true', endpoint: close_issuable_path(issuable), qa_selector: 'close_issue_button' } }
= _("Close %{display_issuable_type}") % { display_issuable_type: display_issuable_type }
- if can_reopen
%button{ class: "d-none d-md-block btn btn-grouped btn-reopen js-btn-issue-action #{issuable_button_visibility(issuable, false)}",
data: { remote: 'true', endpoint: reopen_issuable_path(issuable), qa_selector: 'reopen_issue_button' } }
= _("Reopen %{display_issuable_type}") % { display_issuable_type: display_issuable_type }
- else
- if can_update && !are_close_and_open_buttons_hidden
- if issuable.is_a?(MergeRequest)
= render 'shared/issuable/close_reopen_draft_report_toggle', issuable: issuable
- else
= render 'shared/issuable/close_reopen_report_toggle', issuable: issuable, warn_before_close: add_blocked_class
- else
- unless issuable.is_a?(MergeRequest) && issuable.merged?
= link_to _('Report abuse'), new_abuse_report_path(user_id: issuable.author.id, ref_url: issuable_url(issuable)),
class: 'd-none d-md-block btn btn-grouped btn-close-color', title: _('Report abuse')
- display_issuable_type = issuable_display_type(issuable)
- button_action = issuable.closed? ? 'reopen' : 'close'
- display_button_action = button_action.capitalize
- button_responsive_class = 'd-none d-md-block'
- button_class = "#{button_responsive_class} btn btn-grouped js-issuable-close-button js-btn-issue-action issuable-close-button"
- toggle_class = "#{button_responsive_class} btn btn-nr dropdown-toggle js-issuable-close-toggle"
- add_blocked_class = false
- if defined? warn_before_close
- add_blocked_class = !issuable.closed? && warn_before_close
.float-left.btn-group.gl-ml-3.issuable-close-dropdown.droplab-dropdown.js-issuable-close-dropdown
%button{ class: "#{button_class} btn-#{button_action} #{(add_blocked_class ? 'btn-issue-blocked' : '')}", data: { testid: 'close-issue-button', qa_selector: 'close_issue_button', endpoint: close_reopen_issuable_path(issuable) } }
#{display_button_action} #{display_issuable_type}
= button_tag type: 'button', class: "#{toggle_class} btn-#{button_action}-color",
data: { 'dropdown-trigger' => '#issuable-close-menu' }, 'aria-label' => _('Toggle dropdown') do
= icon('caret-down', class: 'toggle-icon icon')
%ul#issuable-close-menu.js-issuable-close-menu.dropdown-menu{ data: { dropdown: true } }
%li.close-item{ class: "#{issuable_button_visibility(issuable, true) || 'droplab-item-selected'}",
data: { text: _("Close %{display_issuable_type}") % { display_issuable_type: display_issuable_type }, url: close_issuable_path(issuable),
button_class: "#{button_class} btn-close", toggle_class: "#{toggle_class} btn-close-color" } }
%button.btn.btn-transparent
= sprite_icon('check', css_class: 'icon')
.description
%strong.title
= _('Close')
= display_issuable_type
%li.reopen-item{ class: "#{issuable_button_visibility(issuable, false) || 'droplab-item-selected'}",
data: { text: _("Reopen %{display_issuable_type}") % { display_issuable_type: display_issuable_type }, url: reopen_issuable_path(issuable),
button_class: "#{button_class} btn-reopen", toggle_class: "#{toggle_class} btn-reopen-color" } }
%button.btn.btn-transparent
= sprite_icon('check', css_class: 'icon')
.description
%strong.title
= _('Reopen')
= display_issuable_type
%li.divider.droplab-item-ignore
%li.report-item{ data: { text: _('Report abuse'), button_class: "#{button_class} btn-close-color", toggle_class: "#{toggle_class} btn-close-color", method: '' } }
%a.report-abuse-link{ :href => new_abuse_report_path(user_id: issuable.author.id, ref_url: issuable_url(issuable)) }
.description
%strong.title= _('Report abuse')
%p.text
= _('Report %{display_issuable_type} that are abusive, inappropriate or spam.') % { display_issuable_type: display_issuable_type.pluralize }
- can_update_issue = can?(current_user, :update_issue, issuable)
- can_reopen_issue = can?(current_user, :reopen_issue, issuable)
- can_report_spam = issuable.submittable_as_spam_by?(current_user)
- can_create_issue = show_new_issue_link?(@project)
- display_issuable_type = issuable_display_type(issuable)
- new_issuable_params = ({ issuable_template: 'incident', issue: { issue_type: 'incident' } } if issuable.incident?)
.detail-page-header
.detail-page-header-body
.issuable-status-box.status-box.status-box-issue-closed{ class: issue_status_visibility(issuable, status_box: :closed) }
......@@ -18,38 +11,9 @@
.issuable-meta
#js-issuable-header-warnings
= issuable_meta(issuable, @project, display_issuable_type)
= issuable_meta(issuable, @project, issuable_display_type(issuable))
%a.btn.gl-button.btn-default.float-right.gl-display-block.d-sm-none.gutter-toggle.issuable-gutter-toggle.js-sidebar-toggle{ href: "#" }
= sprite_icon('chevron-double-lg-left')
- if Feature.enabled?(:vue_issue_header, @project, default_enabled: true)
.js-issue-header-actions{ data: issue_header_actions_data(@project, issuable, current_user) }
- else
.detail-page-header-actions.js-issuable-actions.js-issuable-buttons{ data: { "action": "close-reopen" } }
.clearfix.issue-btn-group.dropdown
%button.btn.gl-button.btn-default.float-left.gl-display-md-none{ type: "button", data: { toggle: "dropdown" } }
= _('Options')
= icon('caret-down')
.dropdown-menu.dropdown-menu-right
%ul
- unless current_user == issuable.author
%li= link_to _('Report abuse'), new_abuse_report_path(user_id: issuable.author.id, ref_url: issue_url(issuable))
- if can_update_issue
%li= link_to _('Close %{display_issuable_type}') % { display_issuable_type: display_issuable_type }, issue_path(issuable, issue: { state_event: :close }, format: 'json'), class: "btn-close js-btn-issue-action #{issue_button_visibility(issuable, true)}", title: _('Close %{display_issuable_type}') % { display_issuable_type: display_issuable_type }, data: { endpoint: close_reopen_issuable_path(issuable) }
- if can_reopen_issue
%li= link_to _('Reopen %{display_issuable_type}') % { display_issuable_type: display_issuable_type }, issue_path(issuable, issue: { state_event: :reopen }, format: 'json'), class: "btn-reopen js-btn-issue-action #{issue_button_visibility(issuable, false)}", title: _('Reopen %{display_issuable_type}') % { display_issuable_type: display_issuable_type }, data: { endpoint: close_reopen_issuable_path(issuable) }
- if can_report_spam
%li= link_to _('Submit as spam'), mark_as_spam_project_issue_path(@project, issuable), method: :post, class: 'btn-spam', title: 'Submit as spam'
- if can_create_issue
- if can_update_issue || can_report_spam
%li.divider
%li= link_to _('New %{display_issuable_type}') % { display_issuable_type: display_issuable_type }, new_project_issue_path(@project, new_issuable_params), id: 'new_%{display_issuable_type}_link' % { display_issuable_type: display_issuable_type }
= render 'shared/issuable/close_reopen_button', issuable: issuable, can_update: can_update_issue, can_reopen: can_reopen_issue, warn_before_close: defined?(issuable.blocked?) && issuable.blocked?
- if can_report_spam
= link_to _('Submit as spam'), mark_as_spam_project_issue_path(@project, issuable), method: :post, class: 'gl-display-none gl-display-md-block gl-button btn btn-grouped btn-spam', title: 'Submit as spam'
- if can_create_issue
= link_to new_project_issue_path(@project, new_issuable_params), class: 'gl-display-none gl-display-md-block gl-button btn btn-grouped btn-success btn-inverted', title: _('New %{display_issuable_type}') % { display_issuable_type: display_issuable_type }, id: 'new_%{display_issuable_type}_link' % { display_issuable_type: display_issuable_type } do
= _('New %{display_issuable_type}') % { display_issuable_type: display_issuable_type }
.js-issue-header-actions{ data: issue_header_actions_data(@project, issuable, current_user) }
---
name: vue_issue_header
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/44440
rollout_issue_url:
milestone: '13.6'
type: development
group: group::project management
default_enabled: true
......@@ -14,8 +14,6 @@ RSpec.describe 'Issue Sidebar' do
let_it_be(:issue_no_group) { create(:labeled_issue, project: project_without_group, labels: [label]) }
before do
stub_feature_flags(vue_issue_header: false)
sign_in(user)
end
......@@ -98,7 +96,9 @@ RSpec.describe 'Issue Sidebar' do
context 'when user closes an issue' do
it 'disables the edit button' do
page.find('[data-testid="close-issue-button"]').click
page.within('.detail-page-header') do
click_button 'Close issue'
end
page.within('.health-status') do
expect(page).to have_button('Edit', disabled: true)
......
......@@ -16,8 +16,6 @@ RSpec.describe Projects::IssuesController, '(JavaScript fixtures)', type: :contr
end
before do
stub_feature_flags(vue_issue_header: false)
project.add_developer(user)
sign_in(user)
......
......@@ -5640,9 +5640,6 @@ msgstr ""
msgid "Close"
msgstr ""
msgid "Close %{display_issuable_type}"
msgstr ""
msgid "Close %{issueType}"
msgstr ""
......@@ -18203,9 +18200,6 @@ msgstr ""
msgid "New"
msgstr ""
msgid "New %{display_issuable_type}"
msgstr ""
msgid "New %{issueType}"
msgstr ""
......@@ -22741,9 +22735,6 @@ msgstr ""
msgid "Reopen"
msgstr ""
msgid "Reopen %{display_issuable_type}"
msgstr ""
msgid "Reopen %{issueType}"
msgstr ""
......
......@@ -14,7 +14,7 @@ module QA
element :remove_related_issue_button
end
view 'app/views/shared/issuable/_close_reopen_button.html.haml' do
view 'app/assets/javascripts/issue_show/components/header_actions.vue' do
element :close_issue_button
element :reopen_issue_button
end
......
......@@ -13,8 +13,6 @@ RSpec.describe "User views incident" do
end
before do
stub_feature_flags(vue_issue_header: false)
sign_in(user)
visit(project_issues_incident_path(project, incident))
......@@ -24,10 +22,12 @@ RSpec.describe "User views incident" do
it_behaves_like 'page meta description', ' Description header Lorem ipsum dolor sit amet'
it 'shows the merge request and incident actions', :aggregate_failures do
expect(page).to have_link('New incident')
it 'shows the merge request and incident actions', :js, :aggregate_failures do
click_button 'Incident actions'
expect(page).to have_link('New incident', href: new_project_issue_path(project, { issuable_template: 'incident', issue: { issue_type: 'incident' } }))
expect(page).to have_button('Create merge request')
expect(page).to have_link('Close incident')
expect(page).to have_button('Close incident')
end
context 'when the project is archived' do
......
......@@ -7,10 +7,6 @@ RSpec.describe 'Issuables Close/Reopen/Report toggle' do
let(:user) { create(:user) }
before do
stub_feature_flags(vue_issue_header: false)
end
shared_examples 'an issuable close/reopen/report toggle' do
let(:container) { find('.issuable-close-dropdown') }
let(:human_model_name) { issuable.model_name.human.downcase }
......@@ -49,61 +45,6 @@ RSpec.describe 'Issuables Close/Reopen/Report toggle' do
end
end
context 'on an issue' do
let(:project) { create(:project) }
let(:issuable) { create(:issue, project: project) }
before do
project.add_maintainer(user)
login_as user
end
context 'when user has permission to update', :js do
before do
visit project_issue_path(project, issuable)
end
it_behaves_like 'an issuable close/reopen/report toggle'
context 'when the issue is closed and locked' do
let(:issuable) { create(:issue, :closed, :locked, project: project) }
it 'hides the reopen button' do
expect(page).not_to have_button('Reopen issue')
end
context 'when the issue author is the current user' do
before do
issuable.update(author: user)
end
it 'hides the reopen button' do
expect(page).not_to have_button('Reopen issue')
end
end
end
end
context 'when user doesnt have permission to update' do
let(:cant_project) { create(:project) }
let(:cant_issuable) { create(:issue, project: cant_project) }
before do
cant_project.add_guest(user)
visit project_issue_path(cant_project, cant_issuable)
end
it 'only shows the `Report abuse` and `New issue` buttons' do
expect(page).to have_link('Report abuse')
expect(page).to have_link('New issue')
expect(page).not_to have_button('Close issue')
expect(page).not_to have_button('Reopen issue')
expect(page).not_to have_link(title: 'Edit title and description')
end
end
end
context 'on a merge request' do
let(:container) { find('.detail-page-header-actions') }
let(:project) { create(:project, :repository) }
......
......@@ -13,8 +13,6 @@ RSpec.describe "User views issue" do
end
before do
stub_feature_flags(vue_issue_header: false)
sign_in(user)
visit(project_issue_path(project, issue))
......@@ -24,10 +22,12 @@ RSpec.describe "User views issue" do
it_behaves_like 'page meta description', ' Description header Lorem ipsum dolor sit amet'
it 'shows the merge request and issue actions', :aggregate_failures do
expect(page).to have_link('New issue')
it 'shows the merge request and issue actions', :js, :aggregate_failures do
click_button 'Issue actions'
expect(page).to have_link('New issue', href: new_project_issue_path(project))
expect(page).to have_button('Create merge request')
expect(page).to have_link('Close issue')
expect(page).to have_button('Close issue')
end
context 'when the project is archived' do
......
......@@ -16,8 +16,6 @@ RSpec.describe Projects::IssuesController, '(JavaScript fixtures)', type: :contr
end
before do
stub_feature_flags(vue_issue_header: false)
sign_in(admin)
end
......
......@@ -13,52 +13,16 @@ describe('Issue', () => {
testContext = {};
});
let $boxClosed, $boxOpen, $btn;
let $boxClosed, $boxOpen;
preloadFixtures('issues/closed-issue.html');
preloadFixtures('issues/issue-with-task-list.html');
preloadFixtures('issues/open-issue.html');
preloadFixtures('static/issue_with_mermaid_graph.html');
function expectErrorMessage() {
const $flashMessage = $('div.flash-alert');
expect($flashMessage).toExist();
expect($flashMessage).toBeVisible();
expect($flashMessage).toHaveText('Unable to update this issue at this time.');
}
function expectIssueState(isIssueOpen) {
expectVisibility($boxClosed, !isIssueOpen);
expectVisibility($boxOpen, isIssueOpen);
expect($btn).toHaveText(isIssueOpen ? 'Close issue' : 'Reopen issue');
}
function expectNewBranchButtonState(isPending, canCreate) {
if (Issue.$btnNewBranch.length === 0) {
return;
}
const $available = Issue.$btnNewBranch.find('.available');
expect($available).toHaveText('New branch');
if (!isPending && canCreate) {
expect($available).toBeVisible();
} else {
expect($available).toBeHidden();
}
const $unavailable = Issue.$btnNewBranch.find('.unavailable');
expect($unavailable).toHaveText('New branch unavailable');
if (!isPending && !canCreate) {
expect($unavailable).toBeVisible();
} else {
expect($unavailable).toBeHidden();
}
}
function expectVisibility($element, shouldBeVisible) {
......@@ -69,7 +33,7 @@ describe('Issue', () => {
}
}
function findElements(isIssueInitiallyOpen) {
function findElements() {
$boxClosed = $('div.status-box-issue-closed');
expect($boxClosed).toExist();
......@@ -79,11 +43,6 @@ describe('Issue', () => {
expect($boxOpen).toExist();
expect($boxOpen).toHaveText('Open');
$btn = $('.js-issuable-close-button');
expect($btn).toExist();
expect($btn).toHaveText(isIssueInitiallyOpen ? 'Close issue' : 'Reopen issue');
}
[true, false].forEach(isIssueInitiallyOpen => {
......@@ -99,25 +58,6 @@ describe('Issue', () => {
testContext.$projectIssuesCounter.text('1,001');
}
function mockCloseButtonResponseSuccess(url, response) {
mock.onPut(url).reply(() => {
expectNewBranchButtonState(true, false);
return [200, response];
});
}
function mockCloseButtonResponseError(url) {
mock.onPut(url).networkError();
}
function mockCanCreateBranch(canCreateBranch) {
mock.onGet(/(.*)\/can_create_branch$/).reply(200, {
can_create_branch: canCreateBranch,
suggested_branch_name: 'foo-99',
});
}
beforeEach(() => {
if (isIssueInitiallyOpen) {
loadFixtures('issues/open-issue.html');
......@@ -130,7 +70,6 @@ describe('Issue', () => {
jest.spyOn(axios, 'get');
findElements(isIssueInitiallyOpen);
testContext.$triggeredButton = $btn;
});
afterEach(() => {
......@@ -138,94 +77,19 @@ describe('Issue', () => {
$('div.flash-alert').remove();
});
it(`${action}s the issue`, done => {
mockCloseButtonResponseSuccess(testContext.$triggeredButton.attr('href'), {
id: 34,
});
mockCanCreateBranch(!isIssueInitiallyOpen);
setup();
testContext.$triggeredButton.trigger('click');
setImmediate(() => {
expectIssueState(!isIssueInitiallyOpen);
expect(testContext.$triggeredButton.get(0).getAttribute('disabled')).toBeNull();
expect(testContext.$projectIssuesCounter.text()).toBe(
isIssueInitiallyOpen ? '1,000' : '1,002',
);
expectNewBranchButtonState(false, !isIssueInitiallyOpen);
done();
});
});
it(`fails to ${action} the issue if saved:false`, done => {
mockCloseButtonResponseSuccess(testContext.$triggeredButton.attr('href'), {
saved: false,
});
mockCanCreateBranch(isIssueInitiallyOpen);
setup();
testContext.$triggeredButton.trigger('click');
setImmediate(() => {
expectIssueState(isIssueInitiallyOpen);
expect(testContext.$triggeredButton.get(0).getAttribute('disabled')).toBeNull();
expectErrorMessage();
expect(testContext.$projectIssuesCounter.text()).toBe('1,001');
expectNewBranchButtonState(false, isIssueInitiallyOpen);
done();
});
});
it(`fails to ${action} the issue if HTTP error occurs`, done => {
mockCloseButtonResponseError(testContext.$triggeredButton.attr('href'));
mockCanCreateBranch(isIssueInitiallyOpen);
setup();
testContext.$triggeredButton.trigger('click');
setImmediate(() => {
expectIssueState(isIssueInitiallyOpen);
expect(testContext.$triggeredButton.get(0).getAttribute('disabled')).toBeNull();
expectErrorMessage();
expect(testContext.$projectIssuesCounter.text()).toBe('1,001');
expectNewBranchButtonState(false, isIssueInitiallyOpen);
done();
});
});
it('disables the new branch button if Ajax call fails', () => {
mockCloseButtonResponseError(testContext.$triggeredButton.attr('href'));
mock.onGet(/(.*)\/can_create_branch$/).networkError();
setup();
testContext.$triggeredButton.trigger('click');
expectNewBranchButtonState(false, false);
});
it('does not trigger Ajax call if new branch button is missing', done => {
mockCloseButtonResponseError(testContext.$triggeredButton.attr('href'));
document.querySelector('#related-branches').remove();
document.querySelector('.create-mr-dropdown-wrap').remove();
it(`${action}s the issue on dispatch of issuable_vue_app:change event`, () => {
setup();
testContext.$triggeredButton.trigger('click');
setImmediate(() => {
expect(axios.get).not.toHaveBeenCalled();
document.dispatchEvent(
new CustomEvent('issuable_vue_app:change', {
detail: {
data: { id: 1 },
isClosed: isIssueInitiallyOpen,
},
}),
);
done();
});
expectIssueState(!isIssueInitiallyOpen);
});
});
});
......
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