summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/merge_request.js.coffee3
-rw-r--r--app/assets/stylesheets/generic/common.scss28
-rw-r--r--app/assets/stylesheets/generic/issue_box.scss4
-rw-r--r--app/assets/stylesheets/generic/tables.scss20
-rw-r--r--app/assets/stylesheets/main/variables.scss2
-rw-r--r--app/assets/stylesheets/sections/header.scss6
-rw-r--r--app/assets/stylesheets/sections/merge_requests.scss18
-rw-r--r--app/assets/stylesheets/sections/sidebar.scss21
-rw-r--r--app/assets/stylesheets/sections/tree.scss13
-rw-r--r--app/controllers/application_controller.rb4
-rw-r--r--app/controllers/oauth/applications_controller.rb41
-rw-r--r--app/controllers/oauth/authorizations_controller.rb57
-rw-r--r--app/controllers/oauth/authorized_applications_controller.rb8
-rw-r--r--app/controllers/profiles_controller.rb5
-rw-r--r--app/controllers/projects/services_controller.rb2
-rw-r--r--app/helpers/dashboard_helper.rb38
-rw-r--r--app/helpers/diff_helper.rb18
-rw-r--r--app/helpers/tab_helper.rb52
-rw-r--r--app/models/project.rb9
-rw-r--r--app/models/project_services/teamcity_service.rb116
-rw-r--r--app/models/user.rb5
-rw-r--r--app/services/oauth2/access_token_validation_service.rb41
-rw-r--r--app/views/dashboard/projects.html.haml12
-rw-r--r--app/views/doorkeeper/applications/_delete_form.html.haml4
-rw-r--r--app/views/doorkeeper/applications/_form.html.haml24
-rw-r--r--app/views/doorkeeper/applications/edit.html.haml2
-rw-r--r--app/views/doorkeeper/applications/index.html.haml16
-rw-r--r--app/views/doorkeeper/applications/new.html.haml2
-rw-r--r--app/views/doorkeeper/applications/show.html.haml26
-rw-r--r--app/views/doorkeeper/authorizations/error.html.haml3
-rw-r--r--app/views/doorkeeper/authorizations/new.html.haml28
-rw-r--r--app/views/doorkeeper/authorizations/show.html.haml3
-rw-r--r--app/views/doorkeeper/authorized_applications/_delete_form.html.haml4
-rw-r--r--app/views/doorkeeper/authorized_applications/index.html.haml16
-rw-r--r--app/views/groups/milestones/show.html.haml70
-rw-r--r--app/views/layouts/doorkeeper/admin.html.haml22
-rw-r--r--app/views/layouts/doorkeeper/application.html.haml15
-rw-r--r--app/views/layouts/nav/_dashboard.html.haml4
-rw-r--r--app/views/layouts/nav/_profile.html.haml5
-rw-r--r--app/views/layouts/project_settings.html.haml3
-rw-r--r--app/views/layouts/projects.html.haml2
-rw-r--r--app/views/notify/repository_push_email.html.haml4
-rw-r--r--app/views/profiles/accounts/show.html.haml1
-rw-r--r--app/views/profiles/applications.html.haml47
-rw-r--r--app/views/projects/diffs/_diffs.html.haml12
-rw-r--r--app/views/projects/issues/_discussion.html.haml37
-rw-r--r--app/views/projects/issues/show.html.haml86
-rw-r--r--app/views/projects/merge_requests/_discussion.html.haml31
-rw-r--r--app/views/projects/merge_requests/_show.html.haml105
-rw-r--r--app/views/projects/merge_requests/show/_mr_title.html.haml17
-rw-r--r--app/views/projects/merge_requests/show/_participants.html.haml5
-rw-r--r--app/views/projects/milestones/show.html.haml76
-rw-r--r--app/views/projects/show.html.haml3
-rw-r--r--app/views/shared/_no_ssh.html.haml20
54 files changed, 858 insertions, 358 deletions
diff --git a/app/assets/javascripts/merge_request.js.coffee b/app/assets/javascripts/merge_request.js.coffee
index fba933ddab5..9e3ca45ce04 100644
--- a/app/assets/javascripts/merge_request.js.coffee
+++ b/app/assets/javascripts/merge_request.js.coffee
@@ -89,6 +89,9 @@ class @MergeRequest
this.$('.merge-request-tabs .diffs-tab').addClass 'active'
this.loadDiff() unless @diffs_loaded
this.$('.diffs').show()
+ when 'commits'
+ this.$('.merge-request-tabs .commits-tab').addClass 'active'
+ this.$('.commits').show()
else
this.$('.merge-request-tabs .notes-tab').addClass 'active'
this.$('.notes').show()
diff --git a/app/assets/stylesheets/generic/common.scss b/app/assets/stylesheets/generic/common.scss
index 2fc738c18d8..19c8f103535 100644
--- a/app/assets/stylesheets/generic/common.scss
+++ b/app/assets/stylesheets/generic/common.scss
@@ -207,26 +207,6 @@ li.note {
}
}
-.no-ssh-key-message {
- padding: 10px 0;
- background: #C67;
- margin: 0;
- color: #FFF;
- margin-top: -1px;
- text-align: center;
-
- a {
- color: #fff;
- text-decoration: underline;
- }
-
- .links-xs {
- text-align: center;
- font-size: 16px;
- padding: 5px;
- }
-}
-
.warning_message {
border-left: 4px solid #ed9;
color: #b90;
@@ -282,7 +262,7 @@ img.emoji {
}
.navless-container {
- margin-top: 20px;
+ margin-top: 68px;
}
.description-block {
@@ -355,3 +335,9 @@ table {
.task-status {
margin-left: 10px;
}
+
+#nprogress .spinner {
+ top: auto !important;
+ bottom: 20px !important;
+ left: 20px !important;
+}
diff --git a/app/assets/stylesheets/generic/issue_box.scss b/app/assets/stylesheets/generic/issue_box.scss
index 176c45581a8..2563ab516e2 100644
--- a/app/assets/stylesheets/generic/issue_box.scss
+++ b/app/assets/stylesheets/generic/issue_box.scss
@@ -6,7 +6,9 @@
.issue-box {
display: inline-block;
- padding: 0 10px;
+ padding: 7px 13px;
+ font-weight: normal;
+ margin-right: 5px;
&.issue-box-closed {
background-color: $bg_danger;
diff --git a/app/assets/stylesheets/generic/tables.scss b/app/assets/stylesheets/generic/tables.scss
new file mode 100644
index 00000000000..71a7d4abaee
--- /dev/null
+++ b/app/assets/stylesheets/generic/tables.scss
@@ -0,0 +1,20 @@
+table {
+ &.table {
+ tr {
+ td, th {
+ padding: 8px 10px;
+ line-height: 20px;
+ vertical-align: middle;
+ }
+ th {
+ font-weight: normal;
+ font-size: 15px;
+ border-bottom: 1px solid #CCC !important;
+ }
+ td {
+ border-color: #F1F1F1 !important;
+ border-bottom: 1px solid;
+ }
+ }
+ }
+}
diff --git a/app/assets/stylesheets/main/variables.scss b/app/assets/stylesheets/main/variables.scss
index ca296c85a91..92b220f8019 100644
--- a/app/assets/stylesheets/main/variables.scss
+++ b/app/assets/stylesheets/main/variables.scss
@@ -46,4 +46,4 @@ $deleted: #f77;
/**
* NProgress customize
*/
-$nprogress-color: #3498db;
+$nprogress-color: #c0392b;
diff --git a/app/assets/stylesheets/sections/header.scss b/app/assets/stylesheets/sections/header.scss
index db419f76532..32b0b10c649 100644
--- a/app/assets/stylesheets/sections/header.scss
+++ b/app/assets/stylesheets/sections/header.scss
@@ -4,9 +4,13 @@
*/
header {
&.navbar-gitlab {
+ z-index: 100;
margin-bottom: 0;
min-height: 40px;
border: none;
+ position: fixed;
+ top: 0;
+ width: 100%;
.navbar-inner {
filter: none;
@@ -82,8 +86,6 @@ header {
}
}
- z-index: 10;
-
.container {
width: 100% !important;
padding-left: 0px;
diff --git a/app/assets/stylesheets/sections/merge_requests.scss b/app/assets/stylesheets/sections/merge_requests.scss
index a0f709070ac..920702ff3c4 100644
--- a/app/assets/stylesheets/sections/merge_requests.scss
+++ b/app/assets/stylesheets/sections/merge_requests.scss
@@ -19,13 +19,15 @@
}
}
-.merge-request .merge-request-tabs{
- margin: 20px 0;
-
- li {
- a {
- padding: 15px 40px;
- font-size: 14px;
+@media(min-width: $screen-sm-max) {
+ .merge-request .merge-request-tabs{
+ margin: 20px 0;
+
+ li {
+ a {
+ padding: 15px 40px;
+ font-size: 14px;
+ }
}
}
}
@@ -102,6 +104,7 @@
.mr-state-widget {
background: $box_bg;
margin-bottom: 20px;
+ color: #666;
@include box-shadow(0 1px 1px rgba(0, 0, 0, 0.09));
.ci_widget {
@@ -146,7 +149,6 @@
padding: 10px 15px;
h4 {
- font-size: 20px;
font-weight: normal;
}
diff --git a/app/assets/stylesheets/sections/sidebar.scss b/app/assets/stylesheets/sections/sidebar.scss
index 65229336e92..581a7318ee1 100644
--- a/app/assets/stylesheets/sections/sidebar.scss
+++ b/app/assets/stylesheets/sections/sidebar.scss
@@ -3,6 +3,7 @@
}
.sidebar-wrapper {
+ z-index: 99;
overflow-y: auto;
background: #F5F5F5;
}
@@ -11,6 +12,7 @@
width: 100%;
padding: 15px;
background: #FFF;
+ margin-top: 48px;
}
.nav-sidebar {
@@ -60,7 +62,7 @@
font-size: 13px;
line-height: 20px;
text-shadow: 0 1px 2px #FFF;
- padding-left: 67px;
+ padding-left: 20px;
&:hover {
text-decoration: none;
@@ -75,6 +77,7 @@
i {
width: 20px;
color: #888;
+ margin-right: 23px;
}
}
}
@@ -91,7 +94,7 @@
a {
padding: 5px 15px;
font-size: 12px;
- padding-left: 67px;
+ padding-left: 20px;
}
}
}
@@ -103,10 +106,11 @@
.sidebar-wrapper {
width: 250px;
- position: absolute;
+ position: fixed;
left: 250px;
height: 100%;
margin-left: -250px;
+ border-right: 1px solid #EAEAEA;
.nav-sidebar {
margin-top: 20px;
@@ -118,7 +122,6 @@
.content-wrapper {
padding: 20px;
- border-left: 1px solid #EAEAEA;
}
}
@@ -129,14 +132,16 @@
.sidebar-wrapper {
width: 52px;
- position: absolute;
- left: 50px;
+ position: fixed;
+ top: 0;
+ left: 0;
height: 100%;
- margin-left: -50px;
+ border-right: 1px solid #EAEAEA;
+ overflow-x: hidden;
.nav-sidebar {
margin-top: 20px;
- position: fixed;
+ position: absolute;
top: 45px;
width: 52px;
diff --git a/app/assets/stylesheets/sections/tree.scss b/app/assets/stylesheets/sections/tree.scss
index 678a6cd716d..bc7451e2d53 100644
--- a/app/assets/stylesheets/sections/tree.scss
+++ b/app/assets/stylesheets/sections/tree.scss
@@ -17,19 +17,6 @@
@include border-radius(0);
tr {
- td, th {
- padding: 8px 10px;
- line-height: 20px;
- }
- th {
- font-weight: normal;
- font-size: 15px;
- border-bottom: 1px solid #CCC !important;
- }
- td {
- border-color: #F1F1F1 !important;
- border-bottom: 1px solid;
- }
&:hover {
td {
background: $hover;
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 41ad5f98ace..4b8cae469e3 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -257,10 +257,6 @@ class ApplicationController < ActionController::Base
# or improve current implementation to filter only issues you
# created or assigned or mentioned
#@filter_params[:authorized_only] = true
-
- unless @filter_params[:assignee_id]
- @filter_params[:assignee_id] = current_user.id
- end
end
@filter_params
diff --git a/app/controllers/oauth/applications_controller.rb b/app/controllers/oauth/applications_controller.rb
new file mode 100644
index 00000000000..3407490e498
--- /dev/null
+++ b/app/controllers/oauth/applications_controller.rb
@@ -0,0 +1,41 @@
+class Oauth::ApplicationsController < Doorkeeper::ApplicationsController
+ before_filter :authenticate_user!
+ layout "profile"
+
+ def index
+ head :forbidden and return
+ end
+
+ def create
+ @application = Doorkeeper::Application.new(application_params)
+
+ if Doorkeeper.configuration.confirm_application_owner?
+ @application.owner = current_user
+ end
+
+ if @application.save
+ flash[:notice] = I18n.t(:notice, scope: [:doorkeeper, :flash, :applications, :create])
+ redirect_to oauth_application_url(@application)
+ else
+ render :new
+ end
+ end
+
+ def destroy
+ if @application.destroy
+ flash[:notice] = I18n.t(:notice, scope: [:doorkeeper, :flash, :applications, :destroy])
+ end
+
+ redirect_to applications_profile_url
+ end
+
+ private
+
+ def set_application
+ @application = current_user.oauth_applications.find(params[:id])
+ end
+
+ rescue_from ActiveRecord::RecordNotFound do |exception|
+ render "errors/not_found", layout: "errors", status: 404
+ end
+end
diff --git a/app/controllers/oauth/authorizations_controller.rb b/app/controllers/oauth/authorizations_controller.rb
new file mode 100644
index 00000000000..a57b4a60c24
--- /dev/null
+++ b/app/controllers/oauth/authorizations_controller.rb
@@ -0,0 +1,57 @@
+class Oauth::AuthorizationsController < Doorkeeper::AuthorizationsController
+ before_filter :authenticate_resource_owner!
+ layout "profile"
+
+ def new
+ if pre_auth.authorizable?
+ if skip_authorization? || matching_token?
+ auth = authorization.authorize
+ redirect_to auth.redirect_uri
+ else
+ render "doorkeeper/authorizations/new"
+ end
+ else
+ render "doorkeeper/authorizations/error"
+ end
+ end
+
+ # TODO: Handle raise invalid authorization
+ def create
+ redirect_or_render authorization.authorize
+ end
+
+ def destroy
+ redirect_or_render authorization.deny
+ end
+
+ private
+
+ def matching_token?
+ Doorkeeper::AccessToken.matching_token_for(pre_auth.client,
+ current_resource_owner.id,
+ pre_auth.scopes)
+ end
+
+ def redirect_or_render(auth)
+ if auth.redirectable?
+ redirect_to auth.redirect_uri
+ else
+ render json: auth.body, status: auth.status
+ end
+ end
+
+ def pre_auth
+ @pre_auth ||=
+ Doorkeeper::OAuth::PreAuthorization.new(Doorkeeper.configuration,
+ server.client_via_uid,
+ params)
+ end
+
+ def authorization
+ @authorization ||= strategy.request
+ end
+
+ def strategy
+ @strategy ||= server.authorization_request(pre_auth.response_type)
+ end
+end
diff --git a/app/controllers/oauth/authorized_applications_controller.rb b/app/controllers/oauth/authorized_applications_controller.rb
new file mode 100644
index 00000000000..0b27ce7da72
--- /dev/null
+++ b/app/controllers/oauth/authorized_applications_controller.rb
@@ -0,0 +1,8 @@
+class Oauth::AuthorizedApplicationsController < Doorkeeper::AuthorizedApplicationsController
+ layout "profile"
+
+ def destroy
+ Doorkeeper::AccessToken.revoke_all_for(params[:id], current_resource_owner)
+ redirect_to applications_profile_url, notice: I18n.t(:notice, scope: [:doorkeeper, :flash, :authorized_applications, :destroy])
+ end
+end
diff --git a/app/controllers/profiles_controller.rb b/app/controllers/profiles_controller.rb
index e877f9b9049..c0b7e2223a2 100644
--- a/app/controllers/profiles_controller.rb
+++ b/app/controllers/profiles_controller.rb
@@ -13,6 +13,11 @@ class ProfilesController < ApplicationController
def design
end
+ def applications
+ @applications = current_user.oauth_applications
+ @authorized_tokens = current_user.oauth_authorized_tokens
+ end
+
def update
user_params.except!(:email) if @user.ldap_user?
diff --git a/app/controllers/projects/services_controller.rb b/app/controllers/projects/services_controller.rb
index c50a1f1e75b..ef4d2609147 100644
--- a/app/controllers/projects/services_controller.rb
+++ b/app/controllers/projects/services_controller.rb
@@ -42,7 +42,7 @@ class Projects::ServicesController < Projects::ApplicationController
:title, :token, :type, :active, :api_key, :subdomain,
:room, :recipients, :project_url, :webhook,
:user_key, :device, :priority, :sound, :bamboo_url, :username, :password,
- :build_key, :server
+ :build_key, :server, :teamcity_url, :build_type
)
end
end
diff --git a/app/helpers/dashboard_helper.rb b/app/helpers/dashboard_helper.rb
index 976a396e7b6..3e6f3b41ff5 100644
--- a/app/helpers/dashboard_helper.rb
+++ b/app/helpers/dashboard_helper.rb
@@ -1,13 +1,4 @@
module DashboardHelper
- def entities_per_project(project, entity)
- case entity.to_sym
- when :issue then @issues.where(project_id: project.id)
- when :merge_request then @merge_requests.where(target_project_id: project.id)
- else
- []
- end.count
- end
-
def projects_dashboard_filter_path(options={})
exist_opts = {
sort: params[:sort],
@@ -22,32 +13,11 @@ module DashboardHelper
path
end
- def assigned_entities_count(current_user, entity, scope = nil)
- items = current_user.send('assigned_' + entity.pluralize)
- get_count(items, scope)
- end
-
- def authored_entities_count(current_user, entity, scope = nil)
- items = current_user.send(entity.pluralize)
- get_count(items, scope)
+ def assigned_issues_dashboard_path
+ issues_dashboard_path(assignee_id: current_user.id)
end
- def authorized_entities_count(current_user, entity, scope = nil)
- items = entity.classify.constantize
- get_count(items, scope, true, current_user)
- end
-
- protected
-
- def get_count(items, scope, get_authorized = false, current_user = nil)
- items = items.opened
- if scope.kind_of?(Group)
- items = items.of_group(scope)
- elsif scope.kind_of?(Project)
- items = items.of_projects(scope)
- elsif get_authorized
- items = items.of_projects(current_user.authorized_projects)
- end
- items.count
+ def assigned_mrs_dashboard_path
+ merge_requests_dashboard_path(assignee_id: current_user.id)
end
end
diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb
index cb50d89cba8..a15af0be01a 100644
--- a/app/helpers/diff_helper.rb
+++ b/app/helpers/diff_helper.rb
@@ -117,4 +117,22 @@ module DiffHelper
[comments_left, comments_right]
end
+
+ def inline_diff_btn
+ params_copy = params.dup
+ params_copy[:view] = 'inline'
+
+ link_to url_for(params_copy), id: "commit-diff-viewtype", class: (params[:view] != 'parallel' ? 'btn active' : 'btn') do
+ 'Inline'
+ end
+ end
+
+ def parallel_diff_btn
+ params_copy = params.dup
+ params_copy[:view] = 'parallel'
+
+ link_to url_for(params_copy), id: "commit-diff-viewtype", class: (params[:view] == 'parallel' ? 'btn active' : 'btn') do
+ 'Side-by-side'
+ end
+ end
end
diff --git a/app/helpers/tab_helper.rb b/app/helpers/tab_helper.rb
index bc43e078568..639fc98c222 100644
--- a/app/helpers/tab_helper.rb
+++ b/app/helpers/tab_helper.rb
@@ -28,6 +28,10 @@ module TabHelper
# nav_link(controller: [:tree, :refs]) { "Hello" }
# # => '<li class="active">Hello</li>'
#
+ # # Several paths
+ # nav_link(path: ['tree#show', 'profile#show']) { "Hello" }
+ # # => '<li class="active">Hello</li>'
+ #
# # Shorthand path
# nav_link(path: 'tree#show') { "Hello" }
# # => '<li class="active">Hello</li>'
@@ -38,25 +42,7 @@ module TabHelper
#
# Returns a list item element String
def nav_link(options = {}, &block)
- if path = options.delete(:path)
- if path.respond_to?(:each)
- c = path.map { |p| p.split('#').first }
- a = path.map { |p| p.split('#').last }
- else
- c, a, _ = path.split('#')
- end
- else
- c = options.delete(:controller)
- a = options.delete(:action)
- end
-
- if c && a
- # When given both options, make sure BOTH are active
- klass = current_controller?(*c) && current_action?(*a) ? 'active' : ''
- else
- # Otherwise check EITHER option
- klass = current_controller?(*c) || current_action?(*a) ? 'active' : ''
- end
+ klass = active_nav_link?(options) ? 'active' : ''
# Add our custom class into the html_options, which may or may not exist
# and which may or may not already have a :class key
@@ -72,6 +58,34 @@ module TabHelper
end
end
+ def active_nav_link?(options)
+ if path = options.delete(:path)
+ unless path.respond_to?(:each)
+ path = [path]
+ end
+
+ path.any? do |single_path|
+ current_path?(single_path)
+ end
+ else
+ c = options.delete(:controller)
+ a = options.delete(:action)
+
+ if c && a
+ # When given both options, make sure BOTH are true
+ current_controller?(*c) && current_action?(*a)
+ else
+ # Otherwise check EITHER option
+ current_controller?(*c) || current_action?(*a)
+ end
+ end
+ end
+
+ def current_path?(path)
+ c, a, _ = path.split('#')
+ current_controller?(c) && current_action?(a)
+ end
+
def project_tab_class
return "active" if current_page?(controller: "/projects", action: :edit, id: @project)
diff --git a/app/models/project.rb b/app/models/project.rb
index 40b3412c654..b0c379e6157 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -66,6 +66,7 @@ class Project < ActiveRecord::Base
has_one :slack_service, dependent: :destroy
has_one :buildbox_service, dependent: :destroy
has_one :bamboo_service, dependent: :destroy
+ has_one :teamcity_service, dependent: :destroy
has_one :pushover_service, dependent: :destroy
has_one :forked_project_link, dependent: :destroy, foreign_key: "forked_to_project_id"
has_one :forked_from_project, through: :forked_project_link
@@ -314,7 +315,8 @@ class Project < ActiveRecord::Base
end
def available_services_names
- %w(gitlab_ci campfire hipchat pivotaltracker flowdock assembla emails_on_push gemnasium slack pushover buildbox bamboo)
+ %w(gitlab_ci campfire hipchat pivotaltracker flowdock assembla
+ emails_on_push gemnasium slack pushover buildbox bamboo teamcity)
end
def gitlab_ci?
@@ -329,11 +331,6 @@ class Project < ActiveRecord::Base
@ci_service ||= ci_services.select(&:activated?).first
end
- # For compatibility with old code
- def code
- path
- end
-
def items_for(entity)
case entity
when 'issue' then
diff --git a/app/models/project_services/teamcity_service.rb b/app/models/project_services/teamcity_service.rb
new file mode 100644
index 00000000000..52b5862e4d1
--- /dev/null
+++ b/app/models/project_services/teamcity_service.rb
@@ -0,0 +1,116 @@
+class TeamcityService < CiService
+ include HTTParty
+
+ prop_accessor :teamcity_url, :build_type, :username, :password
+
+ validates :teamcity_url, presence: true,
+ format: { with: URI::regexp }, if: :activated?
+ validates :build_type, presence: true, if: :activated?
+ validates :username, presence: true,
+ if: ->(service) { service.password? }, if: :activated?
+ validates :password, presence: true,
+ if: ->(service) { service.username? }, if: :activated?
+
+ attr_accessor :response
+
+ after_save :compose_service_hook, if: :activated?
+
+ def compose_service_hook
+ hook = service_hook || build_service_hook
+ hook.save
+ end
+
+ def title
+ 'JetBrains TeamCity CI'
+ end
+
+ def description
+ 'A continuous integration and build server'
+ end
+
+ def help
+ 'The build configuration in Teamcity must use the build format '\
+ 'number %build.vcs.number% '\
+ 'you will also want to configure monitoring of all branches so merge '\
+ 'requests build, that setting is in the vsc root advanced settings.'
+ end
+
+ def to_param
+ 'teamcity'
+ end
+
+ def fields
+ [
+ { type: 'text', name: 'teamcity_url',
+ placeholder: 'TeamCity root URL like https://teamcity.example.com' },
+ { type: 'text', name: 'build_type',
+ placeholder: 'Build configuration ID' },
+ { type: 'text', name: 'username',
+ placeholder: 'A user with permissions to trigger a manual build' },
+ { type: 'password', name: 'password' },
+ ]
+ end
+
+ def build_info(sha)
+ url = URI.parse("#{teamcity_url}/httpAuth/app/rest/builds/"\
+ "branch:unspecified:any,number:#{sha}")
+ auth = {
+ username: username,
+ password: password,
+ }
+ @response = HTTParty.get("#{url}", verify: false, basic_auth: auth)
+ end
+
+ def build_page(sha)
+ build_info(sha) if @response.nil? || !@response.code
+
+ if @response.code != 200
+ # If actual build link can't be determined,
+ # send user to build summary page.
+ "#{teamcity_url}/viewLog.html?buildTypeId=#{build_type}"
+ else
+ # If actual build link is available, go to build result page.
+ built_id = @response['build']['id']
+ "#{teamcity_url}/viewLog.html?buildId=#{built_id}"\
+ "&buildTypeId=#{build_type}"
+ end
+ end
+
+ def commit_status(sha)
+ build_info(sha) if @response.nil? || !@response.code
+ return :error unless @response.code == 200 || @response.code == 404
+
+ status = if @response.code == 404
+ 'Pending'
+ else
+ @response['build']['status']
+ end
+
+ if status.include?('SUCCESS')
+ 'success'
+ elsif status.include?('FAILURE')
+ 'failed'
+ elsif status.include?('Pending')
+ 'pending'
+ else
+ :error
+ end
+ end
+
+ def execute(data)
+ auth = {
+ username: username,
+ password: password,
+ }
+
+ branch = data[:ref]
+
+ self.class.post("#{teamcity_url}/httpAuth/app/rest/buildQueue",
+ body: "<build branchName=\"#{branch}\">"\
+ "<buildType id=\"#{build_type}\"/>"\
+ '</build>',
+ headers: { 'Content-type' => 'application/xml' },
+ basic_auth: auth
+ )
+ end
+end
diff --git a/app/models/user.rb b/app/models/user.rb
index 7faeef1b5b0..7dae318e780 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -106,6 +106,7 @@ class User < ActiveRecord::Base
has_many :recent_events, -> { order "id DESC" }, foreign_key: :author_id, class_name: "Event"
has_many :assigned_issues, dependent: :destroy, foreign_key: :assignee_id, class_name: "Issue"
has_many :assigned_merge_requests, dependent: :destroy, foreign_key: :assignee_id, class_name: "MergeRequest"
+ has_many :oauth_applications, class_name: 'Doorkeeper::Application', as: :owner, dependent: :destroy
#
@@ -564,4 +565,8 @@ class User < ActiveRecord::Base
namespaces += masters_groups
end
end
+
+ def oauth_authorized_tokens
+ Doorkeeper::AccessToken.where(resource_owner_id: self.id, revoked_at: nil)
+ end
end
diff --git a/app/services/oauth2/access_token_validation_service.rb b/app/services/oauth2/access_token_validation_service.rb
new file mode 100644
index 00000000000..95283489753
--- /dev/null
+++ b/app/services/oauth2/access_token_validation_service.rb
@@ -0,0 +1,41 @@
+module Oauth2::AccessTokenValidationService
+ # Results:
+ VALID = :valid
+ EXPIRED = :expired
+ REVOKED = :revoked
+ INSUFFICIENT_SCOPE = :insufficient_scope
+
+ class << self
+ def validate(token, scopes: [])
+ if token.expired?
+ return EXPIRED
+
+ elsif token.revoked?
+ return REVOKED
+
+ elsif !self.sufficent_scope?(token, scopes)
+ return INSUFFICIENT_SCOPE
+
+ else
+ return VALID
+ end
+ end
+
+ protected
+ # True if the token's scope is a superset of required scopes,
+ # or the required scopes is empty.
+ def sufficent_scope?(token, scopes)
+ if scopes.blank?
+ # if no any scopes required, the scopes of token is sufficient.
+ return true
+ else
+ # If there are scopes required, then check whether
+ # the set of authorized scopes is a superset of the set of required scopes
+ required_scopes = Set.new(scopes)
+ authorized_scopes = Set.new(token.scopes)
+
+ return authorized_scopes >= required_scopes
+ end
+ end
+ end
+end \ No newline at end of file
diff --git a/app/views/dashboard/projects.html.haml b/app/views/dashboard/projects.html.haml
index 5b7835b097b..b880acf1245 100644
--- a/app/views/dashboard/projects.html.haml
+++ b/app/views/dashboard/projects.html.haml
@@ -38,17 +38,19 @@
= link_to project_path(project), class: dom_class(project) do
= project.name_with_namespace
+ - if project.forked_from_project
+ &nbsp;
+ %small
+ %i.fa.fa-code-fork
+ Forked from:
+ = link_to project.forked_from_project.name_with_namespace, project_path(project.forked_from_project)
+
- if current_user.can_leave_project?(project)
.pull-right
= link_to leave_project_team_members_path(project), data: { confirm: "Leave project?"}, method: :delete, remote: true, class: "btn-tiny btn remove-row", title: 'Leave project' do
%i.fa.fa-sign-out
Leave
- - if project.forked_from_project
- %small.pull-right
- %i.fa.fa-code-fork
- Forked from:
- = link_to project.forked_from_project.name_with_namespace, project_path(project.forked_from_project)
.project-info
.pull-right
- if project.archived?
diff --git a/app/views/doorkeeper/applications/_delete_form.html.haml b/app/views/doorkeeper/applications/_delete_form.html.haml
new file mode 100644
index 00000000000..bf8098f38d0
--- /dev/null
+++ b/app/views/doorkeeper/applications/_delete_form.html.haml
@@ -0,0 +1,4 @@
+- submit_btn_css ||= 'btn btn-link btn-remove btn-small'
+= form_tag oauth_application_path(application) do
+ %input{:name => "_method", :type => "hidden", :value => "delete"}/
+ = submit_tag 'Destroy', onclick: "return confirm('Are you sure?')", class: submit_btn_css \ No newline at end of file
diff --git a/app/views/doorkeeper/applications/_form.html.haml b/app/views/doorkeeper/applications/_form.html.haml
new file mode 100644
index 00000000000..a5fec2fabdb
--- /dev/null
+++ b/app/views/doorkeeper/applications/_form.html.haml
@@ -0,0 +1,24 @@
+= form_for application, url: doorkeeper_submit_path(application), html: {class: 'form-horizontal', role: 'form'} do |f|
+ - if application.errors.any?
+ .alert.alert-danger{"data-alert" => ""}
+ %p Whoops! Check your form for possible errors
+ = content_tag :div, class: "form-group#{' has-error' if application.errors[:name].present?}" do
+ = f.label :name, class: 'col-sm-2 control-label'
+ .col-sm-10
+ = f.text_field :name, class: 'form-control'
+ = doorkeeper_errors_for application, :name
+ = content_tag :div, class: "form-group#{' has-error' if application.errors[:redirect_uri].present?}" do
+ = f.label :redirect_uri, class: 'col-sm-2 control-label'
+ .col-sm-10
+ = f.text_area :redirect_uri, class: 'form-control'
+ = doorkeeper_errors_for application, :redirect_uri
+ %span.help-block
+ Use one line per URI
+ - if Doorkeeper.configuration.native_redirect_uri
+ %span.help-block
+ Use
+ %code= Doorkeeper.configuration.native_redirect_uri
+ for local tests
+ .form-actions
+ = f.submit 'Submit', class: "btn btn-primary wide"
+ = link_to "Cancel", applications_profile_path, class: "btn btn-default"
diff --git a/app/views/doorkeeper/applications/edit.html.haml b/app/views/doorkeeper/applications/edit.html.haml
new file mode 100644
index 00000000000..61584eb9c49
--- /dev/null
+++ b/app/views/doorkeeper/applications/edit.html.haml
@@ -0,0 +1,2 @@
+%h3.page-title Edit application
+= render 'form', application: @application \ No newline at end of file
diff --git a/app/views/doorkeeper/applications/index.html.haml b/app/views/doorkeeper/applications/index.html.haml
new file mode 100644
index 00000000000..e5be4b4bcac
--- /dev/null
+++ b/app/views/doorkeeper/applications/index.html.haml
@@ -0,0 +1,16 @@
+%h3.page-title Your applications
+%p= link_to 'New Application', new_oauth_application_path, class: 'btn btn-success'
+%table.table.table-striped
+ %thead
+ %tr
+ %th Name
+ %th Callback URL
+ %th
+ %th
+ %tbody
+ - @applications.each do |application|
+ %tr{:id => "application_#{application.id}"}
+ %td= link_to application.name, oauth_application_path(application)
+ %td= application.redirect_uri
+ %td= link_to 'Edit', edit_oauth_application_path(application), class: 'btn btn-link'
+ %td= render 'delete_form', application: application \ No newline at end of file
diff --git a/app/views/doorkeeper/applications/new.html.haml b/app/views/doorkeeper/applications/new.html.haml
new file mode 100644
index 00000000000..655845e4af5
--- /dev/null
+++ b/app/views/doorkeeper/applications/new.html.haml
@@ -0,0 +1,2 @@
+%h3.page-title New application
+= render 'form', application: @application \ No newline at end of file
diff --git a/app/views/doorkeeper/applications/show.html.haml b/app/views/doorkeeper/applications/show.html.haml
new file mode 100644
index 00000000000..82e78b4af13
--- /dev/null
+++ b/app/views/doorkeeper/applications/show.html.haml
@@ -0,0 +1,26 @@
+%h3.page-title
+ Application: #{@application.name}
+
+
+%table.table
+ %tr
+ %td
+ Application Id
+ %td
+ %code#application_id= @application.uid
+ %tr
+ %td
+ Secret:
+ %td
+ %code#secret= @application.secret
+
+ %tr
+ %td
+ Callback url
+ %td
+ - @application.redirect_uri.split.each do |uri|
+ %div
+ %span.monospace= uri
+.form-actions
+ = link_to 'Edit', edit_oauth_application_path(@application), class: 'btn btn-primary wide pull-left'
+ = render 'delete_form', application: @application, submit_btn_css: 'btn btn-danger prepend-left-10'
diff --git a/app/views/doorkeeper/authorizations/error.html.haml b/app/views/doorkeeper/authorizations/error.html.haml
new file mode 100644
index 00000000000..7561ec85ed9
--- /dev/null
+++ b/app/views/doorkeeper/authorizations/error.html.haml
@@ -0,0 +1,3 @@
+%h3.page-title An error has occurred
+%main{:role => "main"}
+ %pre= @pre_auth.error_response.body[:error_description] \ No newline at end of file
diff --git a/app/views/doorkeeper/authorizations/new.html.haml b/app/views/doorkeeper/authorizations/new.html.haml
new file mode 100644
index 00000000000..15f9ee266c1
--- /dev/null
+++ b/app/views/doorkeeper/authorizations/new.html.haml
@@ -0,0 +1,28 @@
+%h3.page-title Authorize required
+%main{:role => "main"}
+ %p.h4
+ Authorize
+ %strong.text-info= @pre_auth.client.name
+ to use your account?
+ - if @pre_auth.scopes
+ #oauth-permissions
+ %p This application will be able to:
+ %ul.text-info
+ - @pre_auth.scopes.each do |scope|
+ %li= t scope, scope: [:doorkeeper, :scopes]
+ %hr/
+ .actions
+ = form_tag oauth_authorization_path, method: :post do
+ = hidden_field_tag :client_id, @pre_auth.client.uid
+ = hidden_field_tag :redirect_uri, @pre_auth.redirect_uri
+ = hidden_field_tag :state, @pre_auth.state
+ = hidden_field_tag :response_type, @pre_auth.response_type
+ = hidden_field_tag :scope, @pre_auth.scope
+ = submit_tag "Authorize", class: "btn btn-success wide pull-left"
+ = form_tag oauth_authorization_path, method: :delete do
+ = hidden_field_tag :client_id, @pre_auth.client.uid
+ = hidden_field_tag :redirect_uri, @pre_auth.redirect_uri
+ = hidden_field_tag :state, @pre_auth.state
+ = hidden_field_tag :response_type, @pre_auth.response_type
+ = hidden_field_tag :scope, @pre_auth.scope
+ = submit_tag "Deny", class: "btn btn-danger prepend-left-10" \ No newline at end of file
diff --git a/app/views/doorkeeper/authorizations/show.html.haml b/app/views/doorkeeper/authorizations/show.html.haml
new file mode 100644
index 00000000000..9a402007194
--- /dev/null
+++ b/app/views/doorkeeper/authorizations/show.html.haml
@@ -0,0 +1,3 @@
+%h3.page-title Authorization code:
+%main{:role => "main"}
+ %code#authorization_code= params[:code] \ No newline at end of file
diff --git a/app/views/doorkeeper/authorized_applications/_delete_form.html.haml b/app/views/doorkeeper/authorized_applications/_delete_form.html.haml
new file mode 100644
index 00000000000..5cbb4a70c19
--- /dev/null
+++ b/app/views/doorkeeper/authorized_applications/_delete_form.html.haml
@@ -0,0 +1,4 @@
+- submit_btn_css ||= 'btn btn-link btn-remove'
+= form_tag oauth_authorized_application_path(application) do
+ %input{:name => "_method", :type => "hidden", :value => "delete"}/
+ = submit_tag 'Revoke', onclick: "return confirm('Are you sure?')", class: 'btn btn-link btn-remove btn-small' \ No newline at end of file
diff --git a/app/views/doorkeeper/authorized_applications/index.html.haml b/app/views/doorkeeper/authorized_applications/index.html.haml
new file mode 100644
index 00000000000..814cdc987ef
--- /dev/null
+++ b/app/views/doorkeeper/authorized_applications/index.html.haml
@@ -0,0 +1,16 @@
+%header.page-header
+ %h1 Your authorized applications
+%main{:role => "main"}
+ %table.table.table-striped
+ %thead
+ %tr
+ %th Application
+ %th Created At
+ %th
+ %th
+ %tbody
+ - @applications.each do |application|
+ %tr
+ %td= application.name
+ %td= application.created_at.strftime('%Y-%m-%d %H:%M:%S')
+ %td= render 'delete_form', application: application \ No newline at end of file
diff --git a/app/views/groups/milestones/show.html.haml b/app/views/groups/milestones/show.html.haml
index 411d1822be0..7bcac56c37b 100644
--- a/app/views/groups/milestones/show.html.haml
+++ b/app/views/groups/milestones/show.html.haml
@@ -1,4 +1,9 @@
-%h3.page-title
+%h4.page-title
+ .issue-box{ class: "issue-box-#{@group_milestone.closed? ? 'closed' : 'open'}" }
+ - if @group_milestone.closed?
+ Closed
+ - else
+ Open
Milestone #{@group_milestone.title}
.pull-right
- if can?(current_user, :manage_group, @group)
@@ -7,46 +12,41 @@
- else
= link_to 'Reopen Milestone', group_milestone_path(@group, @group_milestone.safe_title, title: @group_milestone.title, milestone: {state_event: :activate }), method: :put, class: "btn btn-small btn-grouped btn-reopen"
+%hr
- if (@group_milestone.total_items_count == @group_milestone.closed_items_count) && @group_milestone.active?
.alert.alert-success
%span All issues for this milestone are closed. You may close the milestone now.
-.back-link
- = link_to group_milestones_path(@group) do
- &larr; To milestones list
-
-.issue-box{ class: "issue-box-#{@group_milestone.closed? ? 'closed' : 'open'}" }
- .state.clearfix
- .state-label
- - if @group_milestone.closed?
- Closed
- - else
- Open
-
- %h4.title
- = gfm escape_once(@group_milestone.title)
-
- .description
- - @group_milestone.milestones.each do |milestone|
- %hr
- %h4
- = link_to "#{milestone.project.name} - #{milestone.title}", project_milestone_path(milestone.project, milestone)
- %span.pull-right= milestone.expires_at
+.description
+%table.table
+ %thead
+ %tr
+ %th Project
+ %th Open issues
+ %th State
+ %th Due date
+ - @group_milestone.milestones.each do |milestone|
+ %tr
+ %td
+ = link_to "#{milestone.project.name}", project_milestone_path(milestone.project, milestone)
+ %td
+ = milestone.issues.opened.count
+ %td
- if milestone.closed?
- %span.label.label-danger #{milestone.state}
- = preserve do
- - if milestone.description.present?
- = milestone.description
-
- .context
- %p
- Progress:
- #{@group_milestone.closed_items_count} closed
- &ndash;
- #{@group_milestone.open_items_count} open
+ Closed
+ - else
+ Open
+ %td
+ = milestone.expires_at
- .progress.progress-info
- .progress-bar{style: "width: #{@group_milestone.percent_complete}%;"}
+.context
+ %p.lead
+ Progress:
+ #{@group_milestone.closed_items_count} closed
+ &ndash;
+ #{@group_milestone.open_items_count} open
+ .progress.progress-info
+ .progress-bar{style: "width: #{@group_milestone.percent_complete}%;"}
%ul.nav.nav-tabs
%li.active
diff --git a/app/views/layouts/doorkeeper/admin.html.haml b/app/views/layouts/doorkeeper/admin.html.haml
new file mode 100644
index 00000000000..bd9adfab66d
--- /dev/null
+++ b/app/views/layouts/doorkeeper/admin.html.haml
@@ -0,0 +1,22 @@
+!!!
+%html
+ %head
+ %meta{:charset => "utf-8"}
+ %meta{:content => "IE=edge", "http-equiv" => "X-UA-Compatible"}
+ %meta{:content => "width=device-width, initial-scale=1.0", :name => "viewport"}
+ %title Doorkeeper
+ = stylesheet_link_tag "doorkeeper/admin/application"
+ = csrf_meta_tags
+ %body
+ .navbar.navbar-inverse.navbar-fixed-top{:role => "navigation"}
+ .container
+ .navbar-header
+ = link_to 'OAuth2 Provider', oauth_applications_path, class: 'navbar-brand'
+ %ul.nav.navbar-nav
+ = content_tag :li, class: "#{'active' if request.path == oauth_applications_path}" do
+ = link_to 'Applications', oauth_applications_path
+ .container
+ - if flash[:notice].present?
+ .alert.alert-info
+ = flash[:notice]
+ = yield \ No newline at end of file
diff --git a/app/views/layouts/doorkeeper/application.html.haml b/app/views/layouts/doorkeeper/application.html.haml
new file mode 100644
index 00000000000..e5f37fad1f4
--- /dev/null
+++ b/app/views/layouts/doorkeeper/application.html.haml
@@ -0,0 +1,15 @@
+!!!
+%html
+ %head
+ %title OAuth authorize required
+ %meta{:charset => "utf-8"}
+ %meta{:content => "IE=edge", "http-equiv" => "X-UA-Compatible"}
+ %meta{:content => "width=device-width, initial-scale=1.0", :name => "viewport"}
+ = stylesheet_link_tag "doorkeeper/application"
+ = csrf_meta_tags
+ %body
+ #container
+ - if flash[:notice].present?
+ .alert.alert-info
+ = flash[:notice]
+ = yield \ No newline at end of file
diff --git a/app/views/layouts/nav/_dashboard.html.haml b/app/views/layouts/nav/_dashboard.html.haml
index da1976346d5..a2eaa2d83c5 100644
--- a/app/views/layouts/nav/_dashboard.html.haml
+++ b/app/views/layouts/nav/_dashboard.html.haml
@@ -10,13 +10,13 @@
%span
Projects
= nav_link(path: 'dashboard#issues') do
- = link_to issues_dashboard_path, class: 'shortcuts-issues' do
+ = link_to assigned_issues_dashboard_path, class: 'shortcuts-issues' do
%i.fa.fa-exclamation-circle
%span
Issues
%span.count= current_user.assigned_issues.opened.count
= nav_link(path: 'dashboard#merge_requests') do
- = link_to merge_requests_dashboard_path, class: 'shortcuts-merge_requests' do
+ = link_to assigned_mrs_dashboard_path, class: 'shortcuts-merge_requests' do
%i.fa.fa-tasks
%span
Merge Requests
diff --git a/app/views/layouts/nav/_profile.html.haml b/app/views/layouts/nav/_profile.html.haml
index 64d9ad75dc2..36b48a5d02d 100644
--- a/app/views/layouts/nav/_profile.html.haml
+++ b/app/views/layouts/nav/_profile.html.haml
@@ -8,6 +8,11 @@
= link_to profile_account_path do
%i.fa.fa-gear
Account
+ = nav_link(path: ['profiles#applications', 'applications#edit', 'applications#show', 'applications#new']) do
+ = link_to applications_profile_path do
+ %i.fa.fa-cloud
+ %span
+ Applications
= nav_link(controller: :emails) do
= link_to profile_emails_path do
%i.fa.fa-envelope-o
diff --git a/app/views/layouts/project_settings.html.haml b/app/views/layouts/project_settings.html.haml
index 810fb4e2005..0f20bf38bfd 100644
--- a/app/views/layouts/project_settings.html.haml
+++ b/app/views/layouts/project_settings.html.haml
@@ -5,8 +5,5 @@
= render "layouts/broadcast"
= render "layouts/head_panel", title: project_title(@project)
= render "layouts/init_auto_complete"
- - if can?(current_user, :download_code, @project)
- = render 'shared/no_ssh'
-
- @project_settings_nav = true
= render 'layouts/page', sidebar: 'layouts/nav/project'
diff --git a/app/views/layouts/projects.html.haml b/app/views/layouts/projects.html.haml
index b4b1bcf241c..d4ee53db55c 100644
--- a/app/views/layouts/projects.html.haml
+++ b/app/views/layouts/projects.html.haml
@@ -5,6 +5,4 @@
= render "layouts/broadcast"
= render "layouts/head_panel", title: project_title(@project)
= render "layouts/init_auto_complete"
- - if can?(current_user, :download_code, @project)
- = render 'shared/no_ssh'
= render 'layouts/page', sidebar: 'layouts/nav/project'
diff --git a/app/views/notify/repository_push_email.html.haml b/app/views/notify/repository_push_email.html.haml
index 3cf50bf0826..d678147ec5d 100644
--- a/app/views/notify/repository_push_email.html.haml
+++ b/app/views/notify/repository_push_email.html.haml
@@ -6,7 +6,9 @@
- @commits.each do |commit|
%li
%strong #{link_to commit.short_id, project_commit_url(@project, commit)}
- %span by #{commit.author_name}
+ %div
+ %span by #{commit.author_name}
+ %i at #{commit.committed_date.strftime("%Y-%m-%dT%H:%M:%SZ")}
%pre #{commit.safe_message}
%h4 Changes:
diff --git a/app/views/profiles/accounts/show.html.haml b/app/views/profiles/accounts/show.html.haml
index a21dcff41c0..53a50f6796b 100644
--- a/app/views/profiles/accounts/show.html.haml
+++ b/app/views/profiles/accounts/show.html.haml
@@ -75,3 +75,4 @@
The following groups will be abandoned. You should transfer or remove them:
%strong #{current_user.solo_owned_groups.map(&:name).join(', ')}
= link_to 'Delete account', user_registration_path, data: { confirm: "REMOVE #{current_user.name}? Are you sure?" }, method: :delete, class: "btn btn-remove"
+
diff --git a/app/views/profiles/applications.html.haml b/app/views/profiles/applications.html.haml
new file mode 100644
index 00000000000..cb24e4a3dde
--- /dev/null
+++ b/app/views/profiles/applications.html.haml
@@ -0,0 +1,47 @@
+%h3.page-title
+ OAuth2
+
+%fieldset.oauth-applications
+ %legend Your applications
+ %p= link_to 'New Application', new_oauth_application_path, class: 'btn btn-success'
+ - if @applications.any?
+ %table.table.table-striped
+ %thead
+ %tr
+ %th Name
+ %th Callback URL
+ %th Clients
+ %th
+ %th
+ %tbody
+ - @applications.each do |application|
+ %tr{:id => "application_#{application.id}"}
+ %td= link_to application.name, oauth_application_path(application)
+ %td
+ - application.redirect_uri.split.each do |uri|
+ %div= uri
+ %td= application.access_tokens.count
+ %td= link_to 'Edit', edit_oauth_application_path(application), class: 'btn btn-link btn-small'
+ %td= render 'doorkeeper/applications/delete_form', application: application
+
+%fieldset.oauth-authorized-applications.prepend-top-20
+ %legend Authorized applications
+
+ - if @authorized_tokens.any?
+ %table.table.table-striped
+ %thead
+ %tr
+ %th Name
+ %th Authorized At
+ %th Scope
+ %th
+ %tbody
+ - @authorized_tokens.each do |token|
+ - application = token.application
+ %tr{:id => "application_#{application.id}"}
+ %td= application.name
+ %td= token.created_at
+ %td= token.scopes
+ %td= render 'doorkeeper/authorized_applications/delete_form', application: application
+ - else
+ %p.light You dont have any authorized applications
diff --git a/app/views/projects/diffs/_diffs.html.haml b/app/views/projects/diffs/_diffs.html.haml
index 334ea1ba82f..48d4c33ce85 100644
--- a/app/views/projects/diffs/_diffs.html.haml
+++ b/app/views/projects/diffs/_diffs.html.haml
@@ -2,15 +2,9 @@
.col-md-8
= render 'projects/diffs/stats', diffs: diffs
.col-md-4
- %ul.nav.nav-tabs
- %li.pull-right{class: params[:view] == 'parallel' ? 'active' : ''}
- - params_copy = params.dup
- - params_copy[:view] = 'parallel'
- = link_to "Side-by-side Diff", url_for(params_copy), {id: "commit-diff-viewtype"}
- %li.pull-right{class: params[:view] != 'parallel' ? 'active' : ''}
- - params_copy[:view] = 'inline'
- = link_to "Inline Diff", url_for(params_copy), {id: "commit-diff-viewtype"}
-
+ .btn-group.pull-right
+ = inline_diff_btn
+ = parallel_diff_btn
- if show_diff_size_warning?(diffs)
= render 'projects/diffs/warning', diffs: diffs
diff --git a/app/views/projects/issues/_discussion.html.haml b/app/views/projects/issues/_discussion.html.haml
new file mode 100644
index 00000000000..ec03f375d6b
--- /dev/null
+++ b/app/views/projects/issues/_discussion.html.haml
@@ -0,0 +1,37 @@
+- content_for :note_actions do
+ - if can?(current_user, :modify_issue, @issue)
+ - if @issue.closed?
+ = link_to 'Reopen Issue', project_issue_path(@project, @issue, issue: {state_event: :reopen }, status_only: true), method: :put, class: "btn btn-grouped btn-reopen js-note-target-reopen", title: 'Reopen Issue'
+ - else
+ = link_to 'Close Issue', project_issue_path(@project, @issue, issue: {state_event: :close }, status_only: true), method: :put, class: "btn btn-grouped btn-close js-note-target-close", title: "Close Issue"
+.row
+ .col-md-9
+ .participants
+ %cite.cgray
+ = pluralize(@issue.participants.count, 'participant')
+ - @issue.participants.each do |participant|
+ = link_to_member(@project, participant, name: false, size: 24)
+
+ .voting_notes#notes= render "projects/notes/notes_with_form"
+ .col-md-3.hidden-sm.hidden-xs
+ %div
+ .clearfix
+ %span.slead.has_tooltip{:"data-original-title" => 'Cross-project reference'}
+ = cross_project_reference(@project, @issue)
+ %hr
+ .clearfix
+ .votes-holder
+ %h6 Votes
+ #votes= render 'votes/votes_block', votable: @issue
+ %hr
+ .context
+ %cite.cgray
+ = render partial: 'issue_context', locals: { issue: @issue }
+
+ - if @issue.labels.any?
+ %hr
+ %h6 Labels
+ .issue-show-labels
+ - @issue.labels.each do |label|
+ = link_to project_issues_path(@project, label_name: label.name) do
+ %p= render_colored_label(label)
diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml
index 1c9af4c4501..b21a394ebeb 100644
--- a/app/views/projects/issues/show.html.haml
+++ b/app/views/projects/issues/show.html.haml
@@ -1,65 +1,37 @@
-%h3.page-title
+%h4.page-title
.issue-box{ class: issue_box_class(@issue) }
- if @issue.closed?
Closed
- else
Open
Issue ##{@issue.iid}
- .pull-right.creator
- %small Created by #{link_to_member(@project, @issue.author)} #{issue_timestamp(@issue)}
-%hr
-.row
- .col-sm-9
- %h3.issue-title
- = gfm escape_once(@issue.title)
- %div
- - if @issue.description.present?
- .description
- .wiki
- = preserve do
- = markdown(@issue.description, parse_tasks: true)
- %hr
- - content_for :note_actions do
- - if can?(current_user, :modify_issue, @issue)
- - if @issue.closed?
- = link_to 'Reopen Issue', project_issue_path(@project, @issue, issue: {state_event: :reopen }, status_only: true), method: :put, class: "btn btn-grouped btn-reopen js-note-target-reopen", title: 'Reopen Issue'
- - else
- = link_to 'Close Issue', project_issue_path(@project, @issue, issue: {state_event: :close }, status_only: true), method: :put, class: "btn btn-grouped btn-close js-note-target-close", title: "Close Issue"
- .participants
- %cite.cgray
- = pluralize(@issue.participants.count, 'participant')
- - @issue.participants.each do |participant|
- = link_to_member(@project, participant, name: false, size: 24)
- .issue-show-labels.pull-right
- - @issue.labels.each do |label|
- = link_to project_issues_path(@project, label_name: label.name) do
- = render_colored_label(label)
+ %small.creator
+ &middot; created by #{link_to_member(@project, @issue.author)} #{issue_timestamp(@issue)}
+
+ .pull-right
+ - if can?(current_user, :write_issue, @project)
+ = link_to new_project_issue_path(@project), class: "btn btn-grouped", title: "New Issue", id: "new_issue_link" do
+ %i.fa.fa-plus
+ New Issue
+ - if can?(current_user, :modify_issue, @issue)
+ - if @issue.closed?
+ = link_to 'Reopen', project_issue_path(@project, @issue, issue: {state_event: :reopen }, status_only: true), method: :put, class: "btn btn-grouped btn-reopen"
+ - else
+ = link_to 'Close', project_issue_path(@project, @issue, issue: {state_event: :close }, status_only: true), method: :put, class: "btn btn-grouped btn-close", title: "Close Issue"
- .voting_notes#notes= render "projects/notes/notes_with_form"
- .col-sm-3
- %div
- - if can?(current_user, :write_issue, @project)
- = link_to new_project_issue_path(@project), class: "btn btn-block", title: "New Issue", id: "new_issue_link" do
- %i.fa.fa-plus
- New Issue
- - if can?(current_user, :modify_issue, @issue)
- - if @issue.closed?
- = link_to 'Reopen', project_issue_path(@project, @issue, issue: {state_event: :reopen }, status_only: true), method: :put, class: "btn btn-block btn-reopen"
- - else
- = link_to 'Close', project_issue_path(@project, @issue, issue: {state_event: :close }, status_only: true), method: :put, class: "btn btn-block btn-close", title: "Close Issue"
+ = link_to edit_project_issue_path(@project, @issue), class: "btn btn-grouped issuable-edit" do
+ %i.fa.fa-pencil-square-o
+ Edit
- = link_to edit_project_issue_path(@project, @issue), class: "btn btn-block issuable-edit" do
- %i.fa.fa-pencil-square-o
- Edit
- .clearfix
- %span.slead.has_tooltip{:"data-original-title" => 'Cross-project reference'}
- = cross_project_reference(@project, @issue)
- %hr
- .clearfix
- .votes-holder
- %h6 Votes
- #votes= render 'votes/votes_block', votable: @issue
- %hr
- .context
- %cite.cgray
- = render partial: 'issue_context', locals: { issue: @issue }
+%hr
+%h3.issue-title
+ = gfm escape_once(@issue.title)
+%div
+ - if @issue.description.present?
+ .description
+ .wiki
+ = preserve do
+ = markdown(@issue.description, parse_tasks: true)
+
+%hr
+= render "projects/issues/discussion"
diff --git a/app/views/projects/merge_requests/_discussion.html.haml b/app/views/projects/merge_requests/_discussion.html.haml
new file mode 100644
index 00000000000..6bb5c465596
--- /dev/null
+++ b/app/views/projects/merge_requests/_discussion.html.haml
@@ -0,0 +1,31 @@
+- content_for :note_actions do
+ - if can?(current_user, :modify_merge_request, @merge_request)
+ - if @merge_request.open?
+ = link_to 'Close', project_merge_request_path(@project, @merge_request, merge_request: {state_event: :close }), method: :put, class: "btn btn-grouped btn-close close-mr-link js-note-target-close", title: "Close merge request"
+ - if @merge_request.closed?
+ = link_to 'Reopen', project_merge_request_path(@project, @merge_request, merge_request: {state_event: :reopen }), method: :put, class: "btn btn-grouped btn-reopen reopen-mr-link js-note-target-reopen", title: "Reopen merge request"
+
+.row
+ .col-md-9
+ = render "projects/merge_requests/show/participants"
+ = render "projects/notes/notes_with_form"
+ .col-md-3.hidden-sm.hidden-xs
+ .clearfix
+ %span.slead.has_tooltip{:"data-original-title" => 'Cross-project reference'}
+ = cross_project_reference(@project, @merge_request)
+ %hr
+ .votes-holder.hidden-sm.hidden-xs
+ %h6 Votes
+ #votes= render 'votes/votes_block', votable: @merge_request
+ %hr
+ .context
+ %cite.cgray
+ = render partial: 'projects/merge_requests/show/context', locals: { merge_request: @merge_request }
+
+ - if @merge_request.labels.any?
+ %hr
+ %h6 Labels
+ .merge-request-show-labels
+ - @merge_request.labels.each do |label|
+ = link_to project_merge_requests_path(@project, label_name: label.name) do
+ %p= render_colored_label(label)
diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml
index 57ab6bdd545..74ef819a7aa 100644
--- a/app/views/projects/merge_requests/_show.html.haml
+++ b/app/views/projects/merge_requests/_show.html.haml
@@ -1,89 +1,64 @@
.merge-request
= render "projects/merge_requests/show/mr_title"
%hr
- .row
- .col-sm-9
- = render "projects/merge_requests/show/how_to_merge"
- = render "projects/merge_requests/show/mr_box"
- %hr
- .append-bottom-20
- %p.slead
- %span From
- - if @merge_request.for_fork?
- %strong.label-branch<
- - if @merge_request.source_project
- = link_to @merge_request.source_project_namespace, project_path(@merge_request.source_project)
- - else
- \ #{@merge_request.source_project_namespace}
- \:#{@merge_request.source_branch}
- %span into
- %strong.label-branch #{@merge_request.target_project_namespace}:#{@merge_request.target_branch}
+ = render "projects/merge_requests/show/mr_box"
+ %hr
+ .append-bottom-20
+ .slead
+ %span From
+ - if @merge_request.for_fork?
+ %strong.label-branch<
+ - if @merge_request.source_project
+ = link_to @merge_request.source_project_namespace, project_path(@merge_request.source_project)
- else
- %strong.label-branch #{@merge_request.source_branch}
- %span into
- %strong.label-branch #{@merge_request.target_branch}
- = render "projects/merge_requests/show/state_widget"
- = render "projects/merge_requests/show/commits"
- = render "projects/merge_requests/show/participants"
+ \ #{@merge_request.source_project_namespace}
+ \:#{@merge_request.source_branch}
+ %span into
+ %strong.label-branch #{@merge_request.target_project_namespace}:#{@merge_request.target_branch}
+ - else
+ %strong.label-branch #{@merge_request.source_branch}
+ %span into
+ %strong.label-branch #{@merge_request.target_branch}
+ - if @merge_request.open?
+ %span.pull-right
+ .btn-group
+ %a.btn.dropdown-toggle{ data: {toggle: :dropdown} }
+ %i.fa.fa-download
+ Download as
+ %span.caret
+ %ul.dropdown-menu
+ %li= link_to "Email Patches", project_merge_request_path(@project, @merge_request, format: :patch)
+ %li= link_to "Plain Diff", project_merge_request_path(@project, @merge_request, format: :diff)
- .col-sm-3
- .issue-btn-group
- - if can?(current_user, :modify_merge_request, @merge_request)
- - if @merge_request.open?
- .btn-group-justified.append-bottom-20
- .btn-group
- %a.btn.dropdown-toggle{ data: {toggle: :dropdown} }
- %i.fa.fa-download
- Download as
- %span.caret
- %ul.dropdown-menu
- %li= link_to "Email Patches", project_merge_request_path(@project, @merge_request, format: :patch)
- %li= link_to "Plain Diff", project_merge_request_path(@project, @merge_request, format: :diff)
- = link_to 'Close', project_merge_request_path(@project, @merge_request, merge_request: { state_event: :close }), method: :put, class: "btn btn-block btn-close", title: "Close merge request"
- = link_to edit_project_merge_request_path(@project, @merge_request), class: "btn btn-block issuable-edit", id: "edit_merge_request" do
- %i.fa.fa-pencil-square-o
- Edit
- - if @merge_request.closed?
- = link_to 'Reopen', project_merge_request_path(@project, @merge_request, merge_request: {state_event: :reopen }), method: :put, class: "btn btn-block btn-reopen reopen-mr-link", title: "Close merge request"
- .clearfix
- %span.slead.has_tooltip{:"data-original-title" => 'Cross-project reference'}
- = cross_project_reference(@project, @merge_request)
- %hr
- .votes-holder.hidden-sm.hidden-xs
- %h6 Votes
- #votes= render 'votes/votes_block', votable: @merge_request
- %hr
- .context
- %cite.cgray
- = render partial: 'projects/merge_requests/show/context', locals: { merge_request: @merge_request }
+ = render "projects/merge_requests/show/how_to_merge"
+ = render "projects/merge_requests/show/state_widget"
- if @commits.present?
%ul.nav.nav-tabs.merge-request-tabs
%li.notes-tab{data: {action: 'notes'}}
= link_to project_merge_request_path(@project, @merge_request) do
- %i.fa.fa-comment
+ %i.fa.fa-comments
Discussion
%span.badge= @merge_request.mr_and_commit_notes.count
+ %li.commits-tab{data: {action: 'commits'}}
+ = link_to project_merge_request_path(@project, @merge_request), title: 'Commits' do
+ %i.fa.fa-database
+ Commits
+ %span.badge= @commits.size
%li.diffs-tab{data: {action: 'diffs'}}
= link_to diffs_project_merge_request_path(@project, @merge_request) do
%i.fa.fa-list-alt
Changes
%span.badge= @merge_request.diffs.size
- - content_for :note_actions do
- - if can?(current_user, :modify_merge_request, @merge_request)
- - if @merge_request.open?
- = link_to 'Close', project_merge_request_path(@project, @merge_request, merge_request: {state_event: :close }), method: :put, class: "btn btn-grouped btn-close close-mr-link js-note-target-close", title: "Close merge request"
- - if @merge_request.closed?
- = link_to 'Reopen', project_merge_request_path(@project, @merge_request, merge_request: {state_event: :reopen }), method: :put, class: "btn btn-grouped btn-reopen reopen-mr-link js-note-target-reopen", title: "Reopen merge request"
-
+ .notes.tab-content.voting_notes#notes{ class: (controller.action_name == 'show') ? "" : "hide" }
+ = render "projects/merge_requests/discussion"
+ .commits.tab-content
+ = render "projects/merge_requests/show/commits"
.diffs.tab-content
- if current_page?(action: 'diffs')
= render "projects/merge_requests/show/diffs"
- .notes.tab-content.voting_notes#notes{ class: (controller.action_name == 'show') ? "" : "hide" }
- .row
- .col-sm-9
- = render "projects/notes/notes_with_form"
+
.mr-loading-status
= spinner
diff --git a/app/views/projects/merge_requests/show/_mr_title.html.haml b/app/views/projects/merge_requests/show/_mr_title.html.haml
index fb34de43c1b..0f20eba382c 100644
--- a/app/views/projects/merge_requests/show/_mr_title.html.haml
+++ b/app/views/projects/merge_requests/show/_mr_title.html.haml
@@ -1,4 +1,4 @@
-%h3.page-title
+%h4.page-title
.issue-box{ class: issue_box_class(@merge_request) }
- if @merge_request.merged?
Merged
@@ -7,5 +7,16 @@
- else
Open
= "Merge Request ##{@merge_request.iid}"
- .pull-right.creator
- %small Created by #{link_to_member(@project, @merge_request.author)} #{time_ago_with_tooltip(@merge_request.created_at)}
+ %small.creator
+ &middot;
+ created by #{link_to_member(@project, @merge_request.author)} #{time_ago_with_tooltip(@merge_request.created_at)}
+
+ .issue-btn-group.pull-right
+ - if can?(current_user, :modify_merge_request, @merge_request)
+ - if @merge_request.open?
+ = link_to 'Close', project_merge_request_path(@project, @merge_request, merge_request: { state_event: :close }), method: :put, class: "btn btn-grouped btn-close", title: "Close merge request"
+ = link_to edit_project_merge_request_path(@project, @merge_request), class: "btn btn-grouped issuable-edit", id: "edit_merge_request" do
+ %i.fa.fa-pencil-square-o
+ Edit
+ - if @merge_request.closed?
+ = link_to 'Reopen', project_merge_request_path(@project, @merge_request, merge_request: {state_event: :reopen }), method: :put, class: "btn btn-grouped btn-reopen reopen-mr-link", title: "Close merge request"
diff --git a/app/views/projects/merge_requests/show/_participants.html.haml b/app/views/projects/merge_requests/show/_participants.html.haml
index b709c89cec2..15a97404cb0 100644
--- a/app/views/projects/merge_requests/show/_participants.html.haml
+++ b/app/views/projects/merge_requests/show/_participants.html.haml
@@ -2,8 +2,3 @@
%cite.cgray #{@merge_request.participants.count} participants
- @merge_request.participants.each do |participant|
= link_to_member(@project, participant, name: false, size: 24)
-
- .merge-request-show-labels.pull-right
- - @merge_request.labels.each do |label|
- = link_to project_merge_requests_path(@project, label_name: label.name) do
- = render_colored_label(label)
diff --git a/app/views/projects/milestones/show.html.haml b/app/views/projects/milestones/show.html.haml
index cd62e4811ac..031b5a31895 100644
--- a/app/views/projects/milestones/show.html.haml
+++ b/app/views/projects/milestones/show.html.haml
@@ -1,5 +1,5 @@
= render "projects/issues_nav"
-%h3.page-title
+%h4.page-title
.issue-box{ class: issue_box_class(@milestone) }
- if @milestone.closed?
Closed
@@ -8,52 +8,44 @@
- else
Open
Milestone ##{@milestone.iid}
- .pull-right.creator
- %small= @milestone.expires_at
+ %small.creator
+ = @milestone.expires_at
+ .pull-right
+ - if can?(current_user, :admin_milestone, @project)
+ = link_to edit_project_milestone_path(@project, @milestone), class: "btn btn-grouped" do
+ %i.fa.fa-pencil-square-o
+ Edit
+ - if @milestone.active?
+ = link_to 'Close Milestone', project_milestone_path(@project, @milestone, milestone: {state_event: :close }), method: :put, class: "btn btn-close btn-grouped"
+ - else
+ = link_to 'Reopen Milestone', project_milestone_path(@project, @milestone, milestone: {state_event: :activate }), method: :put, class: "btn btn-reopen btn-grouped"
%hr
- if @milestone.issues.any? && @milestone.can_be_closed?
.alert.alert-success
%span All issues for this milestone are closed. You may close milestone now.
-.row
- .col-sm-9
- %h3.issue-title
- = gfm escape_once(@milestone.title)
- %div
- - if @milestone.description.present?
- .description
- .wiki
- = preserve do
- = markdown @milestone.description
-
- %hr
- .context
- %p.lead
- Progress:
- #{@milestone.closed_items_count} closed
- &ndash;
- #{@milestone.open_items_count} open
- &nbsp;
- %span.light #{@milestone.percent_complete}% complete
- %span.pull-right= @milestone.expires_at
- .progress.progress-info
- .progress-bar{style: "width: #{@milestone.percent_complete}%;"}
- .col-sm-3
- %div
- - if can?(current_user, :admin_milestone, @project)
- = link_to edit_project_milestone_path(@project, @milestone), class: "btn btn-block" do
- %i.fa.fa-pencil-square-o
- Edit
- - if @milestone.active?
- = link_to 'Close Milestone', project_milestone_path(@project, @milestone, milestone: {state_event: :close }), method: :put, class: "btn btn-close btn-block"
- - else
- = link_to 'Reopen Milestone', project_milestone_path(@project, @milestone, milestone: {state_event: :activate }), method: :put, class: "btn btn-reopen btn-block"
- = link_to new_project_issue_path(@project, issue: { milestone_id: @milestone.id }), class: "btn btn-block", title: "New Issue" do
- %i.fa.fa-plus
- New Issue
- = link_to 'Browse Issues', project_issues_path(@milestone.project, milestone_id: @milestone.id), class: "btn edit-milestone-link btn-block"
+%h3.issue-title
+ = gfm escape_once(@milestone.title)
+%div
+ - if @milestone.description.present?
+ .description
+ .wiki
+ = preserve do
+ = markdown @milestone.description
+%hr
+.context
+ %p.lead
+ Progress:
+ #{@milestone.closed_items_count} closed
+ &ndash;
+ #{@milestone.open_items_count} open
+ &nbsp;
+ %span.light #{@milestone.percent_complete}% complete
+ %span.pull-right= @milestone.expires_at
+ .progress.progress-info
+ .progress-bar{style: "width: #{@milestone.percent_complete}%;"}
%ul.nav.nav-tabs
@@ -71,6 +63,10 @@
%span.badge= @users.count
.pull-right
+ = link_to new_project_issue_path(@project, issue: { milestone_id: @milestone.id }), class: "btn btn-grouped", title: "New Issue" do
+ %i.fa.fa-plus
+ New Issue
+ = link_to 'Browse Issues', project_issues_path(@milestone.project, milestone_id: @milestone.id), class: "btn edit-milestone-link btn-grouped"
.tab-content
.tab-pane.active#tab-issues
diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml
index 9b06ebe95a4..af6e4567c1b 100644
--- a/app/views/projects/show.html.haml
+++ b/app/views/projects/show.html.haml
@@ -1,3 +1,6 @@
+- if current_user && can?(current_user, :download_code, @project)
+ = render 'shared/no_ssh'
+
= render "home_panel"
- readme = @repository.readme
diff --git a/app/views/shared/_no_ssh.html.haml b/app/views/shared/_no_ssh.html.haml
index e70eb4d01b9..8e6f802fd3b 100644
--- a/app/views/shared/_no_ssh.html.haml
+++ b/app/views/shared/_no_ssh.html.haml
@@ -1,14 +1,8 @@
- if cookies[:hide_no_ssh_message].blank? && current_user.require_ssh_key? && !current_user.hide_no_ssh_key
- .no-ssh-key-message
- .container
- You won't be able to pull or push project code via SSH until you #{link_to 'add an SSH key', new_profile_key_path} to your profile
- .pull-right.hidden-xs
- = link_to "Don't show again", profile_path(user: {hide_no_ssh_key: true}), method: :put, class: 'hide-no-ssh-message', remote: true
- |
- = link_to 'Remind later', '#', class: 'hide-no-ssh-message'
- .links-xs.visible-xs
- = link_to "Add key", new_profile_key_path
- |
- = link_to "Don't show again", profile_path(user: {hide_no_ssh_key: true}), method: :put, class: 'hide-no-ssh-message', remote: true
- |
- = link_to 'Later', '#', class: 'hide-no-ssh-message'
+ .no-ssh-key-message.alert.alert-warning.hidden-xs
+ You won't be able to pull or push project code via SSH until you #{link_to 'add an SSH key', new_profile_key_path} to your profile
+
+ .pull-right
+ = link_to "Don't show again", profile_path(user: {hide_no_ssh_key: true}), method: :put
+ |
+ = link_to 'Remind later', '#', class: 'hide-no-ssh-message'