Commit c2f8bdc7 authored by Clement Ho's avatar Clement Ho

Merge branch 'ee-proj-settings-ok-leftovers' into 'master'

Improve project settings page (leftovers)

See merge request gitlab-org/gitlab-ee!10630
parents 51eb9527 4f12ef0f
import _ from 'underscore'; import _ from 'underscore';
import $ from 'jquery';
class DirtySubmitForm { class DirtySubmitForm {
constructor(form) { constructor(form) {
...@@ -26,6 +27,7 @@ class DirtySubmitForm { ...@@ -26,6 +27,7 @@ class DirtySubmitForm {
); );
this.form.addEventListener('input', throttledUpdateDirtyInput); this.form.addEventListener('input', throttledUpdateDirtyInput);
this.form.addEventListener('change', throttledUpdateDirtyInput); this.form.addEventListener('change', throttledUpdateDirtyInput);
$(this.form).on('change.select2', throttledUpdateDirtyInput);
this.form.addEventListener('submit', event => this.formSubmit(event)); this.form.addEventListener('submit', event => this.formSubmit(event));
} }
......
...@@ -3,17 +3,24 @@ import initSettingsPanels from '~/settings_panels'; ...@@ -3,17 +3,24 @@ import initSettingsPanels from '~/settings_panels';
import setupProjectEdit from '~/project_edit'; import setupProjectEdit from '~/project_edit';
import initConfirmDangerModal from '~/confirm_danger_modal'; import initConfirmDangerModal from '~/confirm_danger_modal';
import mountBadgeSettings from '~/pages/shared/mount_badge_settings'; import mountBadgeSettings from '~/pages/shared/mount_badge_settings';
import dirtySubmitFactory from '~/dirty_submit/dirty_submit_factory';
import initAvatarPicker from '~/avatar_picker'; import initAvatarPicker from '~/avatar_picker';
import initProjectLoadingSpinner from '../shared/save_project_loader'; import initProjectLoadingSpinner from '../shared/save_project_loader';
import initProjectPermissionsSettings from '../shared/permissions'; import initProjectPermissionsSettings from '../shared/permissions';
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
initProjectLoadingSpinner();
setupProjectEdit();
// Initialize expandable settings panels
initSettingsPanels();
initAvatarPicker(); initAvatarPicker();
initProjectPermissionsSettings();
initConfirmDangerModal(); initConfirmDangerModal();
initSettingsPanels();
mountBadgeSettings(PROJECT_BADGE); mountBadgeSettings(PROJECT_BADGE);
initProjectLoadingSpinner();
initProjectPermissionsSettings();
setupProjectEdit();
dirtySubmitFactory(
document.querySelectorAll(
'.js-general-settings-form, .js-mr-settings-form, .js-mr-approvals-form',
),
);
}); });
...@@ -157,6 +157,10 @@ label { ...@@ -157,6 +157,10 @@ label {
padding-left: 10px; padding-left: 10px;
padding-right: 10px; padding-right: 10px;
appearance: none; appearance: none;
/* stylelint-disable property-no-vendor-prefix */
-webkit-appearance: none;
-moz-appearance: none;
/* stylelint-enable property-no-vendor-prefix */
&::-ms-expand { &::-ms-expand {
display: none; display: none;
......
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
.settings-header { .settings-header {
position: relative; position: relative;
padding: 20px 110px 10px 0; padding: 20px 110px 0 0;
h4 { h4 {
margin-top: 0; margin-top: 0;
......
- if ::Gitlab::ExternalAuthorization.enabled? - if ::Gitlab::ExternalAuthorization.enabled?
.form-group .form-group.col-md-9
= f.label :external_authorization_classification_label, class: 'label-bold' do = f.label :external_authorization_classification_label, _('Classification Label (optional)'), class: 'label-bold'
= s_('ExternalAuthorizationService|Classification Label')
%span.light (optional)
= f.text_field :external_authorization_classification_label, class: "form-control" = f.text_field :external_authorization_classification_label, class: "form-control"
%span.form-text.text-muted %span.form-text.text-muted
= external_classification_label_help_message = external_classification_label_help_message
- return unless Gitlab::CurrentSettings.project_export_enabled? - return unless Gitlab::CurrentSettings.project_export_enabled?
- project = local_assigns.fetch(:project) - project = local_assigns.fetch(:project)
- expanded = Rails.env.test?
%section.settings.no-animate#js-export-project{ class: ('expanded' if expanded) } .sub-section
.settings-header %h4= _('Export project')
%h4 %p= _('Export this project with all its related data in order to move your project to a new GitLab instance. Once the export is finished, you can import the file from the "New Project" page.')
Export project
%button.btn.js-settings-toggle{ type: 'button' } .bs-callout.bs-callout-info
= expanded ? 'Collapse' : 'Expand' %p.append-bottom-0
%p %p= _('The following items will be exported:')
Export this project with all its related data in order to move your project to a new GitLab instance. Once the export is finished, you can import the file from the "New Project" page. %ul
.settings-content %li= _('Project and wiki repositories')
.bs-callout.bs-callout-info %li= _('Project uploads')
%p.append-bottom-0 %li= _('Project configuration, including services')
%p %li= _('Issues with comments, merge requests with diffs and comments, labels, milestones, snippets, and other project entities')
The following items will be exported: %li= _('LFS objects')
%ul %p= _('The following items will NOT be exported:')
%li Project and wiki repositories %ul
%li Project uploads %li= _('Job traces and artifacts')
%li Project configuration, including services %li= _('Container registry images')
%li Issues with comments, merge requests with diffs and comments, labels, milestones, snippets, and other project entities %li= _('CI variables')
%li LFS objects %li= _('Webhooks')
%p %li= _('Any encrypted tokens')
The following items will NOT be exported: %p= _('Once the exported file is ready, you will receive a notification email with a download link, or you can download it from this page.')
%ul - if project.export_status == :finished
%li Job traces and artifacts = link_to _('Download export'), download_export_project_path(project),
%li Container registry images rel: 'nofollow', download: '', method: :get, class: "btn btn-default"
%li CI variables = link_to _('Generate new export'), generate_new_export_project_path(project),
%li Webhooks method: :post, class: "btn btn-default"
%li Any encrypted tokens - else
%p = link_to _('Export project'), export_project_path(project),
Once the exported file is ready, you will receive a notification email with a download link, or you can download it from this page. method: :post, class: "btn btn-default"
- if project.export_status == :finished
= link_to 'Download export', download_export_project_path(project),
rel: 'nofollow', download: '', method: :get, class: "btn btn-default"
= link_to 'Generate new export', generate_new_export_project_path(project),
method: :post, class: "btn btn-default"
- else
= link_to 'Export project', export_project_path(project),
method: :post, class: "btn btn-default"
This diff is collapsed.
= form_for [@project.namespace.becomes(Namespace), @project], remote: true, html: { multipart: true, class: "edit-project js-general-settings-form" }, authenticity_token: true do |f|
%input{ name: 'update_section', type: 'hidden', value: 'js-general-settings' }
= form_errors(@project)
%fieldset
.row
.form-group.col-md-5
= f.label :name, class: 'label-bold', for: 'project_name_edit' do
= _('Project name')
= f.text_field :name, class: 'form-control qa-project-name-field', id: "project_name_edit"
.form-group.col-md-7
= f.label :id, class: 'label-bold' do
= _('Project ID')
= f.text_field :id, class: 'form-control w-auto', readonly: true
.row
.form-group.col-md-9
= f.label :tag_list, _('Topics'), class: 'label-bold'
= f.text_field :tag_list, value: @project.tag_list.join(', '), maxlength: 2000, class: "form-control"
%p.form-text.text-muted= _('Separate topics with commas.')
.row
.form-group.col-md-9
= f.label :description, _('Project description (optional)'), class: 'label-bold'
= f.text_area :description, class: 'form-control', rows: 3, maxlength: 250
.row= render_if_exists 'projects/classification_policy_settings', f: f
.row= render_if_exists 'shared/repository_size_limit_setting', form: f, type: :project
.form-group.prepend-top-default.append-bottom-20
.avatar-container.s90
= project_icon(@project, alt: _('Project avatar'), class: 'avatar project-avatar s90')
= f.label :avatar, _('Project avatar'), class: 'label-bold d-block'
= render 'shared/choose_avatar_button', f: f
- if @project.avatar?
%hr
= link_to _('Remove avatar'), project_avatar_path(@project), data: { confirm: _('Avatar will be removed. Are you sure?')}, method: :delete, class: 'btn btn-link'
= f.submit _('Save changes'), class: "btn btn-success mt-4 qa-save-naming-topics-avatar-button"
...@@ -2,8 +2,7 @@ ...@@ -2,8 +2,7 @@
.modal-dialog .modal-dialog
.modal-content .modal-content
.modal-header .modal-header
%h3.page-title %h3.page-title= _('Confirmation required')
Confirmation required
%button.close{ type: "button", "data-dismiss": "modal", "aria-label" => _('Close') } %button.close{ type: "button", "data-dismiss": "modal", "aria-label" => _('Close') }
%span{ "aria-hidden": true } × %span{ "aria-hidden": true } ×
...@@ -11,9 +10,7 @@ ...@@ -11,9 +10,7 @@
%p.text-danger.js-confirm-text %p.text-danger.js-confirm-text
%p %p
%span.js-warning-text %span.js-warning-text= _('This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention.')
This action can lead to data loss.
To prevent accidental actions we ask you to confirm your intention.
%br %br
Please type Please type
%code.js-confirm-danger-match= phrase %code.js-confirm-danger-match= phrase
...@@ -22,4 +19,4 @@ ...@@ -22,4 +19,4 @@
.form-group .form-group
= text_field_tag 'confirm_name_input', '', class: 'form-control js-confirm-danger-input' = text_field_tag 'confirm_name_input', '', class: 'form-control js-confirm-danger-input'
.form-actions .form-actions
= submit_tag 'Confirm', class: "btn btn-danger js-confirm-danger-submit" = submit_tag _('Confirm'), class: "btn btn-danger js-confirm-danger-submit"
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
= link_to _("Learn more about approvals."), help_page_path("user/project/merge_requests/merge_request_approvals"), target: '_blank' = link_to _("Learn more about approvals."), help_page_path("user/project/merge_requests/merge_request_approvals"), target: '_blank'
.settings-content .settings-content
= form_for [@project.namespace.becomes(Namespace), @project], remote: true, html: { class: "merge-request-approval-settings-form" }, authenticity_token: true do |f| = form_for [@project.namespace.becomes(Namespace), @project], remote: true, html: { class: "merge-request-approval-settings-form js-mr-approvals-form" }, authenticity_token: true do |f|
%input{ name: 'update_section', type: 'hidden', value: 'js-merge-request-approval-settings' } %input{ name: 'update_section', type: 'hidden', value: 'js-merge-request-approval-settings' }
= render 'projects/merge_request_approvals_settings_form', form: f, project: @project = render 'projects/merge_request_approvals_settings_form', form: f, project: @project
= f.submit _("Save changes"), class: "btn btn-success" = f.submit _("Save changes"), class: "btn btn-success"
...@@ -2,18 +2,20 @@ ...@@ -2,18 +2,20 @@
- expanded = Rails.env.test? - expanded = Rails.env.test?
%section.settings.issues-feature.no-animate#js-issue-settings{ class: [('expanded' if expanded), ('hidden' if @project.project_feature.send(:issues_access_level) == 0)] } %section.settings.issues-feature.no-animate#js-issue-settings{ class: [('expanded' if expanded), ('hidden' if @project.project_feature.send(:issues_access_level) == 0)] }
.settings-header .settings-header
%h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only= _('Issue settings') %h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only= _('Default issue template')
%button.btn.js-settings-toggle= expanded ? _('Collapse') : _('Expand') %button.btn.btn-default.js-settings-toggle= expanded ? _('Collapse') : _('Expand')
%p= _('Customize your issue restrictions.') %p= _('Set a default template for issue descriptions.')
.settings-content .settings-content
= form_for [@project.namespace.becomes(Namespace), @project], remote: true, html: { multipart: true, class: "issue-settings-form" }, authenticity_token: true do |f| = form_for [@project.namespace.becomes(Namespace), @project], remote: true, html: { multipart: true, class: "issue-settings-form" }, authenticity_token: true do |f|
%input{ type: 'hidden', name: 'update_section', value: 'js-issue-settings' } %input{ type: 'hidden', name: 'update_section', value: 'js-issue-settings' }
.form-group .row
= f.label :issues_template, class: 'label-bold' do .form-group.col-md-9
Default description template for issues = f.label :issues_template, class: 'label-bold' do
= link_to icon('question-circle'), help_page_path('user/project/description_templates', anchor: 'setting-a-default-template-for-issues-and-merge-requests'), target: '_blank' = _('Default description template for issues')
= f.text_area :issues_template, class: "form-control", rows: 3 = link_to icon('question-circle'), help_page_path('user/project/description_templates', anchor: 'setting-a-default-template-for-issues-and-merge-requests'), target: '_blank'
.hint = f.text_area :issues_template, class: "form-control", rows: 3
Description parsed with #{link_to "GitLab Flavored Markdown", help_page_path('user/markdown'), target: '_blank'}. .text-secondary
= f.submit 'Save changes', class: "btn btn-success" - link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path('user/markdown') }
= _('Description parsed with %{link_start}GitLab Flavored Markdown%{link_end}').html_safe % { link_start: link_start, link_end: '</a>'.html_safe }
= f.submit _('Save changes'), class: "btn btn-success"
- return unless current_user.admin? && License.feature_available?(:repository_size_limit) - return unless current_user.admin? && License.feature_available?(:repository_size_limit)
- form = local_assigns.fetch(:form) - form = local_assigns.fetch(:form)
- type = local_assigns.fetch(:type) - is_project = local_assigns.fetch(:type) == :project
- form_group_class = type === :group ? 'col-md-9' : ''
.form-group{ class: form_group_class } .form-group.col-md-9
= form.label :repository_size_limit, class: 'label-bold' do = form.label :repository_size_limit, class: 'label-bold' do
Repository size limit (MB) Repository size limit (MB)
= form.number_field :repository_size_limit, value: form.object.repository_size_limit.try(:to_mb), class: 'form-control', min: 0 = form.number_field :repository_size_limit, value: form.object.repository_size_limit.try(:to_mb), class: 'form-control', min: 0
%span.form-text.text-muted#repository_size_limit_help_block %span.form-text.text-muted#repository_size_limit_help_block
= type === :project ? size_limit_message(@project) : size_limit_message_for_group(@group) = is_project ? size_limit_message(@project) : size_limit_message_for_group(@group)
---
title: Improve project settings page layout and UX
merge_request: 10388
author:
type: other
...@@ -17,14 +17,14 @@ describe 'Project settings > Issues', :js do ...@@ -17,14 +17,14 @@ describe 'Project settings > Issues', :js do
end end
it 'shows the Issues settings' do it 'shows the Issues settings' do
expect(page).to have_content('Customize your issue restrictions') expect(page).to have_content('Set a default template for issue descriptions.')
within('.sharing-permissions-form') do within('.sharing-permissions-form') do
find('.project-feature-controls[data-for="project[project_feature_attributes][issues_access_level]"] .project-feature-toggle').click find('.project-feature-controls[data-for="project[project_feature_attributes][issues_access_level]"] .project-feature-toggle').click
click_on('Save changes') click_on('Save changes')
end end
expect(page).not_to have_content('Customize your issue restrictions') expect(page).not_to have_content('Set a default template for issue descriptions.')
end end
end end
end end
...@@ -36,14 +36,14 @@ describe 'Project settings > Issues', :js do ...@@ -36,14 +36,14 @@ describe 'Project settings > Issues', :js do
end end
it 'does not show the Issues settings' do it 'does not show the Issues settings' do
expect(page).not_to have_content('Customize your issue restrictions') expect(page).not_to have_content('Set a default template for issue descriptions.')
within('.sharing-permissions-form') do within('.sharing-permissions-form') do
find('.project-feature-controls[data-for="project[project_feature_attributes][issues_access_level]"] .project-feature-toggle').click find('.project-feature-controls[data-for="project[project_feature_attributes][issues_access_level]"] .project-feature-toggle').click
click_on('Save changes') click_on('Save changes')
end end
expect(page).to have_content('Customize your issue restrictions') expect(page).to have_content('Set a default template for issue descriptions.')
end end
end end
......
...@@ -3,16 +3,19 @@ require 'spec_helper' ...@@ -3,16 +3,19 @@ require 'spec_helper'
describe 'EE > Projects > Settings > User manages approval rule settings' do describe 'EE > Projects > Settings > User manages approval rule settings' do
let(:project) { create(:project) } let(:project) { create(:project) }
let(:user) { project.owner } let(:user) { project.owner }
let(:path) { edit_project_path(project) }
before do before do
sign_in(user) sign_in(user)
stub_licensed_features(licensed_features) stub_licensed_features(licensed_features)
visit edit_project_path(project) visit path
end end
context 'when `code_owner_approval_required` is available' do context 'when `code_owner_approval_required` is available' do
let(:licensed_features) { { code_owner_approval_required: true } } let(:licensed_features) { { code_owner_approval_required: true } }
it_behaves_like 'dirty submit form', [{ form: '#js-merge-request-approval-settings', input: '#project_merge_requests_author_approval' }]
it 'allows the user to enforce code owner approval' do it 'allows the user to enforce code owner approval' do
within('.require-code-owner-approval') do within('.require-code-owner-approval') do
check('Require approval from code owners') check('Require approval from code owners')
......
This diff is collapsed.
...@@ -4,27 +4,21 @@ module QA ...@@ -4,27 +4,21 @@ module QA
module Settings module Settings
class Advanced < Page::Base class Advanced < Page::Base
view 'app/views/projects/edit.html.haml' do view 'app/views/projects/edit.html.haml' do
element :project_path_field, 'text_field :path' # rubocop:disable QA/ElementWithPattern element :project_path_field
element :project_name_field, 'text_field :name' # rubocop:disable QA/ElementWithPattern element :change_path_button
element :rename_project_button, "submit 'Rename project'" # rubocop:disable QA/ElementWithPattern
end end
def rename_to(path) def update_project_path_to(path)
fill_project_name(path)
fill_project_path(path) fill_project_path(path)
rename_project! click_change_path_button
end end
def fill_project_path(path) def fill_project_path(path)
fill_in :project_path, with: path fill_element :project_path_field, path
end end
def fill_project_name(name) def click_change_path_button
fill_in :project_name, with: name click_element :change_path_button
end
def rename_project!
click_on 'Rename project'
end end
end end
end end
......
...@@ -4,14 +4,6 @@ module QA ...@@ -4,14 +4,6 @@ module QA
module Settings module Settings
module Common module Common
include QA::Page::Settings::Common include QA::Page::Settings::Common
def self.included(base)
base.class_eval do
view 'app/views/projects/edit.html.haml' do
element :advanced_settings_expand, "= expanded ? 'Collapse' : 'Expand'" # rubocop:disable QA/ElementWithPattern
end
end
end
end end
end end
end end
......
...@@ -9,6 +9,24 @@ module QA ...@@ -9,6 +9,24 @@ module QA
element :advanced_settings element :advanced_settings
end end
view 'app/views/projects/settings/_general.html.haml' do
element :project_name_field
element :save_naming_topics_avatar_button
end
def rename_project_to(name)
fill_project_name(name)
click_save_changes
end
def fill_project_name(name)
fill_element :project_name_field, name
end
def click_save_changes
click_element :save_naming_topics_avatar_button
end
def expand_advanced_settings(&block) def expand_advanced_settings(&block)
expand_section(:advanced_settings) do expand_section(:advanced_settings) do
Advanced.perform(&block) Advanced.perform(&block)
......
...@@ -34,8 +34,11 @@ module QA ...@@ -34,8 +34,11 @@ module QA
geo_project_renamed = "geo-after-rename-#{SecureRandom.hex(8)}" geo_project_renamed = "geo-after-rename-#{SecureRandom.hex(8)}"
Page::Project::Settings::Main.perform do |settings| Page::Project::Settings::Main.perform do |settings|
settings.rename_project_to(geo_project_renamed)
expect(page).to have_content "Project '#{geo_project_renamed}' was successfully updated."
settings.expand_advanced_settings do |page| settings.expand_advanced_settings do |page|
page.rename_to(geo_project_renamed) page.update_project_path_to(geo_project_renamed)
end end
end end
......
...@@ -9,24 +9,33 @@ describe 'Projects > Settings > User renames a project' do ...@@ -9,24 +9,33 @@ describe 'Projects > Settings > User renames a project' do
visit edit_project_path(project) visit edit_project_path(project)
end end
def rename_project(project, name: nil, path: nil) def change_path(project, path)
fill_in('project_name', with: name) if name within('.advanced-settings') do
fill_in('Path', with: path) if path fill_in('Path', with: path)
click_button('Rename project') click_button('Change path')
end
project.reload
wait_for_edit_project_page_reload wait_for_edit_project_page_reload
end
def change_name(project, name)
within('.general-settings') do
fill_in('Project name', with: name)
click_button('Save changes')
end
project.reload project.reload
wait_for_edit_project_page_reload
end end
def wait_for_edit_project_page_reload def wait_for_edit_project_page_reload
expect(find('.project-edit-container')).to have_content('Rename repository') expect(find('.advanced-settings')).to have_content('Change path')
end end
context 'with invalid characters' do context 'with invalid characters' do
it 'shows errors for invalid project path/name' do it 'shows errors for invalid project path' do
rename_project(project, name: 'foo&bar', path: 'foo&bar') change_path(project, 'foo&bar')
expect(page).to have_field 'Project name', with: 'foo&bar'
expect(page).to have_field 'Path', with: 'foo&bar' expect(page).to have_field 'Path', with: 'foo&bar'
expect(page).to have_content "Name can contain only letters, digits, emojis, '_', '.', dash, space. It must start with letter, digit, emoji or '_'."
expect(page).to have_content "Path can contain only letters, digits, '_', '-' and '.'. Cannot start with '-', end in '.git' or end in '.atom'" expect(page).to have_content "Path can contain only letters, digits, '_', '-' and '.'. Cannot start with '-', end in '.git' or end in '.atom'"
end end
end end
...@@ -42,13 +51,13 @@ describe 'Projects > Settings > User renames a project' do ...@@ -42,13 +51,13 @@ describe 'Projects > Settings > User renames a project' do
context 'when changing project name' do context 'when changing project name' do
it 'renames the repository' do it 'renames the repository' do
rename_project(project, name: 'bar') change_name(project, 'bar')
expect(find('.breadcrumbs')).to have_content(project.name) expect(find('.breadcrumbs')).to have_content(project.name)
end end
context 'with emojis' do context 'with emojis' do
it 'shows error for invalid project name' do it 'shows error for invalid project name' do
rename_project(project, name: '🚀 foo bar ☁️') change_name(project, '🚀 foo bar ☁️')
expect(page).to have_field 'Project name', with: '🚀 foo bar ☁️' expect(page).to have_field 'Project name', with: '🚀 foo bar ☁️'
expect(page).not_to have_content "Name can contain only letters, digits, emojis '_', '.', dash and space. It must start with letter, digit, emoji or '_'." expect(page).not_to have_content "Name can contain only letters, digits, emojis '_', '.', dash and space. It must start with letter, digit, emoji or '_'."
end end
...@@ -67,7 +76,7 @@ describe 'Projects > Settings > User renames a project' do ...@@ -67,7 +76,7 @@ describe 'Projects > Settings > User renames a project' do
end end
it 'the project is accessible via the new path' do it 'the project is accessible via the new path' do
rename_project(project, path: 'bar') change_path(project, 'bar')
new_path = namespace_project_path(project.namespace, 'bar') new_path = namespace_project_path(project.namespace, 'bar')
visit new_path visit new_path
...@@ -77,7 +86,7 @@ describe 'Projects > Settings > User renames a project' do ...@@ -77,7 +86,7 @@ describe 'Projects > Settings > User renames a project' do
it 'the project is accessible via a redirect from the old path' do it 'the project is accessible via a redirect from the old path' do
old_path = project_path(project) old_path = project_path(project)
rename_project(project, path: 'bar') change_path(project, 'bar')
new_path = namespace_project_path(project.namespace, 'bar') new_path = namespace_project_path(project.namespace, 'bar')
visit old_path visit old_path
...@@ -88,7 +97,7 @@ describe 'Projects > Settings > User renames a project' do ...@@ -88,7 +97,7 @@ describe 'Projects > Settings > User renames a project' do
context 'and a new project is added with the same path' do context 'and a new project is added with the same path' do
it 'overrides the redirect' do it 'overrides the redirect' do
old_path = project_path(project) old_path = project_path(project)
rename_project(project, path: 'bar') change_path(project, 'bar')
new_project = create(:project, namespace: user.namespace, path: 'gitlabhq', name: 'quz') new_project = create(:project, namespace: user.namespace, path: 'gitlabhq', name: 'quz')
visit old_path visit old_path
......
...@@ -373,6 +373,21 @@ describe 'Project' do ...@@ -373,6 +373,21 @@ describe 'Project' do
end end
end end
describe 'edit' do
let(:user) { create(:user) }
let(:project) { create(:project, :public) }
let(:path) { edit_project_path(project) }
before do
project.add_maintainer(user)
sign_in(user)
visit path
end
it_behaves_like 'dirty submit form', [{ form: '.js-general-settings-form', input: 'input[name="project[name]"]' },
{ form: '.qa-merge-request-settings', input: '#project_printing_merge_request_link_enabled' }]
end
def remove_with_confirm(button_text, confirm_with) def remove_with_confirm(button_text, confirm_with)
click_button button_text click_button button_text
fill_in 'confirm_name_input', with: confirm_with fill_in 'confirm_name_input', with: confirm_with
......
shared_examples 'dirty submit form' do |selector_args| shared_examples 'dirty submit form' do |selector_args|
selectors = selector_args.is_a?(Array) ? selector_args : [selector_args] selectors = selector_args.is_a?(Array) ? selector_args : [selector_args]
def expect_disabled_state(form, submit, is_disabled = true) def expect_disabled_state(form, submit_selector, is_disabled = true)
disabled_selector = is_disabled == true ? '[disabled]' : ':not([disabled])' disabled_selector = is_disabled == true ? '[disabled]' : ':not([disabled])'
form.find(".js-dirty-submit#{disabled_selector}", match: :first) form.find("#{submit_selector}#{disabled_selector}")
expect(submit.disabled?).to be is_disabled
end end
selectors.each do |selector| selectors.each do |selector|
it "disables #{selector[:form]} submit until there are changes on #{selector[:input]}", :js do it "disables #{selector[:form]} submit until there are changes on #{selector[:input]}", :js do
form = find(selector[:form]) form = find(selector[:form])
submit = form.first('.js-dirty-submit') submit_selector = selector[:submit] || 'input[type="submit"]'
submit = form.first(submit_selector)
input = form.first(selector[:input]) input = form.first(selector[:input])
is_radio = input[:type] == 'radio' is_radio = input[:type] == 'radio'
is_checkbox = input[:type] == 'checkbox' is_checkbox = input[:type] == 'checkbox'
...@@ -22,15 +21,14 @@ shared_examples 'dirty submit form' do |selector_args| ...@@ -22,15 +21,14 @@ shared_examples 'dirty submit form' do |selector_args|
original_checkable = input if is_checkbox original_checkable = input if is_checkbox
expect(submit.disabled?).to be true expect(submit.disabled?).to be true
expect(input.checked?).to be false
is_checkable ? input.click : input.set("#{original_value} changes") is_checkable ? input.click : input.set("#{original_value} changes")
expect_disabled_state(form, submit, false) expect_disabled_state(form, submit_selector, false)
is_checkable ? original_checkable.click : input.set(original_value) is_checkable ? original_checkable.click : input.set(original_value)
expect_disabled_state(form, submit) expect_disabled_state(form, submit_selector)
end end
end end
end end
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