diff options
Diffstat (limited to 'app/views/protected_branches')
13 files changed, 240 insertions, 0 deletions
diff --git a/app/views/protected_branches/_branches_list.html.haml b/app/views/protected_branches/_branches_list.html.haml new file mode 100644 index 00000000000..82eac348f16 --- /dev/null +++ b/app/views/protected_branches/_branches_list.html.haml @@ -0,0 +1,4 @@ +- can_admin_project = can?(current_user, :admin_project, @project) + += render layout: 'protected_branches/shared/branches_list', locals: { can_admin_project: can_admin_project } do + = render partial: 'protected_branches/protected_branch', collection: @protected_branches diff --git a/app/views/protected_branches/_create_protected_branch.html.haml b/app/views/protected_branches/_create_protected_branch.html.haml new file mode 100644 index 00000000000..22a49ba9c7e --- /dev/null +++ b/app/views/protected_branches/_create_protected_branch.html.haml @@ -0,0 +1,14 @@ +- content_for :merge_access_levels do + .merge_access_levels-container + = dropdown_tag(_('Select'), + options: { toggle_class: 'js-allowed-to-merge wide', + dropdown_class: 'dropdown-menu-selectable capitalize-header', dropdown_qa_selector: 'allowed_to_merge_dropdown_content', dropdown_testid: 'allowed-to-merge-dropdown', + data: { field_name: 'protected_branch[merge_access_levels_attributes][0][access_level]', input_id: 'merge_access_levels_attributes', qa_selector: 'allowed_to_merge_dropdown' }}) +- content_for :push_access_levels do + .push_access_levels-container + = dropdown_tag(_('Select'), + options: { toggle_class: "js-allowed-to-push js-multiselect wide", + dropdown_class: 'dropdown-menu-selectable capitalize-header', dropdown_qa_selector: 'allowed_to_push_dropdown_content' , dropdown_testid: 'allowed-to-push-dropdown', + data: { field_name: 'protected_branch[push_access_levels_attributes][0][access_level]', input_id: 'push_access_levels_attributes', qa_selector: 'allowed_to_push_dropdown' }}) + += render 'protected_branches/shared/create_protected_branch' diff --git a/app/views/protected_branches/_index.html.haml b/app/views/protected_branches/_index.html.haml new file mode 100644 index 00000000000..4beca4845b8 --- /dev/null +++ b/app/views/protected_branches/_index.html.haml @@ -0,0 +1,7 @@ +- content_for :create_protected_branch do + = render 'protected_branches/create_protected_branch' + +- content_for :branches_list do + = render "protected_branches/branches_list" + += render 'protected_branches/shared/index' diff --git a/app/views/protected_branches/_protected_branch.html.haml b/app/views/protected_branches/_protected_branch.html.haml new file mode 100644 index 00000000000..423d7f23eb5 --- /dev/null +++ b/app/views/protected_branches/_protected_branch.html.haml @@ -0,0 +1,2 @@ += render layout: 'protected_branches/shared/protected_branch', locals: { protected_branch: protected_branch } do + = render_if_exists 'protected_branches/update_protected_branch', protected_branch: protected_branch diff --git a/app/views/protected_branches/_update_protected_branch.html.haml b/app/views/protected_branches/_update_protected_branch.html.haml new file mode 100644 index 00000000000..a9290d9e0da --- /dev/null +++ b/app/views/protected_branches/_update_protected_branch.html.haml @@ -0,0 +1 @@ += render 'protected_branches/shared/update_protected_branch', protected_branch: protected_branch diff --git a/app/views/protected_branches/shared/_branches_list.html.haml b/app/views/protected_branches/shared/_branches_list.html.haml new file mode 100644 index 00000000000..d041f9c5b48 --- /dev/null +++ b/app/views/protected_branches/shared/_branches_list.html.haml @@ -0,0 +1,38 @@ +.protected-branches-list.js-protected-branches-list{ data: { testid: 'protected-branches-list' } } + - if @protected_branches.empty? + .card-header.bg-white + = s_("ProtectedBranch|Protected branch (%{protected_branches_count})") % { protected_branches_count: 0 } + %p.settings-message.text-center + = s_("ProtectedBranch|There are currently no protected branches, protect a branch with the form above.") + - else + .flash-container + %table.table.table-bordered + %colgroup + %col{ width: "30%" } + %col{ width: "20%" } + %col{ width: "20%" } + %col{ width: "10%" } + %col{ width: "10%" } + - if can_admin_project + %col + %thead + %tr + %th + = s_("ProtectedBranch|Branch") + %th + = s_("ProtectedBranch|Allowed to merge") + %th + = s_("ProtectedBranch|Allowed to push") + %th + = s_("ProtectedBranch|Allowed to force push") + %span.has-tooltip{ data: { container: 'body' }, title: s_('ProtectedBranch|Allow all users with push access to force push.'), 'aria-hidden': 'true' } + = sprite_icon('question', size: 16, css_class: 'gl-text-gray-500') + + = render_if_exists 'protected_branches/ee/code_owner_approval_table_head' + + - if can_admin_project + %th + %tbody + = yield + + = paginate @protected_branches, theme: 'gitlab' diff --git a/app/views/protected_branches/shared/_create_protected_branch.html.haml b/app/views/protected_branches/shared/_create_protected_branch.html.haml new file mode 100644 index 00000000000..6b4a143df69 --- /dev/null +++ b/app/views/protected_branches/shared/_create_protected_branch.html.haml @@ -0,0 +1,35 @@ += gitlab_ui_form_for [@project, @protected_branch], html: { class: 'new-protected-branch js-new-protected-branch' } do |f| + %input{ type: 'hidden', name: 'update_section', value: 'js-protected-branches-settings' } + = render Pajamas::CardComponent.new(card_options: { class: "gl-mb-5" }) do |c| + - c.header do + = s_("ProtectedBranch|Protect a branch") + - c.body do + = form_errors(@protected_branch) + .form-group.row + = f.label :name, s_('ProtectedBranch|Branch:'), class: 'col-sm-12' + .col-sm-12 + = render partial: "protected_branches/shared/dropdown", locals: { f: f, toggle_classes: 'gl-w-full! gl-form-input-lg' } + .form-text.text-muted + - wildcards_url = help_page_url('user/project/protected_branches', anchor: 'configure-multiple-protected-branches-by-using-a-wildcard') + - wildcards_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: wildcards_url } + = (s_("ProtectedBranch|%{wildcards_link_start}Wildcards%{wildcards_link_end} such as %{code_tag_start}*-stable%{code_tag_end} or %{code_tag_start}production/*%{code_tag_end} are supported.") % { wildcards_link_start: wildcards_link_start, wildcards_link_end: '</a>', code_tag_start: '<code>', code_tag_end: '</code>' }).html_safe + .form-group.row + = f.label :merge_access_levels_attributes, s_("ProtectedBranch|Allowed to merge:"), class: 'col-sm-12' + .col-sm-12 + = yield :merge_access_levels + .form-group.row + = f.label :push_access_levels_attributes, s_("ProtectedBranch|Allowed to push:"), class: 'col-sm-12' + .col-sm-12 + = yield :push_access_levels + .form-group.row + = f.label :allow_force_push, s_("ProtectedBranch|Allowed to force push:"), class: 'col-sm-12' + .col-sm-12 + = render Pajamas::ToggleComponent.new(classes: 'js-force-push-toggle', + label: s_("ProtectedBranch|Allowed to force push"), + label_position: :hidden) do + - force_push_docs_url = help_page_url('topics/git/git_rebase', anchor: 'force-push') + - force_push_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: force_push_docs_url } + = (s_("ProtectedBranch|Allow all users with push access to %{tag_start}force push%{tag_end}.") % { tag_start: force_push_link_start, tag_end: '</a>' }).html_safe + = render_if_exists 'protected_branches/ee/code_owner_approval_form', f: f + - c.footer do + = f.submit s_('ProtectedBranch|Protect'), disabled: true, data: { qa_selector: 'protect_button' }, pajamas_button: true diff --git a/app/views/protected_branches/shared/_dropdown.html.haml b/app/views/protected_branches/shared/_dropdown.html.haml new file mode 100644 index 00000000000..c5dbf8991cd --- /dev/null +++ b/app/views/protected_branches/shared/_dropdown.html.haml @@ -0,0 +1,21 @@ +- toggle_classes = local_assigns.fetch(:toggle_classes, '') + += f.hidden_field(:name) + += dropdown_tag(_('Select branch or create wildcard'), + options: { toggle_class: "js-protected-branch-select js-filter-submit wide monospace #{toggle_classes}", + filter: true, + dropdown_class: "dropdown-menu-selectable git-revision-dropdown", + dropdown_qa_selector: "protected_branch_dropdown_content", + 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), + qa_selector: "protected_branch_dropdown" } }) do + + %ul.dropdown-footer-list + %li + %button{ class: "dropdown-create-new-item-button js-dropdown-create-new-item", title: _("New Protected Branch") } + = _('Create wildcard') + %code diff --git a/app/views/protected_branches/shared/_index.html.haml b/app/views/protected_branches/shared/_index.html.haml new file mode 100644 index 00000000000..c204508d355 --- /dev/null +++ b/app/views/protected_branches/shared/_index.html.haml @@ -0,0 +1,20 @@ +- expanded = expanded_by_default? + +%section.settings.no-animate#js-protected-branches-settings{ class: ('expanded' if expanded), data: { qa_selector: 'protected_branches_settings_content' } } + .settings-header + %h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only + = s_("ProtectedBranch|Protected branches") + = render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do + = expanded ? _('Collapse') : _('Expand') + %p + = s_("ProtectedBranch|Keep stable branches secure and force developers to use merge requests.") + = link_to s_("ProtectedBranch|What are protected branches?"), help_page_path("user/project/protected_branches") + .settings-content + %p + = s_("ProtectedBranch|By default, protected branches restrict who can modify the branch.") + = link_to s_("ProtectedBranch|Learn more."), help_page_path("user/project/protected_branches", anchor: "who-can-modify-a-protected-branch") + + - if can? current_user, :admin_project, @project + = content_for :create_protected_branch + + = content_for :branches_list diff --git a/app/views/protected_branches/shared/_matching_branch.html.haml b/app/views/protected_branches/shared/_matching_branch.html.haml new file mode 100644 index 00000000000..1a2ec38fae9 --- /dev/null +++ b/app/views/protected_branches/shared/_matching_branch.html.haml @@ -0,0 +1,10 @@ +%tr + %td + = link_to matching_branch.name, project_ref_path(@project, matching_branch.name), class: 'ref-name' + + - if @project.root_ref?(matching_branch.name) + = gl_badge_tag s_('ProtectedBranch|default'), { variant: :info }, { class: 'gl-ml-2' } + %td + - commit = @project.commit(matching_branch.name) + = link_to(commit.short_id, project_commit_path(@project, commit.id), class: 'commit-sha') + = time_ago_with_tooltip(commit.committed_date) diff --git a/app/views/protected_branches/shared/_protected_branch.html.haml b/app/views/protected_branches/shared/_protected_branch.html.haml new file mode 100644 index 00000000000..5dea85aaa41 --- /dev/null +++ b/app/views/protected_branches/shared/_protected_branch.html.haml @@ -0,0 +1,23 @@ +- can_admin_project = can?(current_user, :admin_project, @project) + +%tr.js-protected-branch-edit-form{ data: { url: namespace_project_protected_branch_path(@project.namespace, @project, protected_branch), testid: 'protected-branch' } } + %td + %span.ref-name= protected_branch.name + + - if @project.root_ref?(protected_branch.name) + = gl_badge_tag s_('ProtectedBranch|default'), variant: :info + + %div + - if protected_branch.wildcard? + - matching_branches = protected_branch.matching(repository.branch_names) + = link_to pluralize(matching_branches.count, "matching branch"), namespace_project_protected_branch_path(@project.namespace, @project, protected_branch) + - elsif !protected_branch.commit + %span.text-muted Branch was deleted. + + = yield + + = render_if_exists 'protected_branches/ee/code_owner_approval_table', protected_branch: protected_branch + + - if can_admin_project + %td + = link_to s_('ProtectedBranch|Unprotect'), [@project, protected_branch, { update_section: 'js-protected-branches-settings' }], disabled: local_assigns[:disabled], aria: { label: s_('ProtectedBranch|Unprotect branch') }, data: { confirm: s_('ProtectedBranch|Branch will be writable for developers. Are you sure?'), confirm_btn_variant: 'danger' }, method: :delete, class: "btn gl-button btn-danger btn-sm" diff --git a/app/views/protected_branches/shared/_update_protected_branch.html.haml b/app/views/protected_branches/shared/_update_protected_branch.html.haml new file mode 100644 index 00000000000..0244f9e2158 --- /dev/null +++ b/app/views/protected_branches/shared/_update_protected_branch.html.haml @@ -0,0 +1,40 @@ +- merge_access_levels = protected_branch.merge_access_levels.for_role +- push_access_levels = protected_branch.push_access_levels.for_role + +- user_merge_access_levels = protected_branch.merge_access_levels.for_user +- user_push_access_levels = protected_branch.push_access_levels.for_user + +- group_merge_access_levels = protected_branch.merge_access_levels.for_group +- group_push_access_levels = protected_branch.push_access_levels.for_group + +%td.merge_access_levels-container + = hidden_field_tag "allowed_to_merge_#{protected_branch.id}", merge_access_levels.first&.access_level + = dropdown_tag((merge_access_levels.first&.humanize || 'Select') , + options: { toggle_class: 'js-allowed-to-merge', dropdown_class: 'dropdown-menu-selectable js-allowed-to-merge-container capitalize-header', + data: { field_name: "allowed_to_merge_#{protected_branch.id}", preselected_items: access_levels_data(merge_access_levels) }}) + - if user_merge_access_levels.any? + %p.small + = _('The following %{user} can also merge into this branch: %{branch}') % { user: 'user'.pluralize(user_merge_access_levels.size), branch: user_merge_access_levels.map(&:humanize).to_sentence } + + - if group_merge_access_levels.any? + %p.small + = _('Members of %{group} can also merge into this branch: %{branch}') % { group: (group_merge_access_levels.size > 1 ? 'these groups' : 'this group'), branch: group_merge_access_levels.map(&:humanize).to_sentence } + +%td.push_access_levels-container + = hidden_field_tag "allowed_to_push_#{protected_branch.id}", push_access_levels.first&.access_level + = dropdown_tag((push_access_levels.first&.humanize || 'Select') , + options: { toggle_class: "js-allowed-to-push js-multiselect", dropdown_class: 'dropdown-menu-selectable js-allowed-to-push-container capitalize-header', + data: { field_name: "allowed_to_push_#{protected_branch.id}", preselected_items: access_levels_data(push_access_levels) }}) + - if user_push_access_levels.any? + %p.small + = _('The following %{user} can also push to this branch: %{branch}') % { user: 'user'.pluralize(user_push_access_levels.size), branch: user_push_access_levels.map(&:humanize).to_sentence } + + - if group_push_access_levels.any? + %p.small + = _('Members of %{group} can also push to this branch: %{branch}') % { group: (group_push_access_levels.size > 1 ? 'these groups' : 'this group'), branch: group_push_access_levels.map(&:humanize).to_sentence } + +%td + = render Pajamas::ToggleComponent.new(classes: 'js-force-push-toggle', + label: s_("ProtectedBranch|Toggle allowed to force push"), + is_checked: protected_branch.allow_force_push, + label_position: :hidden) diff --git a/app/views/protected_branches/show.html.haml b/app/views/protected_branches/show.html.haml new file mode 100644 index 00000000000..e0bd392ae93 --- /dev/null +++ b/app/views/protected_branches/show.html.haml @@ -0,0 +1,25 @@ +- page_title @protected_ref.name, _("Protected Branches") + +.row.gl-mt-3.gl-mb-3 + .col-lg-3 + %h4.gl-mt-0.ref-name + = @protected_ref.name + + .col-lg-9 + %h5 Matching Branches + - if @matching_refs.present? + .table-responsive + %table.table.protected-branches-list + %colgroup + %col{ width: "30%" } + %col{ width: "30%" } + %thead + %tr + %th Branch + %th Last commit + %tbody + - @matching_refs.each do |matching_branch| + = render partial: "protected_branches/shared/matching_branch", object: matching_branch + - else + %p.settings-message.text-center + Couldn't find any matching branches. |