diff --git a/app/assets/stylesheets/design/custom.scss b/app/assets/stylesheets/design/custom.scss
index edc2c37f2..75db3e66f 100644
--- a/app/assets/stylesheets/design/custom.scss
+++ b/app/assets/stylesheets/design/custom.scss
@@ -921,3 +921,7 @@ div#git_help_data p {
.dropdown.open .dropdown-toggle {
background: none repeat scroll 0 0;
}
+
+.font14 {
+ font-size: 14px;
+}
diff --git a/app/controllers/pull_requests_controller.rb b/app/controllers/pull_requests_controller.rb
new file mode 100644
index 000000000..18f0e0e9f
--- /dev/null
+++ b/app/controllers/pull_requests_controller.rb
@@ -0,0 +1,21 @@
+# -*- encoding : utf-8 -*-
+class PullRequestsController < ApplicationController
+ before_filter :authenticate_user!
+ load_resource :project
+ load_and_authorize_resource :pull_request, :through => :project, :find_by => :serial_id
+
+ def index(status = 200)
+ end
+
+ def new
+ @base = @project.default_branch
+ @head = params[:treeish].presence || @project.default_branch
+ end
+
+ def create
+ end
+
+ def update
+ end
+
+end
diff --git a/app/views/projects/_submenu.html.haml b/app/views/projects/_submenu.html.haml
index 0f7e536b3..7ff21a0f0 100644
--- a/app/views/projects/_submenu.html.haml
+++ b/app/views/projects/_submenu.html.haml
@@ -16,3 +16,4 @@
%li= link_to t("project_menu.readme"), "#" #pending
- if can? :update, @project
%li= link_to t("project_menu.settings"), edit_project_path(@project), :class => (act == :edit && contr == :projects ? 'active' : nil)
+ %li= link_to t("project_menu.pull_requests"), project_pull_requests_path(@project), :class => (contr == :pull_requests ? 'active' : nil)
diff --git a/app/views/pull_requests/index.html.haml b/app/views/pull_requests/index.html.haml
new file mode 100644
index 000000000..10bd17193
--- /dev/null
+++ b/app/views/pull_requests/index.html.haml
@@ -0,0 +1,20 @@
+-set_meta_tags :title => [title_object(@project), t('.title')]
+= render :partial => 'projects/submenu'
+-#render :partial => 'pull_requests/index_sidebar'
+%ul.nav.nav-tabs
+ %li
+ %a{"data-toggle" => "tab", :href => "#show"} Home
+ %li
+ %a{"data-toggle" => "tab", :href => "#diff"} Profile
+ %li
+ %a{"data-toggle" => "tab", :href => "#commits"} Messages
+
+.tab-content
+ #show.tab-pane.active ...
+ #diff.tab-pane ...
+ #commits.tab-pane ...
+/
+ :javascript
+ $(function () {
+ $('.tabs a:last').tab('show')
+ })
diff --git a/app/views/pull_requests/new.html.haml b/app/views/pull_requests/new.html.haml
new file mode 100644
index 000000000..532c5a7fe
--- /dev/null
+++ b/app/views/pull_requests/new.html.haml
@@ -0,0 +1,16 @@
+-set_meta_tags :title => [title_object(@project), t('.title')]
+= render :partial => 'projects/submenu'
+
+=form_for @project.pull_requests.new, :url => project_pull_requests_path do |f|
+ .row-fluid
+ .span12
+ %h3=raw t '.new', {:base => @base, :head => @head}
+ .row-fluid
+ .span6
+ .span
+ %h3 #{t '.base'} #{t '.refs'}:
+ =text_field_tag :base_ref, @base
+ .span6
+ .span
+ %h3 #{t '.head'} #{t '.refs'}:
+ =text_field_tag :head_ref, @head
diff --git a/config/locales/menu.en.yml b/config/locales/menu.en.yml
index f3bae9b88..ff5cbe8f2 100644
--- a/config/locales/menu.en.yml
+++ b/config/locales/menu.en.yml
@@ -24,6 +24,7 @@ en:
wiki: Wiki
readme: Readme
settings: Settings
+ pull_requests: Pull Requests
feed_menu:
all: All
code: Code
@@ -37,4 +38,4 @@ en:
users: Users
register_requests: Invites
event_logs: Event log
-
+
diff --git a/config/locales/menu.ru.yml b/config/locales/menu.ru.yml
index 209b30527..95e068ddd 100644
--- a/config/locales/menu.ru.yml
+++ b/config/locales/menu.ru.yml
@@ -24,6 +24,7 @@ ru:
wiki: Wiki
readme: Readme
settings: Настройки
+ pull_requests: Запросы на слияние
feed_menu:
all: Все
code: Код
diff --git a/config/locales/models/pull_request.en.yml b/config/locales/models/pull_request.en.yml
new file mode 100644
index 000000000..13a98fc00
--- /dev/null
+++ b/config/locales/models/pull_request.en.yml
@@ -0,0 +1,7 @@
+en:
+ pull_requests:
+ new:
+ new: 'Create a pull request into %{base} from %{head}'
+ base: 'Base'
+ head: 'Head'
+ refs: 'branch · tag · commit'
diff --git a/config/locales/models/pull_request.ru.yml b/config/locales/models/pull_request.ru.yml
new file mode 100644
index 000000000..87a586b21
--- /dev/null
+++ b/config/locales/models/pull_request.ru.yml
@@ -0,0 +1,7 @@
+ru:
+ pull_requests:
+ new:
+ new: 'Создать запрос на слияние в %{base} из %{head}'
+ base: 'База'
+ head: 'Источник'
+ refs: 'ветка · тег · коммит'
diff --git a/config/locales/title.en.yml b/config/locales/title.en.yml
index 85ab39254..198c74254 100644
--- a/config/locales/title.en.yml
+++ b/config/locales/title.en.yml
@@ -22,4 +22,9 @@ en:
compare:
title: 'Compare Revisions'
searching:
- title: 'Search in Wiki'
\ No newline at end of file
+ title: 'Search in Wiki'
+ pull_requests:
+ index:
+ title: 'Pull Requests'
+ new:
+ title: 'Create a Pull Request'
diff --git a/config/locales/title.ru.yml b/config/locales/title.ru.yml
index af631bc9a..6f5793063 100644
--- a/config/locales/title.ru.yml
+++ b/config/locales/title.ru.yml
@@ -23,3 +23,8 @@ ru:
title: 'Сравнение версий'
searching:
title: 'Поиск в вики'
+ pull_requests:
+ index:
+ title: 'Запросы на слияние'
+ new:
+ title: 'Создать запрос на слияние'
diff --git a/config/routes.rb b/config/routes.rb
index 1ede68a47..3dbd25809 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -107,6 +107,11 @@ Rosa::Application.routes.draw do
get :search_collaborators
end
end
+
+ resources :pull_requests, :except => :destroy do
+ #get :autocomplete_refs, :on => :collection
+ end
+
post "labels/:label_id" => "issues#destroy_label", :as => :issues_delete_label
post "labels/:label_id/update" => "issues#update_label", :as => :issues_update_label
resources :build_lists, :only => [:index, :new, :create] do
diff --git a/vendor/assets/javascripts/bootstrap-tab.js b/vendor/assets/javascripts/bootstrap-tab.js
new file mode 100644
index 000000000..b3938f671
--- /dev/null
+++ b/vendor/assets/javascripts/bootstrap-tab.js
@@ -0,0 +1,130 @@
+/* ========================================================
+ * bootstrap-tab.js v2.0.2
+ * http://twitter.github.com/bootstrap/javascript.html#tabs
+ * ========================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ======================================================== */
+
+
+!function( $ ){
+
+ "use strict"
+
+ /* TAB CLASS DEFINITION
+ * ==================== */
+
+ var Tab = function ( element ) {
+ this.element = $(element)
+ }
+
+ Tab.prototype = {
+
+ constructor: Tab
+
+ , show: function () {
+ var $this = this.element
+ , $ul = $this.closest('ul:not(.dropdown-menu)')
+ , selector = $this.attr('data-target')
+ , previous
+ , $target
+
+ if (!selector) {
+ selector = $this.attr('href')
+ selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
+ }
+
+ if ( $this.parent('li').hasClass('active') ) return
+
+ previous = $ul.find('.active a').last()[0]
+
+ $this.trigger({
+ type: 'show'
+ , relatedTarget: previous
+ })
+
+ $target = $(selector)
+
+ this.activate($this.parent('li'), $ul)
+ this.activate($target, $target.parent(), function () {
+ $this.trigger({
+ type: 'shown'
+ , relatedTarget: previous
+ })
+ })
+ }
+
+ , activate: function ( element, container, callback) {
+ var $active = container.find('> .active')
+ , transition = callback
+ && $.support.transition
+ && $active.hasClass('fade')
+
+ function next() {
+ $active
+ .removeClass('active')
+ .find('> .dropdown-menu > .active')
+ .removeClass('active')
+
+ element.addClass('active')
+
+ if (transition) {
+ element[0].offsetWidth // reflow for transition
+ element.addClass('in')
+ } else {
+ element.removeClass('fade')
+ }
+
+ if ( element.parent('.dropdown-menu') ) {
+ element.closest('li.dropdown').addClass('active')
+ }
+
+ callback && callback()
+ }
+
+ transition ?
+ $active.one($.support.transition.end, next) :
+ next()
+
+ $active.removeClass('in')
+ }
+ }
+
+
+ /* TAB PLUGIN DEFINITION
+ * ===================== */
+
+ $.fn.tab = function ( option ) {
+ return this.each(function () {
+ var $this = $(this)
+ , data = $this.data('tab')
+ if (!data) $this.data('tab', (data = new Tab(this)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ $.fn.tab.Constructor = Tab
+
+
+ /* TAB DATA-API
+ * ============ */
+
+ $(function () {
+ $('body').on('click.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
+ e.preventDefault()
+ $(this).tab('show')
+ })
+ })
+
+}( window.jQuery );
\ No newline at end of file
diff --git a/vendor/assets/javascripts/vendor.js b/vendor/assets/javascripts/vendor.js
index 1cdbc55b5..17db61668 100644
--- a/vendor/assets/javascripts/vendor.js
+++ b/vendor/assets/javascripts/vendor.js
@@ -10,5 +10,6 @@
//= require bootstrap-modal
//= require bootstrap-button
//= require bootstrap-dropdown
+//= require bootstrap-tab
// require html5shiv
// require_tree .
diff --git a/vendor/assets/stylesheets/bootstrap.css b/vendor/assets/stylesheets/bootstrap.css
index f43391083..0288a28f9 100644
--- a/vendor/assets/stylesheets/bootstrap.css
+++ b/vendor/assets/stylesheets/bootstrap.css
@@ -419,4 +419,502 @@
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
-}
\ No newline at end of file
+}
+.nav {
+ margin-left: 0;
+ margin-bottom: 18px;
+ list-style: none;
+}
+.nav > li > a {
+ display: block;
+}
+.nav > li > a:hover {
+ text-decoration: none;
+ background-color: #eeeeee;
+}
+.nav .nav-header {
+ display: block;
+ padding: 3px 15px;
+ font-size: 11px;
+ font-weight: bold;
+ line-height: 18px;
+ color: #999999;
+ text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
+ text-transform: uppercase;
+}
+.nav li + .nav-header {
+ margin-top: 9px;
+}
+.nav-list {
+ padding-left: 15px;
+ padding-right: 15px;
+ margin-bottom: 0;
+}
+.nav-list > li > a,
+.nav-list .nav-header {
+ margin-left: -15px;
+ margin-right: -15px;
+ text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
+}
+.nav-list > li > a {
+ padding: 3px 15px;
+}
+.nav-list > .active > a,
+.nav-list > .active > a:hover {
+ color: #ffffff;
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2);
+ background-color: #0088cc;
+}
+.nav-list [class^="icon-"] {
+ margin-right: 2px;
+}
+.nav-list .divider {
+ height: 1px;
+ margin: 8px 1px;
+ overflow: hidden;
+ background-color: #e5e5e5;
+ border-bottom: 1px solid #ffffff;
+ *width: 100%;
+ *margin: -5px 0 5px;
+}
+.nav-tabs,
+.nav-pills {
+ *zoom: 1;
+}
+.nav-tabs:before,
+.nav-pills:before,
+.nav-tabs:after,
+.nav-pills:after {
+ display: table;
+ content: "";
+}
+.nav-tabs:after,
+.nav-pills:after {
+ clear: both;
+}
+.nav-tabs > li,
+.nav-pills > li {
+ float: left;
+}
+.nav-tabs > li > a,
+.nav-pills > li > a {
+ padding-right: 12px;
+ padding-left: 12px;
+ margin-right: 2px;
+ line-height: 14px;
+}
+.nav-tabs {
+ border-bottom: 1px solid #ddd;
+}
+.nav-tabs > li {
+ margin-bottom: -1px;
+}
+.nav-tabs > li > a {
+ padding-top: 8px;
+ padding-bottom: 8px;
+ line-height: 18px;
+ border: 1px solid transparent;
+ -webkit-border-radius: 4px 4px 0 0;
+ -moz-border-radius: 4px 4px 0 0;
+ border-radius: 4px 4px 0 0;
+}
+.nav-tabs > li > a:hover {
+ border-color: #eeeeee #eeeeee #dddddd;
+}
+.nav-tabs > .active > a,
+.nav-tabs > .active > a:hover {
+ color: #555555;
+ background-color: #ffffff;
+ border: 1px solid #ddd;
+ border-bottom-color: transparent;
+ cursor: default;
+}
+.nav-pills > li > a {
+ padding-top: 8px;
+ padding-bottom: 8px;
+ margin-top: 2px;
+ margin-bottom: 2px;
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px;
+}
+.nav-pills > .active > a,
+.nav-pills > .active > a:hover {
+ color: #ffffff;
+ background-color: #0088cc;
+}
+.nav-stacked > li {
+ float: none;
+}
+.nav-stacked > li > a {
+ margin-right: 0;
+}
+.nav-tabs.nav-stacked {
+ border-bottom: 0;
+}
+.nav-tabs.nav-stacked > li > a {
+ border: 1px solid #ddd;
+ -webkit-border-radius: 0;
+ -moz-border-radius: 0;
+ border-radius: 0;
+}
+.nav-tabs.nav-stacked > li:first-child > a {
+ -webkit-border-radius: 4px 4px 0 0;
+ -moz-border-radius: 4px 4px 0 0;
+ border-radius: 4px 4px 0 0;
+}
+.nav-tabs.nav-stacked > li:last-child > a {
+ -webkit-border-radius: 0 0 4px 4px;
+ -moz-border-radius: 0 0 4px 4px;
+ border-radius: 0 0 4px 4px;
+}
+.nav-tabs.nav-stacked > li > a:hover {
+ border-color: #ddd;
+ z-index: 2;
+}
+.nav-pills.nav-stacked > li > a {
+ margin-bottom: 3px;
+}
+.nav-pills.nav-stacked > li:last-child > a {
+ margin-bottom: 1px;
+}
+.nav-tabs .dropdown-menu,
+.nav-pills .dropdown-menu {
+ margin-top: 1px;
+ border-width: 1px;
+}
+.nav-pills .dropdown-menu {
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+}
+.nav-tabs .dropdown-toggle .caret,
+.nav-pills .dropdown-toggle .caret {
+ border-top-color: #0088cc;
+ border-bottom-color: #0088cc;
+ margin-top: 6px;
+}
+.nav-tabs .dropdown-toggle:hover .caret,
+.nav-pills .dropdown-toggle:hover .caret {
+ border-top-color: #005580;
+ border-bottom-color: #005580;
+}
+.nav-tabs .active .dropdown-toggle .caret,
+.nav-pills .active .dropdown-toggle .caret {
+ border-top-color: #333333;
+ border-bottom-color: #333333;
+}
+.nav > .dropdown.active > a:hover {
+ color: #000000;
+ cursor: pointer;
+}
+.nav-tabs .open .dropdown-toggle,
+.nav-pills .open .dropdown-toggle,
+.nav > .open.active > a:hover {
+ color: #ffffff;
+ background-color: #999999;
+ border-color: #999999;
+}
+.nav .open .caret,
+.nav .open.active .caret,
+.nav .open a:hover .caret {
+ border-top-color: #ffffff;
+ border-bottom-color: #ffffff;
+ opacity: 1;
+ filter: alpha(opacity=100);
+}
+.tabs-stacked .open > a:hover {
+ border-color: #999999;
+}
+.tabbable {
+ *zoom: 1;
+}
+.tabbable:before,
+.tabbable:after {
+ display: table;
+ content: "";
+}
+.tabbable:after {
+ clear: both;
+}
+.tab-content {
+ display: table;
+ width: 100%;
+}
+.tabs-below .nav-tabs,
+.tabs-right .nav-tabs,
+.tabs-left .nav-tabs {
+ border-bottom: 0;
+}
+.tab-content > .tab-pane,
+.pill-content > .pill-pane {
+ display: none;
+}
+.tab-content > .active,
+.pill-content > .active {
+ display: block;
+}
+.tabs-below .nav-tabs {
+ border-top: 1px solid #ddd;
+}
+.tabs-below .nav-tabs > li {
+ margin-top: -1px;
+ margin-bottom: 0;
+}
+.tabs-below .nav-tabs > li > a {
+ -webkit-border-radius: 0 0 4px 4px;
+ -moz-border-radius: 0 0 4px 4px;
+ border-radius: 0 0 4px 4px;
+}
+.tabs-below .nav-tabs > li > a:hover {
+ border-bottom-color: transparent;
+ border-top-color: #ddd;
+}
+.tabs-below .nav-tabs .active > a,
+.tabs-below .nav-tabs .active > a:hover {
+ border-color: transparent #ddd #ddd #ddd;
+}
+.tabs-left .nav-tabs > li,
+.tabs-right .nav-tabs > li {
+ float: none;
+}
+.tabs-left .nav-tabs > li > a,
+.tabs-right .nav-tabs > li > a {
+ min-width: 74px;
+ margin-right: 0;
+ margin-bottom: 3px;
+}
+.tabs-left .nav-tabs {
+ float: left;
+ margin-right: 19px;
+ border-right: 1px solid #ddd;
+}
+.tabs-left .nav-tabs > li > a {
+ margin-right: -1px;
+ -webkit-border-radius: 4px 0 0 4px;
+ -moz-border-radius: 4px 0 0 4px;
+ border-radius: 4px 0 0 4px;
+}
+.tabs-left .nav-tabs > li > a:hover {
+ border-color: #eeeeee #dddddd #eeeeee #eeeeee;
+}
+.tabs-left .nav-tabs .active > a,
+.tabs-left .nav-tabs .active > a:hover {
+ border-color: #ddd transparent #ddd #ddd;
+ *border-right-color: #ffffff;
+}
+.tabs-right .nav-tabs {
+ float: right;
+ margin-left: 19px;
+ border-left: 1px solid #ddd;
+}
+.tabs-right .nav-tabs > li > a {
+ margin-left: -1px;
+ -webkit-border-radius: 0 4px 4px 0;
+ -moz-border-radius: 0 4px 4px 0;
+ border-radius: 0 4px 4px 0;
+}
+.tabs-right .nav-tabs > li > a:hover {
+ border-color: #eeeeee #eeeeee #eeeeee #dddddd;
+}
+.tabs-right .nav-tabs .active > a,
+.tabs-right .nav-tabs .active > a:hover {
+ border-color: #ddd #ddd #ddd transparent;
+ *border-left-color: #ffffff;
+}
+.row {
+ margin-left: -20px;
+ *zoom: 1;
+}
+.row:before,
+.row:after {
+ display: table;
+ content: "";
+}
+.row:after {
+ clear: both;
+}
+[class*="span"] {
+ float: left;
+ margin-left: 20px;
+}
+.container,
+.navbar-fixed-top .container,
+.navbar-fixed-bottom .container {
+ width: 940px;
+}
+.span12 {
+ width: 940px;
+}
+.span11 {
+ width: 860px;
+}
+.span10 {
+ width: 780px;
+}
+.span9 {
+ width: 700px;
+}
+.span8 {
+ width: 620px;
+}
+.span7 {
+ width: 540px;
+}
+.span6 {
+ width: 460px;
+}
+.span5 {
+ width: 380px;
+}
+.span4 {
+ width: 300px;
+}
+.span3 {
+ width: 220px;
+}
+.span2 {
+ width: 140px;
+}
+.span1 {
+ width: 60px;
+}
+.offset12 {
+ margin-left: 980px;
+}
+.offset11 {
+ margin-left: 900px;
+}
+.offset10 {
+ margin-left: 820px;
+}
+.offset9 {
+ margin-left: 740px;
+}
+.offset8 {
+ margin-left: 660px;
+}
+.offset7 {
+ margin-left: 580px;
+}
+.offset6 {
+ margin-left: 500px;
+}
+.offset5 {
+ margin-left: 420px;
+}
+.offset4 {
+ margin-left: 340px;
+}
+.offset3 {
+ margin-left: 260px;
+}
+.offset2 {
+ margin-left: 180px;
+}
+.offset1 {
+ margin-left: 100px;
+}
+.row-fluid {
+ width: 100%;
+ *zoom: 1;
+}
+.row-fluid:before,
+.row-fluid:after {
+ display: table;
+ content: "";
+}
+.row-fluid:after {
+ clear: both;
+}
+.row-fluid > [class*="span"] {
+ float: left;
+ margin-left: 2.127659574%;
+}
+.row-fluid > [class*="span"]:first-child {
+ margin-left: 0;
+}
+.row-fluid > .span12 {
+ width: 99.99999998999999%;
+}
+.row-fluid > .span11 {
+ width: 91.489361693%;
+}
+.row-fluid > .span10 {
+ width: 82.97872339599999%;
+}
+.row-fluid > .span9 {
+ width: 74.468085099%;
+}
+.row-fluid > .span8 {
+ width: 65.95744680199999%;
+}
+.row-fluid > .span7 {
+ width: 57.446808505%;
+}
+.row-fluid > .span6 {
+ width: 48.93617020799999%;
+}
+.row-fluid > .span5 {
+ width: 40.425531911%;
+}
+.row-fluid > .span4 {
+ width: 31.914893614%;
+}
+.row-fluid > .span3 {
+ width: 23.404255317%;
+}
+.row-fluid > .span2 {
+ width: 14.89361702%;
+}
+.row-fluid > .span1 {
+ width: 6.382978723%;
+}
+.label {
+ padding: 1px 4px 2px;
+ font-size: 10.998px;
+ font-weight: bold;
+ line-height: 13px;
+ color: #ffffff;
+ vertical-align: middle;
+ white-space: nowrap;
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+ background-color: #999999;
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+}
+.label:hover {
+ color: #ffffff;
+ text-decoration: none;
+}
+.label-important {
+ background-color: #b94a48;
+}
+.label-important:hover {
+ background-color: #953b39;
+}
+.label-warning {
+ background-color: #f89406;
+}
+.label-warning:hover {
+ background-color: #c67605;
+}
+.label-success {
+ background-color: #468847;
+}
+.label-success:hover {
+ background-color: #356635;
+}
+.label-info {
+ background-color: #3a87ad;
+}
+.label-info:hover {
+ background-color: #2d6987;
+}
+.label-inverse {
+ background-color: #333333;
+}
+.label-inverse:hover {
+ background-color: #1a1a1a;
+}