Resolve "When changing project visibility setting, change other dropdowns automatically"

This commit is contained in:
Mike Greiling 2017-06-06 08:28:39 +00:00 committed by Phil Hughes
parent 17feb2faa7
commit e245d7eebe
10 changed files with 95 additions and 17 deletions

View file

@ -1,11 +1,17 @@
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, no-unused-vars, one-var, no-underscore-dangle, prefer-template, no-else-return, prefer-arrow-callback, max-len */ /* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, no-unused-vars, one-var, no-underscore-dangle, prefer-template, no-else-return, prefer-arrow-callback, max-len */
function highlightChanges($elm) {
$elm.addClass('highlight-changes');
setTimeout(() => $elm.removeClass('highlight-changes'), 10);
}
(function() { (function() {
this.ProjectNew = (function() { this.ProjectNew = (function() {
function ProjectNew() { function ProjectNew() {
this.toggleSettings = this.toggleSettings.bind(this); this.toggleSettings = this.toggleSettings.bind(this);
this.$selects = $('.features select'); this.$selects = $('.features select');
this.$repoSelects = this.$selects.filter('.js-repo-select'); this.$repoSelects = this.$selects.filter('.js-repo-select');
this.$projectSelects = this.$selects.not('.js-repo-select');
$('.project-edit-container').on('ajax:before', (function(_this) { $('.project-edit-container').on('ajax:before', (function(_this) {
return function() { return function() {
@ -26,6 +32,42 @@
if (!visibilityContainer) return; if (!visibilityContainer) return;
const visibilitySelect = new gl.VisibilitySelect(visibilityContainer); const visibilitySelect = new gl.VisibilitySelect(visibilityContainer);
visibilitySelect.init(); visibilitySelect.init();
const $visibilitySelect = $(visibilityContainer).find('select');
let projectVisibility = $visibilitySelect.val();
const PROJECT_VISIBILITY_PRIVATE = '0';
$visibilitySelect.on('change', () => {
const newProjectVisibility = $visibilitySelect.val();
if (projectVisibility !== newProjectVisibility) {
this.$projectSelects.each((idx, select) => {
const $select = $(select);
const $options = $select.find('option');
const values = $.map($options, e => e.value);
// if switched to "private", limit visibility options
if (newProjectVisibility === PROJECT_VISIBILITY_PRIVATE) {
if ($select.val() !== values[0] && $select.val() !== values[1]) {
$select.val(values[1]).trigger('change');
highlightChanges($select);
}
$options.slice(2).disable();
}
// if switched from "private", increase visibility for non-disabled options
if (projectVisibility === PROJECT_VISIBILITY_PRIVATE) {
$options.enable();
if ($select.val() !== values[0] && $select.val() !== values[values.length - 1]) {
$select.val(values[values.length - 1]).trigger('change');
highlightChanges($select);
}
}
});
projectVisibility = newProjectVisibility;
}
});
}; };
ProjectNew.prototype.toggleSettings = function() { ProjectNew.prototype.toggleSettings = function() {
@ -56,8 +98,10 @@
ProjectNew.prototype.toggleRepoVisibility = function () { ProjectNew.prototype.toggleRepoVisibility = function () {
var $repoAccessLevel = $('.js-repo-access-level select'); var $repoAccessLevel = $('.js-repo-access-level select');
var $lfsEnabledOption = $('.js-lfs-enabled select');
var containerRegistry = document.querySelectorAll('.js-container-registry')[0]; var containerRegistry = document.querySelectorAll('.js-container-registry')[0];
var containerRegistryCheckbox = document.getElementById('project_container_registry_enabled'); var containerRegistryCheckbox = document.getElementById('project_container_registry_enabled');
var prevSelectedVal = parseInt($repoAccessLevel.val(), 10);
this.$repoSelects.find("option[value='" + $repoAccessLevel.val() + "']") this.$repoSelects.find("option[value='" + $repoAccessLevel.val() + "']")
.nextAll() .nextAll()
@ -71,29 +115,40 @@
var $this = $(this); var $this = $(this);
var repoSelectVal = parseInt($this.val(), 10); var repoSelectVal = parseInt($this.val(), 10);
$this.find('option').show(); $this.find('option').enable();
if (selectedVal < repoSelectVal) { if (selectedVal < repoSelectVal || repoSelectVal === prevSelectedVal) {
$this.val(selectedVal); $this.val(selectedVal).trigger('change');
highlightChanges($this);
} }
$this.find("option[value='" + selectedVal + "']").nextAll().hide(); $this.find("option[value='" + selectedVal + "']").nextAll().disable();
}); });
if (selectedVal) { if (selectedVal) {
this.$repoSelects.removeClass('disabled'); this.$repoSelects.removeClass('disabled');
if ($lfsEnabledOption.length) {
$lfsEnabledOption.removeClass('disabled');
highlightChanges($lfsEnabledOption);
}
if (containerRegistry) { if (containerRegistry) {
containerRegistry.style.display = ''; containerRegistry.style.display = '';
} }
} else { } else {
this.$repoSelects.addClass('disabled'); this.$repoSelects.addClass('disabled');
if ($lfsEnabledOption.length) {
$lfsEnabledOption.val('false').addClass('disabled');
highlightChanges($lfsEnabledOption);
}
if (containerRegistry) { if (containerRegistry) {
containerRegistry.style.display = 'none'; containerRegistry.style.display = 'none';
containerRegistryCheckbox.checked = false; containerRegistryCheckbox.checked = false;
} }
} }
prevSelectedVal = selectedVal;
}.bind(this)); }.bind(this));
}; };

View file

@ -187,6 +187,7 @@ $divergence-graph-bar-bg: #ccc;
$divergence-graph-separator-bg: #ccc; $divergence-graph-separator-bg: #ccc;
$general-hover-transition-duration: 100ms; $general-hover-transition-duration: 100ms;
$general-hover-transition-curve: linear; $general-hover-transition-curve: linear;
$highlight-changes-color: rgb(235, 255, 232);
/* /*

View file

@ -29,6 +29,20 @@
& > .form-group { & > .form-group {
padding-left: 0; padding-left: 0;
} }
select option[disabled] {
display: none;
}
}
select {
background: transparent;
transition: background 2s ease-out;
&.highlight-changes {
background: $highlight-changes-color;
transition: none;
}
} }
.help-block { .help-block {

View file

@ -138,11 +138,15 @@ module ProjectsHelper
if @project.private? if @project.private?
level = @project.project_feature.send(field) level = @project.project_feature.send(field)
options.delete('Everyone with access') disabled_option = ProjectFeature::ENABLED
highest_available_option = options.values.max if level == ProjectFeature::ENABLED highest_available_option = ProjectFeature::PRIVATE if level == disabled_option
end end
options = options_for_select(options, selected: highest_available_option || @project.project_feature.public_send(field)) options = options_for_select(
options,
selected: highest_available_option || @project.project_feature.public_send(field),
disabled: disabled_option
)
content_tag( content_tag(
:select, :select,

View file

@ -31,9 +31,9 @@ module VisibilityLevelHelper
when Gitlab::VisibilityLevel::PRIVATE when Gitlab::VisibilityLevel::PRIVATE
"Project access must be granted explicitly to each user." "Project access must be granted explicitly to each user."
when Gitlab::VisibilityLevel::INTERNAL when Gitlab::VisibilityLevel::INTERNAL
"The project can be cloned by any logged in user." "The project can be accessed by any logged in user."
when Gitlab::VisibilityLevel::PUBLIC when Gitlab::VisibilityLevel::PUBLIC
"The project can be cloned without any authentication." "The project can be accessed without any authentication."
end end
end end

View file

@ -42,7 +42,7 @@
.col-md-9 .col-md-9
.label-light .label-light
= label_tag :project_visibility, 'Project Visibility', class: 'label-light', for: :project_visibility_level = label_tag :project_visibility, 'Project Visibility', class: 'label-light', for: :project_visibility_level
= link_to "(?)", help_page_path("public_access/public_access") = link_to icon('question-circle'), help_page_path("public_access/public_access")
%span.help-block %span.help-block
.col-md-3.visibility-select-container .col-md-3.visibility-select-container
= render('projects/visibility_select', model_method: :visibility_level, form: f, selected_level: @project.visibility_level) = render('projects/visibility_select', model_method: :visibility_level, form: f, selected_level: @project.visibility_level)
@ -92,14 +92,14 @@
.form-group .form-group
= render 'shared/allow_request_access', form: f = render 'shared/allow_request_access', form: f
- if Gitlab.config.lfs.enabled && current_user.admin? - if Gitlab.config.lfs.enabled && current_user.admin?
.row .row.js-lfs-enabled
.col-md-9 .col-md-9
= f.label :lfs_enabled, 'LFS', class: 'label-light' = f.label :lfs_enabled, 'LFS', class: 'label-light'
%span.help-block %span.help-block
Git Large File Storage Git Large File Storage
= link_to icon('question-circle'), help_page_path('workflow/lfs/manage_large_binaries_with_git_lfs') = link_to icon('question-circle'), help_page_path('workflow/lfs/manage_large_binaries_with_git_lfs')
.col-md-3 .col-md-3
= f.select :lfs_enabled, [%w(Enabled true), %w(Disabled false)], {}, selected: @project.lfs_enabled?, class: 'pull-right form-control', data: { field: 'lfs_enabled' } = f.select :lfs_enabled, [%w(Enabled true), %w(Disabled false)], {}, selected: @project.lfs_enabled?, class: 'pull-right form-control project-repo-select', data: { field: 'lfs_enabled' }
- if Gitlab.config.registry.enabled - if Gitlab.config.registry.enabled

View file

@ -0,0 +1,4 @@
---
title: Automatically adjust project settings to match changes in project visibility
merge_request: 11831
author:

View file

@ -14,7 +14,7 @@ feature 'Visibility settings', feature: true, js: true do
visibility_select_container = find('.js-visibility-select') visibility_select_container = find('.js-visibility-select')
expect(visibility_select_container.find('.visibility-select').value).to eq project.visibility_level.to_s expect(visibility_select_container.find('.visibility-select').value).to eq project.visibility_level.to_s
expect(visibility_select_container).to have_content 'The project can be cloned without any authentication.' expect(visibility_select_container).to have_content 'The project can be accessed without any authentication.'
end end
scenario 'project visibility description updates on change' do scenario 'project visibility description updates on change' do
@ -41,7 +41,7 @@ feature 'Visibility settings', feature: true, js: true do
expect(visibility_select_container).not_to have_select '.visibility-select' expect(visibility_select_container).not_to have_select '.visibility-select'
expect(visibility_select_container).to have_content 'Public' expect(visibility_select_container).to have_content 'Public'
expect(visibility_select_container).to have_content 'The project can be cloned without any authentication.' expect(visibility_select_container).to have_content 'The project can be accessed without any authentication.'
end end
end end
end end

View file

@ -257,7 +257,7 @@ describe ProjectsHelper do
result = helper.project_feature_access_select(:issues_access_level) result = helper.project_feature_access_select(:issues_access_level)
expect(result).to include("Disabled") expect(result).to include("Disabled")
expect(result).to include("Only team members") expect(result).to include("Only team members")
expect(result).not_to include("Everyone with access") expect(result).to have_selector('option[disabled]', text: "Everyone with access")
end end
end end
@ -272,7 +272,7 @@ describe ProjectsHelper do
expect(result).to include("Disabled") expect(result).to include("Disabled")
expect(result).to include("Only team members") expect(result).to include("Only team members")
expect(result).not_to include("Everyone with access") expect(result).to have_selector('option[disabled]', text: "Everyone with access")
expect(result).to have_selector('option[selected]', text: "Only team members") expect(result).to have_selector('option[selected]', text: "Only team members")
end end
end end

View file

@ -37,7 +37,7 @@ describe VisibilityLevelHelper do
it "describes public projects" do it "describes public projects" do
expect(project_visibility_level_description(Gitlab::VisibilityLevel::PUBLIC)) expect(project_visibility_level_description(Gitlab::VisibilityLevel::PUBLIC))
.to eq "The project can be cloned without any authentication." .to eq "The project can be accessed without any authentication."
end end
end end