diff --git a/Gemfile b/Gemfile index 44e9f795c..4114eb8b7 100644 --- a/Gemfile +++ b/Gemfile @@ -89,11 +89,13 @@ gem 'therubyracer', '~> 0.12.1', platforms: [:mri, :rbx] gem 'therubyrhino', '~> 1.73.1', platforms: :jruby gem 'bootstrap-sass', '~> 3.1.1' -gem 'font-awesome-rails' +gem 'font-awesome-rails', '~> 4.1' gem 'codemirror-rails' gem 'sitemap_generator' +gem 'zeroclipboard-rails' + group :production do gem "airbrake", '~> 3.1.2' gem 'bluepill', '~> 0.0.60', require: false diff --git a/Gemfile.lock b/Gemfile.lock index 4ab8c8218..df0485453 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -168,7 +168,7 @@ GEM faraday (0.9.0) multipart-post (>= 1.2, < 3) ffi (1.9.3) - font-awesome-rails (4.0.3.1) + font-awesome-rails (4.1.0.0) railties (>= 3.2, < 5.0) formtastic (2.3.0.rc2) actionpack (>= 3.0) @@ -513,6 +513,8 @@ GEM will_paginate (3.0.5) ya2yaml (0.31) yajl-ruby (1.1.0) + zeroclipboard-rails (0.1.0) + railties (>= 3.1) PLATFORMS ruby @@ -544,7 +546,7 @@ DEPENDENCIES diff-display (~> 0.0.1) factory_girl_rails (~> 4.4.1) ffi (~> 1.9.3) - font-awesome-rails + font-awesome-rails (~> 4.1) friendly_id (~> 5.0.3) gemoji (~> 1.2.1) github-linguist (~> 2.10) @@ -616,3 +618,4 @@ DEPENDENCIES whenever (~> 0.9.0) wikicloth will_paginate (~> 3.0.5) + zeroclipboard-rails diff --git a/app/assets/javascripts/angular-new/controllers/project_repo_block_controller.js b/app/assets/javascripts/angular-new/controllers/project_repo_block_controller.js new file mode 100644 index 000000000..506ec6745 --- /dev/null +++ b/app/assets/javascripts/angular-new/controllers/project_repo_block_controller.js @@ -0,0 +1,20 @@ +RosaABF.controller('ProjectRepoBlockController', ['$scope', 'ApiProject', function($scope, ApiProject) { + + $scope.clone_url = null; + $scope.singleton = ApiProject.singleton; + $scope.clone_url_protocol = 'ssh'; + $scope.is_collapsed_git_help = true; + + $scope.init = function(clone_url, branches) { + $scope.clone_url = clone_url; + $scope.singleton.project.branches_count = branches; + } + + // TODO refactoring + $scope.select_branch = function() { + $form = $('form#branch_changer'); + $form.attr('action', $scope.branch); + $form.submit(); + }; + +}]); \ No newline at end of file diff --git a/app/assets/javascripts/angularjs/services/collaborator.js b/app/assets/javascripts/angular-new/services/collaborator.js similarity index 100% rename from app/assets/javascripts/angularjs/services/collaborator.js rename to app/assets/javascripts/angular-new/services/collaborator.js diff --git a/app/assets/javascripts/angularjs/services/project.js b/app/assets/javascripts/angular-new/services/project.js similarity index 100% rename from app/assets/javascripts/angularjs/services/project.js rename to app/assets/javascripts/angular-new/services/project.js diff --git a/app/assets/javascripts/angularjs/services/pull_request.js b/app/assets/javascripts/angular-new/services/pull_request.js similarity index 100% rename from app/assets/javascripts/angularjs/services/pull_request.js rename to app/assets/javascripts/angular-new/services/pull_request.js diff --git a/app/assets/javascripts/angularjs/controllers/build_lists_controller.js.erb b/app/assets/javascripts/angularjs/controllers/build_lists_controller.js.erb deleted file mode 100644 index 3a69e8e02..000000000 --- a/app/assets/javascripts/angularjs/controllers/build_lists_controller.js.erb +++ /dev/null @@ -1,161 +0,0 @@ -RosaABF.controller('BuildListsController', ['$scope', '$http', '$location', '$timeout', function($scope, $http, $location, $timeout) { - - $scope.params = null; - $scope.first_run = true; - $scope.server_status = null; - $scope.build_lists = []; - $scope.isRequest = false; // Disable 'Search' button - $scope.pages = []; - - $scope.opened = {}; - $scope.map_priorities = { - <%=BuildList::WAITING_FOR_RESPONSE%>: 13, - <%=BuildList::BUILD_PENDING%>: 12, - <%=BuildList::RERUN_TESTS%>: 11, - <%=BuildList::BUILD_CANCELING%>: 10, - <%=BuildList::BUILD_CANCELED%>: 9, - <%=BuildList::BUILD_STARTED%>: 8, - <%=BuildList::RERUNNING_TESTS%>: 7, - <%=BuildList::BUILD_PUBLISH%>: 6, - <%=BuildList::BUILD_PUBLISHED%>: 5, - <%=BuildList::BUILD_ERROR%>: 4, - <%=BuildList::SUCCESS%>: 3, - <%=BuildList::TESTS_FAILED%>: 2, - <%=BuildList::FAILED_PUBLISH%>: 1, - <%=BuildList::REJECTED_PUBLISH%>: 0 - }; - - - // Fixes: redirect to page after form submit - $("#monitoring_filter").on('submit', function(){ return false; }); - - $scope.getBuildLists = function() { - // Disable 'Search' button - $scope.isRequest = true; - - - $http.get(Routes.build_lists_path({format: 'json'}), {params: $location.search()}).success(function(results) { - // Render Server status - $scope.server_status = results.server_status; - - // TMP fields - var dictionary = results.dictionary; - var build_lists = []; - var groups = {}; - - var to_open = []; - // Grouping of build_lists - _.each(results.build_lists, function(r){ - var bl = new BuildList(r, dictionary); - var key = bl.project_id + '-'; - key += bl.group_id ? bl.group_id : (bl.commit_hash + '-' + bl.user_id); - if (groups[key]) { - groups[key].addRelated(bl); - } else { - groups[key] = bl; - build_lists.push(bl); - if ( bl.id in $scope.opened ) { to_open.push(bl); } - } - }); - - // Adds all build_lists into the table (group by group) - $scope.build_lists = []; - $scope.opened = {}; - _.each(build_lists, function(bl){ - if (bl.related.length > 1) { - var sorted_build_lists = _.sortBy(bl.related, function(b) { return $scope.map_priorities[b.status]; }); - bl.clearRelated(); - var first_in_group = sorted_build_lists[0]; - first_in_group.clearRelated(); - _.each(sorted_build_lists, function(b){ - if (b != first_in_group) { first_in_group.addRelated(b); } - $scope.build_lists.push(b); - }); - } else { - $scope.build_lists.push(bl); - } - }); - // Shows groups which have been opened before - _.each(to_open, function(bl){ $scope.showRelated(bl, true); }); - - // Render pagination - $scope.pages = results.pages; - // Enable 'Search' button - $scope.isRequest = false; - }).error(function(data, status, headers, config) { - // Enable 'Search' button - $scope.isRequest = false; - });; - } - - $scope.showRelated = function(build_list, disable_effect) { - build_list.relatedHidden = false; - _.each(build_list.related, function(bl){ - bl.show = true; - $scope.opened[bl.id] = true; - // Waits for render of build_lists - if (!disable_effect) - $timeout(function() { - $('#build-list-' + bl.id + ' td:visible').effect('highlight', {}, 1000); - }, 100); - }); - } - - $scope.hideRelated = function(build_list) { - build_list.relatedHidden = true; - _.each(build_list.related, function(bl){ - bl.show = false; - delete $scope.opened[bl.id]; - }); - build_list.show = true; - } - - $scope.cancelRefresh = null; - $scope.refresh = function(force) { - if ($('#autoreload').is(':checked') || force) { - var params = {}; - _.each($("#monitoring_filter").serializeArray(), function(a){ - if (a.value) { params[a.name] = a.value; } - }); - $location.search(params); - $scope.first_run = false; - $scope.getBuildLists(); - } - if (!force) - $scope.cancelRefresh = $timeout($scope.refresh, 60000); - } - - - $scope.$on('$locationChangeSuccess', function(event) { - $scope.updateParams(); - if (!$scope.first_run) { $scope.getBuildLists(); } - }); - - $scope.updateParams = function() { - var params = $location.search(); - $scope.params = { - page: params.page || 1, - per_page: params.per_page || 25, - filter: { - ownership: params['filter[ownership]'] || 'owned', - status: params['filter[status]'], - platform_id: params['filter[platform_id]'], - arch_id: params['filter[arch_id]'], - mass_build_id: params['filter[mass_build_id]'], - updated_at_start: params['filter[updated_at_start]'], - updated_at_end: params['filter[updated_at_end]'], - project_name: params['filter[project_name]'], - id: params['filter[id]'] - } - } - } - - $scope.goToPage = function(number) { - $location.search('page', number); - $scope.getBuildLists(); - } - - $scope.updateParams(); - // Waits for render of filters - $timeout($scope.refresh, 100); -}]); diff --git a/app/assets/javascripts/angularjs/controllers/project_repo_block_controller.js b/app/assets/javascripts/angularjs/controllers/project_repo_block_controller.js deleted file mode 100644 index 731fc754e..000000000 --- a/app/assets/javascripts/angularjs/controllers/project_repo_block_controller.js +++ /dev/null @@ -1,9 +0,0 @@ -RosaABF.controller('ProjectRepoBlockController', ['$scope', 'ApiProject', function($scope, ApiProject) { - - $scope.singleton = ApiProject.singleton; - - $scope.init = function(branches) { - $scope.singleton.project.branches_count = branches; - } - -}]); \ No newline at end of file diff --git a/app/assets/javascripts/new_application.js b/app/assets/javascripts/new_application.js index ff77ac268..b3e6eeda2 100644 --- a/app/assets/javascripts/new_application.js +++ b/app/assets/javascripts/new_application.js @@ -29,6 +29,8 @@ //= require underscore +//= require zeroclipboard + //= require_self function setCookie (name, value, expires, path, domain, secure) { @@ -46,4 +48,6 @@ $(document).ready(function() { var expires="expires="+exdate.toUTCString(); setCookie("flash_notify_hash", FLASH_HASH_ID, expires); }); + + var clip = new ZeroClipboard($("#clipboard_copy_button")); }); diff --git a/app/assets/stylesheets/custom_bootstrap.scss b/app/assets/stylesheets/custom_bootstrap.scss index 898fa3afc..41fc85e63 100644 --- a/app/assets/stylesheets/custom_bootstrap.scss +++ b/app/assets/stylesheets/custom_bootstrap.scss @@ -38,7 +38,7 @@ $mini-avatar-height: 30px; } .nav a, .pagination a, .carousel a, .panel-title a, i.fa-question-circle[data-toggle='modal'], -span.fa.fa-times { +span.fa.fa-times, .navbar a { cursor: pointer; } @@ -147,6 +147,28 @@ table.table-borderless > thead > tr > th { margin-bottom: 0; } -ul.nav.navbar-nav.left-border { +#submenu-navbar-collapse ul.left-border { border-left: 1px solid #dcdcdc; } + +#repo-block-navbar-collapse { + padding-left: 0; +} + +form#clone_url { + padding-left: 0px; + padding-right: 1px; +} + +#copy_to_clipboard.navbar-text.navbar-left { + margin-left: 8px; +} + +#git-help.navbar-text.navbar-left { + margin-left: 8px; + margin-right: 8px; +} + +p.navbar-text.navbar-right.current_branch { + margin-right: 0; +} \ No newline at end of file diff --git a/app/assets/stylesheets/new_application.css.scss b/app/assets/stylesheets/new_application.css.scss index 9266f9fbe..459234383 100644 --- a/app/assets/stylesheets/new_application.css.scss +++ b/app/assets/stylesheets/new_application.css.scss @@ -1,5 +1,5 @@ //$body-bg: #1F60A1; -$navbar-height: 38px; +$navbar-height: 37px; $navbar-border-radius: 0px; $top-menu-height: 52px; diff --git a/app/controllers/projects/git/trees_controller.rb b/app/controllers/projects/git/trees_controller.rb index eb68dccbb..53a73f204 100644 --- a/app/controllers/projects/git/trees_controller.rb +++ b/app/controllers/projects/git/trees_controller.rb @@ -1,4 +1,6 @@ class Projects::Git::TreesController < Projects::Git::BaseController + layout 'bootstrap', only: [:show] + before_filter -> {redirect_to @project if params[:treeish] == @project.default_branch and params[:path].blank?}, only: :show skip_before_filter :set_branch_and_tree, :set_treeish_and_path, only: :archive before_filter -> { raise Grit::NoSuchPathError if params[:treeish] != @branch.try(:name) }, only: [:branch, :destroy] @@ -17,7 +19,7 @@ class Projects::Git::TreesController < Projects::Git::BaseController def archive format, @treeish = params[:format], params[:treeish] - raise Grit::NoSuchPathError unless @treeish =~ /^#{@project.name}-/ && + raise Grit::NoSuchPathError unless @treeish =~ /^#{@project.name}-/ && @treeish !~ /[\s]+/ && format =~ /^(zip|tar\.gz)$/ @treeish.gsub!(/^#{@project.name}-/, '') diff --git a/app/views/projects/base/_branch_select.html.haml b/app/views/projects/base/_branch_select.html.haml index 4bee2ccee..7562cf111 100644 --- a/app/views/projects/base/_branch_select.html.haml +++ b/app/views/projects/base/_branch_select.html.haml @@ -1,15 +1,6 @@ -.lineForm.fork - = select_tag :branch, branch_selector_options(project), id: 'branch_selector', class: 'sel80' - %form{action: '', method: :get, id: 'branch_changer', :'data-action' => "#{controller_name}"} -.fork - %p #{t('layout.projects.current_branch')}: -.both - -:javascript - $(document).ready(function() { - $('select#branch_selector').on('change', function(e) { - $form = $('form#branch_changer'); - $form.attr('action', $(this).val()); - $form.submit(); - }); - }); \ No newline at end of file +%form.navbar-form.navbar-right + .form-group + = select_tag :branch, branch_selector_options(project), id: 'branch_selector', + class: 'form-control', 'ng-change' => 'select_branch()', 'ng-model' => 'branch' +%form{action: '', method: :get, id: 'branch_changer', 'data-action' => "#{controller_name}"} +%p.navbar-text.navbar-right.current_branch #{t('layout.projects.current_branch')}: diff --git a/app/views/projects/base/_layout.html.haml b/app/views/projects/base/_layout.html.haml index a91d2374a..fc6545ef7 100644 --- a/app/views/projects/base/_layout.html.haml +++ b/app/views/projects/base/_layout.html.haml @@ -1,5 +1,6 @@ = render 'submenu' = render 'repo_block', project: @project + = render 'about_block', project: @project %h3= t("layout.projects.last_commit") diff --git a/app/views/projects/base/_repo_block.html.haml b/app/views/projects/base/_repo_block.html.haml index df1cdca7b..d822b6e0f 100644 --- a/app/views/projects/base/_repo_block.html.haml +++ b/app/views/projects/base/_repo_block.html.haml @@ -1,54 +1,120 @@ - act = action_name.to_sym; contr = controller_name.to_sym; treeish = project.default_head(params[:treeish]); branch = @branch.try(:name) || project.default_head -http_url = git_repo_url(project.name_with_owner) -ssh_url = git_ssh_repo_url(project.name_with_owner) -#description-top{'ng-controller' => 'ProjectRepoBlockController', 'ng-init' => "init(#{project.repo.branches.count})"} - -if @commit - %ul.nav.zip - %li#menu-archive.dropdown - %a.dropdown-toggle{"data-toggle" => "dropdown", href: "#menu-archive"} - =image_tag 'zip.png', alt: 'ZIP' - %b.caret - %ul.dropdown-menu - - file_name = "#{@project.name}-#{treeish}" - %li=link_to "tar.gz", archive_path(project, file_name, 'tar.gz') - %li=link_to "zip", archive_path(project, file_name, 'zip') - .btn-group#clone-urls - %button.git-protocol-selector.btn{value: 'http_url', class: current_user ? '' : 'active'} HTTP - %button.git-protocol-selector.btn{value: 'ssh_url', class: current_user ? 'active' : ''} SSH - =hidden_field_tag :http_url, http_url - =hidden_field_tag :ssh_url, ssh_url - = text_field_tag :url, (current_user ? ssh_url : http_url), class: 'name', spellcheck: 'false', readonly: true - .git_help ? - .role= can?(:write, project) ? t("layout.read_write_access") : t("layout.read_access") - = render 'branch_select', project: project if act != :tags + +%nav.navbar.navbar-default{ role: 'navigation', 'ng-controller' => 'ProjectRepoBlockController', + 'ng-init' => "init('#{ssh_url}', #{project.repo.branches.count})", + 'ng-cloak' => true } + .container-fluid + / Brand and toggle get grouped for better mobile display + .navbar-header + %button.navbar-toggle{ 'data-target' => '#repo-block-navbar-collapse', 'data-toggle' => 'collapse', type: 'button' } + %span.sr-only Toggle navigation + %span.icon-bar + %span.icon-bar + %span.icon-bar + / Collect the nav links, forms, and other content for toggling + #repo-block-navbar-collapse.collapse.navbar-collapse + %ul.nav.navbar-nav + %li.dropdown + %a.dropdown-toggle{ href: '#', 'data-toggle' => 'dropdown' } + = fa_icon 'file-archive-o', class: 'fa-lg' + %span.caret + %ul.dropdown-menu{ role: 'menu' } + - file_name = "#{@project.name}-#{treeish}" + %li= link_to 'tar.gz', archive_path(project, file_name, 'tar.gz') + %li= link_to 'zip', archive_path(project, file_name, 'zip') + .navbar-left + %button.btn.navbar-btn.btn-default{ type: 'button', 'ng-click' => "clone_url = '#{http_url}'", + 'ng-model' => "clone_url_protocol", 'btn-radio' => "'http'", + 'ng-class' => '{"btn-info": clone_url_protocol == "http"}' } HTTP + %button.btn.navbar-btn.btn-default{ type: 'button', 'ng-click' => "clone_url = '#{ssh_url}'", + 'ng-model' => "clone_url_protocol", 'btn-radio' => "'ssh'", + 'ng-class' => '{"btn-info": clone_url_protocol == "ssh"}'} SSH + #git-help.navbar-text.navbar-left + %a.navbar-link{ 'ng-click' => 'is_collapsed_git_help = !is_collapsed_git_help' } + = fa_icon 'question', class: 'fa-lg' + + %form#clone_url.navbar-form.navbar-left + .form-group + %input#clone-url.form-control{ readonly: 'readonly', spellcheck: false, + type: 'text', 'ng-model' => 'clone_url' } + #copy_to_clipboard.navbar-text.navbar-left + %a.navbar-link + %i.fa.fa-clipboard.fa-lg + + .navbar-text.navbar-left + = can?(:write, project) ? t("layout.read_write_access") : t("layout.read_access") + + = render 'branch_select', project: project if act != :tags + + %div{ collapse: "is_collapsed_git_help" } + .container + %p= t("layout.projects.git_help.cloning") + ":" + %p + - if current_user + %p{ 'ng-hide' => 'clone_url_protocol == "ssh"' }~ "git clone #{http_url} #{project.name}" + %p{ 'ng-hide' => 'clone_url_protocol == "http"' }~ "git clone #{ssh_url} #{project.name}" + %p~ "cd #{project.name}" + %p + %p= t("layout.projects.git_help.remote") + ":" + %p + - if current_user + %p{ 'ng-hide' => 'clone_url_protocol == "ssh"' }~ "git remote add #{project.name} #{http_url}" + %p{ 'ng-hide' => 'clone_url_protocol == "http"' }~ "git remote add #{project.name} #{ssh_url}" + %p~ "git fetch #{project.name}" + %p~ "git checkout -b my-local-tracking-branch #{project.name}/master_or_other_branch" + + +-# + .well#description-top{'ng-controller' => 'ProjectRepoBlockController', 'ng-init' => "init(#{project.repo.branches.count})"} + -if @commit + %ul.nav.zip + %li#menu-archive.dropdown + %a.dropdown-toggle{"data-toggle" => "dropdown", href: "#menu-archive"} + =image_tag 'zip.png', alt: 'ZIP' + %b.caret + %ul.dropdown-menu + - file_name = "#{@project.name}-#{treeish}" + %li=link_to "tar.gz", archive_path(project, file_name, 'tar.gz') + %li=link_to "zip", archive_path(project, file_name, 'zip') + .btn-group#clone-urls + %button.git-protocol-selector.btn{value: 'http_url', class: current_user ? '' : 'active'} HTTP + %button.git-protocol-selector.btn{value: 'ssh_url', class: current_user ? 'active' : ''} SSH + =hidden_field_tag :http_url, http_url + =hidden_field_tag :ssh_url, ssh_url + = text_field_tag :url, (current_user ? ssh_url : http_url), class: 'name', spellcheck: 'false', readonly: true + .git_help ? + .role= can?(:write, project) ? t("layout.read_write_access") : t("layout.read_access") + = render 'branch_select', project: project if act != :tags + .both + #git_help_data + %p= t("layout.projects.git_help.cloning") + ":" + %p + %p.http_url{class: current_user ? 'hidden' : ''}~ "git clone #{http_url} #{project.name}" + %p.ssh_url{class: current_user ? '' : 'hidden'}~ "git clone #{ssh_url} #{project.name}" + %p~ "cd #{project.name}" + %p + %p= t("layout.projects.git_help.remote") + ":" + %p + %p.http_url{class: current_user ? 'hidden' : ''}~ "git remote add #{project.name} #{http_url}" + %p.ssh_url{class: current_user ? '' : 'hidden'}~ "git remote add #{project.name} #{ssh_url}" + %p~ "git fetch #{project.name}" + %p~ "git checkout -b my-local-tracking-branch #{project.name}/master_or_other_branch" + .project-tabnav + %ul.tabnav-tabs + %li{class: ('selected' if act == :show && contr == :trees )} + = link_to t('project_menu.files'), tree_path(project, treeish) + %li{class: ('selected' if act == :index && contr == :commits )} + = link_to t('project_menu.commits'), commits_path(project, treeish) + %li{class: ('selected' if act == :branches && contr == :trees )} + = link_to t('project_menu.branches', count: '{{singleton.project.branches_count}}'), branch_path(project, branch) + %li.tags{class: ('selected' if act == :tags && contr == :trees )} + = link_to t('project_menu.tags', count: project.repo.tags.count), tags_path(project) .both - #git_help_data - %p= t("layout.projects.git_help.cloning") + ":" - %p - %p.http_url{class: current_user ? 'hidden' : ''}~ "git clone #{http_url} #{project.name}" - %p.ssh_url{class: current_user ? '' : 'hidden'}~ "git clone #{ssh_url} #{project.name}" - %p~ "cd #{project.name}" - %p - %p= t("layout.projects.git_help.remote") + ":" - %p - %p.http_url{class: current_user ? 'hidden' : ''}~ "git remote add #{project.name} #{http_url}" - %p.ssh_url{class: current_user ? '' : 'hidden'}~ "git remote add #{project.name} #{ssh_url}" - %p~ "git fetch #{project.name}" - %p~ "git checkout -b my-local-tracking-branch #{project.name}/master_or_other_branch" - .project-tabnav - %ul.tabnav-tabs - %li{class: ('selected' if act == :show && contr == :trees )} - = link_to t('project_menu.files'), tree_path(project, treeish) - %li{class: ('selected' if act == :index && contr == :commits )} - = link_to t('project_menu.commits'), commits_path(project, treeish) - %li{class: ('selected' if act == :branches && contr == :trees )} - = link_to t('project_menu.branches', count: '{{singleton.project.branches_count}}'), branch_path(project, branch) - %li.tags{class: ('selected' if act == :tags && contr == :trees )} - = link_to t('project_menu.tags', count: project.repo.tags.count), tags_path(project) -.both -:javascript - $(document).ready(function() { - $('#url').on('click', function() { - $(this).select(); + :javascript + $(document).ready(function() { + $('#url').on('click', function() { + $(this).select(); + }); }); - }); diff --git a/app/views/projects/base/_submenu.html.haml b/app/views/projects/base/_submenu.html.haml index 1d3372203..ec2a2659e 100644 --- a/app/views/projects/base/_submenu.html.haml +++ b/app/views/projects/base/_submenu.html.haml @@ -9,12 +9,19 @@ %span.icon-bar %span.icon-bar %span.icon-bar - = link_to project_path(@project), class: 'navbar-brand' do + .navbar-brand = fa_visibility_icon @project - = @project.name_with_owner + = link_to @project.owner.uname, @project.owner + \/ + = link_to @project.name, project_path(@project) / Collect the nav links, forms, and other content for toggling #submenu-navbar-collapse.collapse.navbar-collapse %ul.nav.navbar-nav.left-border + - if @project.parent + %li + = link_to project_path(@project.parent), class: 'small' do + = fa_icon 'code-fork' + = @project.parent.name_with_owner %li{ class: ('active' if act.in?([:show, :edit, :branches, :tags]) && contr.in?([:trees, :blobs]) || contr == :commits) } = link_to t('project_menu.code'), tree_path(@project, treeish) - if @project.is_package and can?(:read, @project => BuildList)