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; +}