Update layout and JS for create protected branch.
Also updates protect branch list
This commit is contained in:
parent
d4f06e4907
commit
1ac953dab4
14 changed files with 259 additions and 215 deletions
0
app/assets/javascripts/allowed_to_merge_select.js.es6
Normal file
0
app/assets/javascripts/allowed_to_merge_select.js.es6
Normal file
|
@ -173,8 +173,7 @@
|
|||
new Search();
|
||||
break;
|
||||
case 'projects:protected_branches:index':
|
||||
new ProtectedBranchesAccessSelect($(".new_protected_branch"), false, true);
|
||||
new ProtectedBranchesAccessSelect($(".protected-branches-list"), true, false);
|
||||
new CreateProtectedBranch();
|
||||
break;
|
||||
}
|
||||
switch (path.first()) {
|
||||
|
|
84
app/assets/javascripts/protect_branch.js.es6
Normal file
84
app/assets/javascripts/protect_branch.js.es6
Normal file
|
@ -0,0 +1,84 @@
|
|||
class ProtectedBranchesAccessDropdown {
|
||||
constructor(options) {
|
||||
const { $dropdown, data, onSelect } = options;
|
||||
|
||||
$dropdown.glDropdown({
|
||||
data: data,
|
||||
selectable: true,
|
||||
fieldName: $dropdown.data('field-name'),
|
||||
toggleLabel(item) {
|
||||
return item.text;
|
||||
},
|
||||
clicked(item, $el, e) {
|
||||
e.preventDefault();
|
||||
onSelect();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class AllowedToMergeDropdowns {
|
||||
constructor (options) {
|
||||
const { $dropdowns, onSelect } = options;
|
||||
|
||||
$dropdowns.each((i, el) => {
|
||||
new ProtectedBranchesAccessDropdown({
|
||||
$dropdown: $(el),
|
||||
data: gon.merge_access_levels,
|
||||
onSelect: onSelect
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class AllowedToPushSelects {
|
||||
constructor (options) {
|
||||
const { $dropdowns, onSelect } = options;
|
||||
|
||||
$dropdowns.each((i, el) => {
|
||||
new ProtectedBranchesAccessDropdown({
|
||||
$dropdown: $(el),
|
||||
data: gon.push_access_levels,
|
||||
onSelect: onSelect
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class CreateProtectedBranch {
|
||||
constructor() {
|
||||
this.$wrap = this.$form = $('#new_protected_branch');
|
||||
this.buildDropdowns();
|
||||
}
|
||||
|
||||
buildDropdowns() {
|
||||
// Allowed to Merge dropdowns
|
||||
new AllowedToMergeDropdowns({
|
||||
$dropdowns: this.$wrap.find('.js-allowed-to-merge'),
|
||||
onSelect: this.onSelect.bind(this)
|
||||
});
|
||||
|
||||
// Allowed to Push dropdowns
|
||||
new AllowedToPushSelects({
|
||||
$dropdowns: this.$wrap.find('.js-allowed-to-push'),
|
||||
onSelect: this.onSelect.bind(this)
|
||||
});
|
||||
|
||||
new ProtectedBranchSelects({
|
||||
$dropdowns: this.$wrap.find('.js-protected-branch-select'),
|
||||
onSelect: this.onSelect.bind(this)
|
||||
});
|
||||
}
|
||||
|
||||
// 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('[type="submit"]').removeAttr('disabled');
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
88
app/assets/javascripts/protected_branch_select.js.es6
Normal file
88
app/assets/javascripts/protected_branch_select.js.es6
Normal file
|
@ -0,0 +1,88 @@
|
|||
class ProtectedBranchSelect {
|
||||
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(protected_branch) {
|
||||
return _.escape(protected_branch.title);
|
||||
},
|
||||
id(protected_branch) {
|
||||
return _.escape(protected_branch.id);
|
||||
},
|
||||
onFilter: this.toggleCreateNewButton.bind(this),
|
||||
clicked: (item, $el, e) => {
|
||||
e.preventDefault();
|
||||
this.onSelect();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bindEvents() {
|
||||
this.$protectedBranch.on('click', this.onClickCreateWildcard.bind(this));
|
||||
}
|
||||
|
||||
onClickCreateWildcard(e) {
|
||||
this.$dropdown.data('glDropdown').remote.execute();
|
||||
this.$dropdown.data('glDropdown').selectRowAtIndex(e, 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')
|
||||
.html(`Create wildcard <code>${branchName}</code>`);
|
||||
}
|
||||
|
||||
this.$dropdownFooter.toggleClass('hidden', !branchName);
|
||||
}
|
||||
}
|
||||
|
||||
class ProtectedBranchSelects {
|
||||
constructor(options) {
|
||||
const { $dropdowns, onSelect } = options;
|
||||
|
||||
$dropdowns.each((i, el) => {
|
||||
new ProtectedBranchSelect({
|
||||
$dropdown: $(el),
|
||||
onSelect: onSelect
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
&.wide {
|
||||
width: 100%;
|
||||
|
||||
+ .dropdown-select {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-menu,
|
||||
|
|
|
@ -656,13 +656,9 @@ pre.light-well {
|
|||
}
|
||||
|
||||
.new_protected_branch {
|
||||
.dropdown {
|
||||
display: inline;
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
label {
|
||||
min-width: 120px;
|
||||
margin-top: 6px;
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -678,6 +674,14 @@ pre.light-well {
|
|||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
&.table-bordered {
|
||||
border-radius: 1px;
|
||||
|
||||
th:not(:last-child), td:not(:last-child) {
|
||||
border-right: solid 1px transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.custom-notifications-form {
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
%h5.prepend-top-0
|
||||
Already Protected (#{@protected_branches.size})
|
||||
- if @protected_branches.empty?
|
||||
.panel.panel-default
|
||||
- if @protected_branches.empty?
|
||||
%p.settings-message.text-center
|
||||
No branches are protected, protect a branch with the form above.
|
||||
- else
|
||||
- else
|
||||
- can_admin_project = can?(current_user, :admin_project, @project)
|
||||
|
||||
%table.table.protected-branches-list
|
||||
%table.table.protected-branches-list.table-bordered
|
||||
%colgroup
|
||||
%col{ width: "20%" }
|
||||
%col{ width: "30%" }
|
||||
|
@ -14,7 +13,7 @@
|
|||
%col{ width: "25%" }
|
||||
%thead
|
||||
%tr
|
||||
%th Branch
|
||||
%th Protected branch (#{@protected_branches.size})
|
||||
%th Last commit
|
||||
%th Allowed to merge
|
||||
%th Allowed to push
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
= form_for [@project.namespace.becomes(Namespace), @project, @protected_branch] do |f|
|
||||
.panel.panel-default
|
||||
.panel-heading
|
||||
%b Protect a branch
|
||||
.panel-body
|
||||
.form-horizontal
|
||||
.form-group
|
||||
%label.col-md-2.text-right
|
||||
Branch:
|
||||
.col-md-10
|
||||
= render partial: "dropdown", locals: { f: f }
|
||||
.help-block
|
||||
Wildcards such as
|
||||
%code *-stable
|
||||
or
|
||||
%code production/*
|
||||
are supported
|
||||
.form-group
|
||||
%label.col-md-2.text-right
|
||||
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]' }})
|
||||
.form-group
|
||||
%label.col-md-2.text-right
|
||||
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]' }})
|
||||
|
||||
.panel-footer
|
||||
= f.submit 'Protect', class: 'btn-create btn', disabled: true
|
|
@ -1,17 +1,14 @@
|
|||
= f.hidden_field(:name)
|
||||
|
||||
= dropdown_tag("Protected Branch",
|
||||
options: { title: "Pick protected branch", toggle_class: 'js-protected-branch-select js-filter-submit',
|
||||
= dropdown_tag('Select branch or create wildcard',
|
||||
options: { toggle_class: 'js-protected-branch-select js-filter-submit wide',
|
||||
filter: true, dropdown_class: "dropdown-menu-selectable", placeholder: "Search protected branches",
|
||||
footer_content: true,
|
||||
data: { show_no: true, show_any: true, show_upcoming: true,
|
||||
selected: params[:protected_branch_name],
|
||||
project_id: @project.try(:id) } }) do
|
||||
|
||||
%ul.dropdown-footer-list.hidden.protected-branch-select-footer-list
|
||||
%ul.dropdown-footer-list
|
||||
%li
|
||||
= link_to '#', title: "New Protected Branch", class: "create-new-protected-branch" do
|
||||
Create new
|
||||
|
||||
:javascript
|
||||
new ProtectedBranchSelect();
|
||||
|
|
|
@ -17,13 +17,13 @@
|
|||
%td
|
||||
= hidden_field_tag "allowed_to_merge_#{protected_branch.id}", protected_branch.merge_access_level.access_level
|
||||
= dropdown_tag(protected_branch.merge_access_level.humanize,
|
||||
options: { title: "Allowed to merge", toggle_class: 'allowed-to-merge', dropdown_class: 'dropdown-menu-selectable merge',
|
||||
options: { toggle_class: 'allowed-to-merge', dropdown_class: 'dropdown-menu-selectable merge',
|
||||
data: { field_name: "allowed_to_merge_#{protected_branch.id}", url: url, id: protected_branch.id, type: "merge_access_level" }})
|
||||
%td
|
||||
= hidden_field_tag "allowed_to_push_#{protected_branch.id}", protected_branch.push_access_level.access_level
|
||||
= dropdown_tag(protected_branch.push_access_level.humanize,
|
||||
options: { title: "Allowed to push", toggle_class: 'allowed-to-push', dropdown_class: 'dropdown-menu-selectable push',
|
||||
options: { toggle_class: 'allowed-to-push', dropdown_class: 'dropdown-menu-selectable push',
|
||||
data: { field_name: "allowed_to_push_#{protected_branch.id}", url: url, id: protected_branch.id, type: "push_access_level" }})
|
||||
- if can_admin_project
|
||||
%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
|
||||
%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
|
||||
%h5.prepend-top-0
|
||||
Protect a branch
|
||||
- if can? current_user, :admin_project, @project
|
||||
= form_for [@project.namespace.becomes(Namespace), @project, @protected_branch] do |f|
|
||||
= form_errors(@protected_branch)
|
||||
= render 'create_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"
|
||||
|
|
|
@ -90,7 +90,7 @@ feature 'Projected Branches', feature: true, js: true do
|
|||
visit namespace_project_protected_branches_path(project.namespace, project)
|
||||
set_protected_branch_name('master')
|
||||
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 }
|
||||
end
|
||||
click_on "Protect"
|
||||
|
@ -107,7 +107,7 @@ feature 'Projected Branches', feature: true, js: true do
|
|||
expect(ProtectedBranch.count).to eq(1)
|
||||
|
||||
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 }
|
||||
end
|
||||
|
||||
|
@ -121,7 +121,7 @@ feature 'Projected Branches', feature: true, js: true do
|
|||
visit namespace_project_protected_branches_path(project.namespace, project)
|
||||
set_protected_branch_name('master')
|
||||
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 }
|
||||
end
|
||||
click_on "Protect"
|
||||
|
@ -138,7 +138,7 @@ feature 'Projected Branches', feature: true, js: true do
|
|||
expect(ProtectedBranch.count).to eq(1)
|
||||
|
||||
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 }
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in a new issue