Merge branch 'branch-permissions' into 'master'
Branch permissions layout CE part of https://gitlab.com/gitlab-org/gitlab-ee/issues/179 Related javascript code has been refactored and also layout has been updated. ![Screen_Shot_2016-08-04_at_3.23.19_PM](/uploads/a0f6165e255b3f93dcb80eaa3f3318e4/Screen_Shot_2016-08-04_at_3.23.19_PM.png) See merge request !5652
This commit is contained in:
commit
b767d86885
18 changed files with 350 additions and 229 deletions
|
@ -173,8 +173,8 @@
|
||||||
new Search();
|
new Search();
|
||||||
break;
|
break;
|
||||||
case 'projects:protected_branches:index':
|
case 'projects:protected_branches:index':
|
||||||
new ProtectedBranchesAccessSelect($(".new_protected_branch"), false, true);
|
new gl.ProtectedBranchCreate();
|
||||||
new ProtectedBranchesAccessSelect($(".protected-branches-list"), true, false);
|
new gl.ProtectedBranchEditList();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
switch (path.first()) {
|
switch (path.first()) {
|
||||||
|
|
|
@ -607,7 +607,7 @@
|
||||||
return this.dropdown.before($input);
|
return this.dropdown.before($input);
|
||||||
};
|
};
|
||||||
|
|
||||||
GitLabDropdown.prototype.selectRowAtIndex = function(e, index) {
|
GitLabDropdown.prototype.selectRowAtIndex = function(index) {
|
||||||
var $el, selector;
|
var $el, selector;
|
||||||
selector = ".dropdown-content li:not(.divider,.dropdown-header,.separator):eq(" + index + ") a";
|
selector = ".dropdown-content li:not(.divider,.dropdown-header,.separator):eq(" + index + ") a";
|
||||||
if (this.dropdown.find(".dropdown-toggle-page").length) {
|
if (this.dropdown.find(".dropdown-toggle-page").length) {
|
||||||
|
@ -615,8 +615,6 @@
|
||||||
}
|
}
|
||||||
$el = $(selector, this.dropdown);
|
$el = $(selector, this.dropdown);
|
||||||
if ($el.length) {
|
if ($el.length) {
|
||||||
e.preventDefault();
|
|
||||||
e.stopImmediatePropagation();
|
|
||||||
return $el.first().trigger('click');
|
return $el.first().trigger('click');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -653,7 +651,7 @@
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (currentKeyCode === 13 && currentIndex !== -1) {
|
if (currentKeyCode === 13 && currentIndex !== -1) {
|
||||||
return _this.selectRowAtIndex(e, $('.is-focused', _this.dropdown).closest('li').index() - 1);
|
return _this.selectRowAtIndex($('.is-focused', _this.dropdown).closest('li').index() - 1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
})(this));
|
})(this));
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
(global => {
|
||||||
|
global.gl = global.gl || {};
|
||||||
|
|
||||||
|
gl.ProtectedBranchAccessDropdown = class {
|
||||||
|
constructor(options) {
|
||||||
|
const { $dropdown, data, onSelect } = options;
|
||||||
|
|
||||||
|
$dropdown.glDropdown({
|
||||||
|
data: data,
|
||||||
|
selectable: true,
|
||||||
|
inputId: $dropdown.data('input-id'),
|
||||||
|
fieldName: $dropdown.data('field-name'),
|
||||||
|
toggleLabel(item) {
|
||||||
|
return item.text;
|
||||||
|
},
|
||||||
|
clicked(item, $el, e) {
|
||||||
|
e.preventDefault();
|
||||||
|
onSelect();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
})(window);
|
56
app/assets/javascripts/protected_branch_create.js.es6
Normal file
56
app/assets/javascripts/protected_branch_create.js.es6
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
(global => {
|
||||||
|
global.gl = global.gl || {};
|
||||||
|
|
||||||
|
gl.ProtectedBranchCreate = class {
|
||||||
|
constructor() {
|
||||||
|
this.$wrap = this.$form = $('#new_protected_branch');
|
||||||
|
this.buildDropdowns();
|
||||||
|
}
|
||||||
|
|
||||||
|
buildDropdowns() {
|
||||||
|
const $allowedToMergeDropdown = this.$wrap.find('.js-allowed-to-merge');
|
||||||
|
const $allowedToPushDropdown = this.$wrap.find('.js-allowed-to-push');
|
||||||
|
|
||||||
|
// Cache callback
|
||||||
|
this.onSelectCallback = this.onSelect.bind(this);
|
||||||
|
|
||||||
|
// Allowed to Merge dropdown
|
||||||
|
new gl.ProtectedBranchAccessDropdown({
|
||||||
|
$dropdown: $allowedToMergeDropdown,
|
||||||
|
data: gon.merge_access_levels,
|
||||||
|
onSelect: this.onSelectCallback
|
||||||
|
});
|
||||||
|
|
||||||
|
// Allowed to Push dropdown
|
||||||
|
new gl.ProtectedBranchAccessDropdown({
|
||||||
|
$dropdown: $allowedToPushDropdown,
|
||||||
|
data: gon.push_access_levels,
|
||||||
|
onSelect: this.onSelectCallback
|
||||||
|
});
|
||||||
|
|
||||||
|
// Select default
|
||||||
|
$allowedToPushDropdown.data('glDropdown').selectRowAtIndex(0);
|
||||||
|
$allowedToMergeDropdown.data('glDropdown').selectRowAtIndex(0);
|
||||||
|
|
||||||
|
// Protected branch dropdown
|
||||||
|
new ProtectedBranchDropdown({
|
||||||
|
$dropdown: this.$wrap.find('.js-protected-branch-select'),
|
||||||
|
onSelect: this.onSelectCallback
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// This will run after clicked callback
|
||||||
|
onSelect() {
|
||||||
|
|
||||||
|
// Enable submit button
|
||||||
|
const $branchInput = this.$wrap.find('input[name="protected_branch[name]"]');
|
||||||
|
const $allowedToMergeInput = this.$wrap.find('input[name="protected_branch[merge_access_level_attributes][access_level]"]');
|
||||||
|
const $allowedToPushInput = this.$wrap.find('input[name="protected_branch[push_access_level_attributes][access_level]"]');
|
||||||
|
|
||||||
|
if ($branchInput.val() && $allowedToMergeInput.val() && $allowedToPushInput.val()){
|
||||||
|
this.$form.find('input[type="submit"]').removeAttr('disabled');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
})(window);
|
75
app/assets/javascripts/protected_branch_dropdown.js.es6
Normal file
75
app/assets/javascripts/protected_branch_dropdown.js.es6
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
class ProtectedBranchDropdown {
|
||||||
|
constructor(options) {
|
||||||
|
this.onSelect = options.onSelect;
|
||||||
|
this.$dropdown = options.$dropdown;
|
||||||
|
this.$dropdownContainer = this.$dropdown.parent();
|
||||||
|
this.$dropdownFooter = this.$dropdownContainer.find('.dropdown-footer');
|
||||||
|
this.$protectedBranch = this.$dropdownContainer.find('.create-new-protected-branch');
|
||||||
|
|
||||||
|
this.buildDropdown();
|
||||||
|
this.bindEvents();
|
||||||
|
|
||||||
|
// Hide footer
|
||||||
|
this.$dropdownFooter.addClass('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
buildDropdown() {
|
||||||
|
this.$dropdown.glDropdown({
|
||||||
|
data: this.getProtectedBranches.bind(this),
|
||||||
|
filterable: true,
|
||||||
|
remote: false,
|
||||||
|
search: {
|
||||||
|
fields: ['title']
|
||||||
|
},
|
||||||
|
selectable: true,
|
||||||
|
toggleLabel(selected) {
|
||||||
|
return (selected && 'id' in selected) ? selected.title : 'Protected Branch';
|
||||||
|
},
|
||||||
|
fieldName: 'protected_branch[name]',
|
||||||
|
text(protectedBranch) {
|
||||||
|
return _.escape(protectedBranch.title);
|
||||||
|
},
|
||||||
|
id(protectedBranch) {
|
||||||
|
return _.escape(protectedBranch.id);
|
||||||
|
},
|
||||||
|
onFilter: this.toggleCreateNewButton.bind(this),
|
||||||
|
clicked: (item, $el, e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
this.onSelect();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bindEvents() {
|
||||||
|
this.$protectedBranch.on('click', this.onClickCreateWildcard.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
onClickCreateWildcard() {
|
||||||
|
this.$dropdown.data('glDropdown').remote.execute();
|
||||||
|
this.$dropdown.data('glDropdown').selectRowAtIndex(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
getProtectedBranches(term, callback) {
|
||||||
|
if (this.selectedBranch) {
|
||||||
|
callback(gon.open_branches.concat(this.selectedBranch));
|
||||||
|
} else {
|
||||||
|
callback(gon.open_branches);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleCreateNewButton(branchName) {
|
||||||
|
this.selectedBranch = {
|
||||||
|
title: branchName,
|
||||||
|
id: branchName,
|
||||||
|
text: branchName
|
||||||
|
};
|
||||||
|
|
||||||
|
if (branchName) {
|
||||||
|
this.$dropdownContainer
|
||||||
|
.find('.create-new-protected-branch code')
|
||||||
|
.text(branchName);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$dropdownFooter.toggleClass('hidden', !branchName);
|
||||||
|
}
|
||||||
|
}
|
61
app/assets/javascripts/protected_branch_edit.js.es6
Normal file
61
app/assets/javascripts/protected_branch_edit.js.es6
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
(global => {
|
||||||
|
global.gl = global.gl || {};
|
||||||
|
|
||||||
|
gl.ProtectedBranchEdit = class {
|
||||||
|
constructor(options) {
|
||||||
|
this.$wrap = options.$wrap;
|
||||||
|
this.$allowedToMergeDropdown = this.$wrap.find('.js-allowed-to-merge');
|
||||||
|
this.$allowedToPushDropdown = this.$wrap.find('.js-allowed-to-push');
|
||||||
|
|
||||||
|
this.buildDropdowns();
|
||||||
|
}
|
||||||
|
|
||||||
|
buildDropdowns() {
|
||||||
|
|
||||||
|
// Allowed to merge dropdown
|
||||||
|
new gl.ProtectedBranchAccessDropdown({
|
||||||
|
$dropdown: this.$allowedToMergeDropdown,
|
||||||
|
data: gon.merge_access_levels,
|
||||||
|
onSelect: this.onSelect.bind(this)
|
||||||
|
});
|
||||||
|
|
||||||
|
// Allowed to push dropdown
|
||||||
|
new gl.ProtectedBranchAccessDropdown({
|
||||||
|
$dropdown: this.$allowedToPushDropdown,
|
||||||
|
data: gon.push_access_levels,
|
||||||
|
onSelect: this.onSelect.bind(this)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onSelect() {
|
||||||
|
const $allowedToMergeInput = this.$wrap.find(`input[name="${this.$allowedToMergeDropdown.data('fieldName')}"]`);
|
||||||
|
const $allowedToPushInput = this.$wrap.find(`input[name="${this.$allowedToPushDropdown.data('fieldName')}"]`);
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
type: 'POST',
|
||||||
|
url: this.$wrap.data('url'),
|
||||||
|
dataType: 'json',
|
||||||
|
data: {
|
||||||
|
_method: 'PATCH',
|
||||||
|
id: this.$wrap.data('banchId'),
|
||||||
|
protected_branch: {
|
||||||
|
merge_access_level_attributes: {
|
||||||
|
access_level: $allowedToMergeInput.val()
|
||||||
|
},
|
||||||
|
push_access_level_attributes: {
|
||||||
|
access_level: $allowedToPushInput.val()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
success: () => {
|
||||||
|
this.$wrap.effect('highlight');
|
||||||
|
},
|
||||||
|
error() {
|
||||||
|
$.scrollTo(0);
|
||||||
|
new Flash('Failed to update branch!');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
})(window);
|
17
app/assets/javascripts/protected_branch_edit_list.js.es6
Normal file
17
app/assets/javascripts/protected_branch_edit_list.js.es6
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
(global => {
|
||||||
|
global.gl = global.gl || {};
|
||||||
|
|
||||||
|
gl.ProtectedBranchEditList = class {
|
||||||
|
constructor() {
|
||||||
|
this.$wrap = $('.protected-branches-list');
|
||||||
|
|
||||||
|
// Build edit forms
|
||||||
|
this.$wrap.find('.js-protected-branch-edit-form').each((i, el) => {
|
||||||
|
new gl.ProtectedBranchEdit({
|
||||||
|
$wrap: $(el)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
})(window);
|
|
@ -1,72 +0,0 @@
|
||||||
(function() {
|
|
||||||
var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
|
|
||||||
|
|
||||||
this.ProtectedBranchSelect = (function() {
|
|
||||||
function ProtectedBranchSelect(currentProject) {
|
|
||||||
this.toggleCreateNewButton = bind(this.toggleCreateNewButton, this);
|
|
||||||
this.getProtectedBranches = bind(this.getProtectedBranches, this);
|
|
||||||
$('.dropdown-footer').hide();
|
|
||||||
this.dropdown = $('.js-protected-branch-select').glDropdown({
|
|
||||||
data: this.getProtectedBranches,
|
|
||||||
filterable: true,
|
|
||||||
remote: false,
|
|
||||||
search: {
|
|
||||||
fields: ['title']
|
|
||||||
},
|
|
||||||
selectable: true,
|
|
||||||
toggleLabel: function(selected) {
|
|
||||||
if (selected && 'id' in selected) {
|
|
||||||
return selected.title;
|
|
||||||
} else {
|
|
||||||
return 'Protected Branch';
|
|
||||||
}
|
|
||||||
},
|
|
||||||
fieldName: 'protected_branch[name]',
|
|
||||||
text: function(protected_branch) {
|
|
||||||
return _.escape(protected_branch.title);
|
|
||||||
},
|
|
||||||
id: function(protected_branch) {
|
|
||||||
return _.escape(protected_branch.id);
|
|
||||||
},
|
|
||||||
onFilter: this.toggleCreateNewButton,
|
|
||||||
clicked: function() {
|
|
||||||
return $('.protect-branch-btn').attr('disabled', false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
$('.create-new-protected-branch').on('click', (function(_this) {
|
|
||||||
return function(event) {
|
|
||||||
_this.dropdown.data('glDropdown').remote.execute();
|
|
||||||
return _this.dropdown.data('glDropdown').selectRowAtIndex(event, 0);
|
|
||||||
};
|
|
||||||
})(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
ProtectedBranchSelect.prototype.getProtectedBranches = function(term, callback) {
|
|
||||||
if (this.selectedBranch) {
|
|
||||||
return callback(gon.open_branches.concat(this.selectedBranch));
|
|
||||||
} else {
|
|
||||||
return callback(gon.open_branches);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ProtectedBranchSelect.prototype.toggleCreateNewButton = function(branchName) {
|
|
||||||
this.selectedBranch = {
|
|
||||||
title: branchName,
|
|
||||||
id: branchName,
|
|
||||||
text: branchName
|
|
||||||
};
|
|
||||||
if (branchName === '') {
|
|
||||||
$('.protected-branch-select-footer-list').addClass('hidden');
|
|
||||||
return $('.dropdown-footer').hide();
|
|
||||||
} else {
|
|
||||||
$('.create-new-protected-branch').text("Create Protected Branch: " + branchName);
|
|
||||||
$('.protected-branch-select-footer-list').removeClass('hidden');
|
|
||||||
return $('.dropdown-footer').show();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return ProtectedBranchSelect;
|
|
||||||
|
|
||||||
})();
|
|
||||||
|
|
||||||
}).call(this);
|
|
|
@ -1,63 +0,0 @@
|
||||||
class ProtectedBranchesAccessSelect {
|
|
||||||
constructor(container, saveOnSelect, selectDefault) {
|
|
||||||
this.container = container;
|
|
||||||
this.saveOnSelect = saveOnSelect;
|
|
||||||
|
|
||||||
this.container.find(".allowed-to-merge").each((i, element) => {
|
|
||||||
var fieldName = $(element).data('field-name');
|
|
||||||
var dropdown = $(element).glDropdown({
|
|
||||||
data: gon.merge_access_levels,
|
|
||||||
selectable: true,
|
|
||||||
fieldName: fieldName,
|
|
||||||
clicked: _.chain(this.onSelect).partial(element).bind(this).value()
|
|
||||||
});
|
|
||||||
|
|
||||||
if (selectDefault) {
|
|
||||||
dropdown.data('glDropdown').selectRowAtIndex(document.createEvent("Event"), 0);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
this.container.find(".allowed-to-push").each((i, element) => {
|
|
||||||
var fieldName = $(element).data('field-name');
|
|
||||||
var dropdown = $(element).glDropdown({
|
|
||||||
data: gon.push_access_levels,
|
|
||||||
selectable: true,
|
|
||||||
fieldName: fieldName,
|
|
||||||
clicked: _.chain(this.onSelect).partial(element).bind(this).value()
|
|
||||||
});
|
|
||||||
|
|
||||||
if (selectDefault) {
|
|
||||||
dropdown.data('glDropdown').selectRowAtIndex(document.createEvent("Event"), 0);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onSelect(dropdown, selected, element, e) {
|
|
||||||
$(dropdown).find('.dropdown-toggle-text').text(selected.text);
|
|
||||||
if (this.saveOnSelect) {
|
|
||||||
return $.ajax({
|
|
||||||
type: "POST",
|
|
||||||
url: $(dropdown).data('url'),
|
|
||||||
dataType: "json",
|
|
||||||
data: {
|
|
||||||
_method: 'PATCH',
|
|
||||||
id: $(dropdown).data('id'),
|
|
||||||
protected_branch: {
|
|
||||||
["" + ($(dropdown).data('type')) + "_attributes"]: {
|
|
||||||
"access_level": selected.id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
success: function() {
|
|
||||||
var row;
|
|
||||||
row = $(e.target);
|
|
||||||
return row.closest('tr').effect('highlight');
|
|
||||||
},
|
|
||||||
error: function() {
|
|
||||||
return new Flash("Failed to update branch!", "alert");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -72,6 +72,14 @@
|
||||||
&.large {
|
&.large {
|
||||||
width: 200px;
|
width: 200px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.wide {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
+ .dropdown-select {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropdown-menu,
|
.dropdown-menu,
|
||||||
|
|
|
@ -23,4 +23,9 @@
|
||||||
margin-top: $gl-padding;
|
margin-top: $gl-padding;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.panel-title {
|
||||||
|
font-size: inherit;
|
||||||
|
line-height: inherit;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -656,13 +656,9 @@ pre.light-well {
|
||||||
}
|
}
|
||||||
|
|
||||||
.new_protected_branch {
|
.new_protected_branch {
|
||||||
.dropdown {
|
|
||||||
display: inline;
|
|
||||||
margin-left: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
label {
|
label {
|
||||||
min-width: 120px;
|
margin-top: 6px;
|
||||||
|
font-weight: normal;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -678,6 +674,21 @@ pre.light-well {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.settings-message {
|
||||||
|
margin: 0;
|
||||||
|
border-radius: 0 0 1px 1px;
|
||||||
|
padding: 20px 0;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-bordered {
|
||||||
|
border-radius: 1px;
|
||||||
|
|
||||||
|
th:not(:last-child), td:not(:last-child) {
|
||||||
|
border-right: solid 1px transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-notifications-form {
|
.custom-notifications-form {
|
||||||
|
|
|
@ -1,26 +1,28 @@
|
||||||
%h5.prepend-top-0
|
.panel.panel-default.protected-branches-list
|
||||||
Already Protected (#{@protected_branches.size})
|
- if @protected_branches.empty?
|
||||||
- if @protected_branches.empty?
|
.panel-heading
|
||||||
%p.settings-message.text-center
|
%h3.panel-title
|
||||||
No branches are protected, protect a branch with the form above.
|
Protected branch (#{@protected_branches.size})
|
||||||
- else
|
%p.settings-message.text-center
|
||||||
- can_admin_project = can?(current_user, :admin_project, @project)
|
There are currently no protected branches, protect a branch with the form above.
|
||||||
|
- else
|
||||||
|
- can_admin_project = can?(current_user, :admin_project, @project)
|
||||||
|
|
||||||
%table.table.protected-branches-list
|
%table.table.table-bordered
|
||||||
%colgroup
|
%colgroup
|
||||||
%col{ width: "20%" }
|
%col{ width: "25%" }
|
||||||
%col{ width: "30%" }
|
%col{ width: "30%" }
|
||||||
%col{ width: "25%" }
|
%col{ width: "25%" }
|
||||||
%col{ width: "25%" }
|
%col{ width: "20%" }
|
||||||
%thead
|
%thead
|
||||||
%tr
|
%tr
|
||||||
%th Branch
|
%th Protected branch (#{@protected_branches.size})
|
||||||
%th Last commit
|
%th Last commit
|
||||||
%th Allowed to merge
|
%th Allowed to merge
|
||||||
%th Allowed to push
|
%th Allowed to push
|
||||||
- if can_admin_project
|
- if can_admin_project
|
||||||
%th
|
%th
|
||||||
%tbody
|
%tbody
|
||||||
= render partial: @protected_branches, locals: { can_admin_project: can_admin_project }
|
= render partial: @protected_branches, locals: { can_admin_project: can_admin_project }
|
||||||
|
|
||||||
= paginate @protected_branches, theme: 'gitlab'
|
= paginate @protected_branches, theme: 'gitlab'
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
= form_for [@project.namespace.becomes(Namespace), @project, @protected_branch] do |f|
|
||||||
|
.panel.panel-default
|
||||||
|
.panel-heading
|
||||||
|
%h3.panel-title
|
||||||
|
Protect a branch
|
||||||
|
.panel-body
|
||||||
|
.form-horizontal
|
||||||
|
.form-group
|
||||||
|
= f.label :name, class: 'col-md-2 text-right' do
|
||||||
|
Branch:
|
||||||
|
.col-md-10
|
||||||
|
= render partial: "dropdown", locals: { f: f }
|
||||||
|
.help-block
|
||||||
|
= link_to 'Wildcards', help_page_path('user/project/protected_branches', anchor: 'wildcard-protected-branches')
|
||||||
|
such as
|
||||||
|
%code *-stable
|
||||||
|
or
|
||||||
|
%code production/*
|
||||||
|
are supported
|
||||||
|
.form-group
|
||||||
|
%label.col-md-2.text-right{ for: 'merge_access_level_attributes' }
|
||||||
|
Allowed to merge:
|
||||||
|
.col-md-10
|
||||||
|
= dropdown_tag('Select',
|
||||||
|
options: { toggle_class: 'js-allowed-to-merge wide',
|
||||||
|
data: { field_name: 'protected_branch[merge_access_level_attributes][access_level]', input_id: 'merge_access_level_attributes' }})
|
||||||
|
.form-group
|
||||||
|
%label.col-md-2.text-right{ for: 'push_access_level_attributes' }
|
||||||
|
Allowed to push:
|
||||||
|
.col-md-10
|
||||||
|
= dropdown_tag('Select',
|
||||||
|
options: { toggle_class: 'js-allowed-to-push wide',
|
||||||
|
data: { field_name: 'protected_branch[push_access_level_attributes][access_level]', input_id: 'push_access_level_attributes' }})
|
||||||
|
|
||||||
|
.panel-footer
|
||||||
|
= f.submit 'Protect', class: 'btn-create btn', disabled: true
|
|
@ -1,17 +1,15 @@
|
||||||
= f.hidden_field(:name)
|
= f.hidden_field(:name)
|
||||||
|
|
||||||
= dropdown_tag("Protected Branch",
|
= dropdown_tag('Select branch or create wildcard',
|
||||||
options: { title: "Pick protected branch", toggle_class: 'js-protected-branch-select js-filter-submit',
|
options: { toggle_class: 'js-protected-branch-select js-filter-submit wide',
|
||||||
filter: true, dropdown_class: "dropdown-menu-selectable", placeholder: "Search protected branches",
|
filter: true, dropdown_class: "dropdown-menu-selectable", placeholder: "Search protected branches",
|
||||||
footer_content: true,
|
footer_content: true,
|
||||||
data: { show_no: true, show_any: true, show_upcoming: true,
|
data: { show_no: true, show_any: true, show_upcoming: true,
|
||||||
selected: params[:protected_branch_name],
|
selected: params[:protected_branch_name],
|
||||||
project_id: @project.try(:id) } }) do
|
project_id: @project.try(:id) } }) do
|
||||||
|
|
||||||
%ul.dropdown-footer-list.hidden.protected-branch-select-footer-list
|
%ul.dropdown-footer-list
|
||||||
%li
|
%li
|
||||||
= link_to '#', title: "New Protected Branch", class: "create-new-protected-branch" do
|
= link_to '#', title: "New Protected Branch", class: "create-new-protected-branch" do
|
||||||
Create new
|
Create wildcard
|
||||||
|
%code
|
||||||
:javascript
|
|
||||||
new ProtectedBranchSelect();
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
- url = namespace_project_protected_branch_path(@project.namespace, @project, protected_branch)
|
%tr.js-protected-branch-edit-form{ data: { url: namespace_project_protected_branch_path(@project.namespace, @project, protected_branch), branch_id: protected_branch.id } }
|
||||||
%tr
|
|
||||||
%td
|
%td
|
||||||
= protected_branch.name
|
= protected_branch.name
|
||||||
- if @project.root_ref?(protected_branch.name)
|
- if @project.root_ref?(protected_branch.name)
|
||||||
|
@ -16,14 +15,14 @@
|
||||||
(branch was removed from repository)
|
(branch was removed from repository)
|
||||||
%td
|
%td
|
||||||
= hidden_field_tag "allowed_to_merge_#{protected_branch.id}", protected_branch.merge_access_level.access_level
|
= hidden_field_tag "allowed_to_merge_#{protected_branch.id}", protected_branch.merge_access_level.access_level
|
||||||
= dropdown_tag(protected_branch.merge_access_level.humanize,
|
= dropdown_tag( (protected_branch.merge_access_level.humanize || 'Select') ,
|
||||||
options: { title: "Allowed to merge", toggle_class: 'allowed-to-merge', dropdown_class: 'dropdown-menu-selectable merge',
|
options: { toggle_class: 'js-allowed-to-merge', dropdown_class: 'dropdown-menu-selectable js-allowed-to-merge-container',
|
||||||
data: { field_name: "allowed_to_merge_#{protected_branch.id}", url: url, id: protected_branch.id, type: "merge_access_level" }})
|
data: { field_name: "allowed_to_merge_#{protected_branch.id}" }})
|
||||||
%td
|
%td
|
||||||
= hidden_field_tag "allowed_to_push_#{protected_branch.id}", protected_branch.push_access_level.access_level
|
= hidden_field_tag "allowed_to_push_#{protected_branch.id}", protected_branch.push_access_level.access_level
|
||||||
= dropdown_tag(protected_branch.push_access_level.humanize,
|
= dropdown_tag( (protected_branch.push_access_level.humanize || 'Select') ,
|
||||||
options: { title: "Allowed to push", toggle_class: 'allowed-to-push', dropdown_class: 'dropdown-menu-selectable push',
|
options: { toggle_class: 'js-allowed-to-push', dropdown_class: 'dropdown-menu-selectable js-allowed-to-push-container',
|
||||||
data: { field_name: "allowed_to_push_#{protected_branch.id}", url: url, id: protected_branch.id, type: "push_access_level" }})
|
data: { field_name: "allowed_to_push_#{protected_branch.id}" }})
|
||||||
- if can_admin_project
|
- if can_admin_project
|
||||||
%td
|
%td
|
||||||
= link_to 'Unprotect', [@project.namespace.becomes(Namespace), @project, protected_branch], data: { confirm: 'Branch will be writable for developers. Are you sure?' }, method: :delete, class: "btn btn-warning btn-sm pull-right"
|
= link_to 'Unprotect', [@project.namespace.becomes(Namespace), @project, protected_branch], data: { confirm: 'Branch will be writable for developers. Are you sure?' }, method: :delete, class: 'btn btn-warning'
|
||||||
|
|
|
@ -14,41 +14,7 @@
|
||||||
%li prevent <strong>anyone</strong> from deleting the branch
|
%li prevent <strong>anyone</strong> from deleting the branch
|
||||||
%p.append-bottom-0 Read more about #{link_to "protected branches", help_page_path("user/project/protected_branches"), class: "underlined-link"} and #{link_to "project permissions", help_page_path("user/permissions"), class: "underlined-link"}.
|
%p.append-bottom-0 Read more about #{link_to "protected branches", help_page_path("user/project/protected_branches"), class: "underlined-link"} and #{link_to "project permissions", help_page_path("user/permissions"), class: "underlined-link"}.
|
||||||
.col-lg-9
|
.col-lg-9
|
||||||
%h5.prepend-top-0
|
|
||||||
Protect a branch
|
|
||||||
- if can? current_user, :admin_project, @project
|
- if can? current_user, :admin_project, @project
|
||||||
= form_for [@project.namespace.becomes(Namespace), @project, @protected_branch] do |f|
|
= render 'create_protected_branch'
|
||||||
= form_errors(@protected_branch)
|
|
||||||
|
|
||||||
.form-group
|
|
||||||
= f.label :name, "Branch", class: "label-light"
|
|
||||||
= render partial: "dropdown", locals: { f: f }
|
|
||||||
%p.help-block
|
|
||||||
= link_to "Wildcards", help_page_path('user/project/protected_branches', anchor: "wildcard-protected-branches")
|
|
||||||
such as
|
|
||||||
%code *-stable
|
|
||||||
or
|
|
||||||
%code production/*
|
|
||||||
are supported.
|
|
||||||
|
|
||||||
.form-group
|
|
||||||
= hidden_field_tag 'protected_branch[merge_access_level_attributes][access_level]'
|
|
||||||
= label_tag "Allowed to merge: ", nil, class: "label-light append-bottom-0"
|
|
||||||
= dropdown_tag("<Make a selection>",
|
|
||||||
options: { title: "Allowed to merge", toggle_class: 'allowed-to-merge',
|
|
||||||
dropdown_class: 'dropdown-menu-selectable',
|
|
||||||
data: { field_name: "protected_branch[merge_access_level_attributes][access_level]" }})
|
|
||||||
|
|
||||||
.form-group
|
|
||||||
= hidden_field_tag 'protected_branch[push_access_level_attributes][access_level]'
|
|
||||||
= label_tag "Allowed to push: ", nil, class: "label-light append-bottom-0"
|
|
||||||
= dropdown_tag("<Make a selection>",
|
|
||||||
options: { title: "Allowed to push", toggle_class: 'allowed-to-push',
|
|
||||||
dropdown_class: 'dropdown-menu-selectable',
|
|
||||||
data: { field_name: "protected_branch[push_access_level_attributes][access_level]" }})
|
|
||||||
|
|
||||||
|
|
||||||
= f.submit "Protect", class: "btn-create btn protect-branch-btn", disabled: true
|
|
||||||
|
|
||||||
%hr
|
|
||||||
= render "branches_list"
|
= render "branches_list"
|
||||||
|
|
|
@ -11,7 +11,7 @@ feature 'Projected Branches', feature: true, js: true do
|
||||||
def set_protected_branch_name(branch_name)
|
def set_protected_branch_name(branch_name)
|
||||||
find(".js-protected-branch-select").click
|
find(".js-protected-branch-select").click
|
||||||
find(".dropdown-input-field").set(branch_name)
|
find(".dropdown-input-field").set(branch_name)
|
||||||
click_on "Create Protected Branch: #{branch_name}"
|
click_on("Create wildcard #{branch_name}")
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "explicit protected branches" do
|
describe "explicit protected branches" do
|
||||||
|
@ -90,7 +90,7 @@ feature 'Projected Branches', feature: true, js: true do
|
||||||
visit namespace_project_protected_branches_path(project.namespace, project)
|
visit namespace_project_protected_branches_path(project.namespace, project)
|
||||||
set_protected_branch_name('master')
|
set_protected_branch_name('master')
|
||||||
within('.new_protected_branch') do
|
within('.new_protected_branch') do
|
||||||
find(".allowed-to-push").click
|
find(".js-allowed-to-push").click
|
||||||
within(".dropdown.open .dropdown-menu") { click_on access_type_name }
|
within(".dropdown.open .dropdown-menu") { click_on access_type_name }
|
||||||
end
|
end
|
||||||
click_on "Protect"
|
click_on "Protect"
|
||||||
|
@ -107,8 +107,8 @@ feature 'Projected Branches', feature: true, js: true do
|
||||||
expect(ProtectedBranch.count).to eq(1)
|
expect(ProtectedBranch.count).to eq(1)
|
||||||
|
|
||||||
within(".protected-branches-list") do
|
within(".protected-branches-list") do
|
||||||
find(".allowed-to-push").click
|
find(".js-allowed-to-push").click
|
||||||
within('.dropdown-menu.push') { click_on access_type_name }
|
within('.js-allowed-to-push-container') { click_on access_type_name }
|
||||||
end
|
end
|
||||||
|
|
||||||
wait_for_ajax
|
wait_for_ajax
|
||||||
|
@ -121,7 +121,7 @@ feature 'Projected Branches', feature: true, js: true do
|
||||||
visit namespace_project_protected_branches_path(project.namespace, project)
|
visit namespace_project_protected_branches_path(project.namespace, project)
|
||||||
set_protected_branch_name('master')
|
set_protected_branch_name('master')
|
||||||
within('.new_protected_branch') do
|
within('.new_protected_branch') do
|
||||||
find(".allowed-to-merge").click
|
find(".js-allowed-to-merge").click
|
||||||
within(".dropdown.open .dropdown-menu") { click_on access_type_name }
|
within(".dropdown.open .dropdown-menu") { click_on access_type_name }
|
||||||
end
|
end
|
||||||
click_on "Protect"
|
click_on "Protect"
|
||||||
|
@ -138,8 +138,8 @@ feature 'Projected Branches', feature: true, js: true do
|
||||||
expect(ProtectedBranch.count).to eq(1)
|
expect(ProtectedBranch.count).to eq(1)
|
||||||
|
|
||||||
within(".protected-branches-list") do
|
within(".protected-branches-list") do
|
||||||
find(".allowed-to-merge").click
|
find(".js-allowed-to-merge").click
|
||||||
within('.dropdown-menu.merge') { click_on access_type_name }
|
within('.js-allowed-to-merge-container') { click_on access_type_name }
|
||||||
end
|
end
|
||||||
|
|
||||||
wait_for_ajax
|
wait_for_ajax
|
||||||
|
|
Loading…
Reference in a new issue