Merge branch 'master' of dev.gitlab.org:gitlab/gitlabhq into ce-to-ee

Signed-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>
This commit is contained in:
Dmitriy Zaporozhets
2015-08-26 17:15:12 +02:00
219 changed files with 5159 additions and 816 deletions
+1
View File
@@ -25,6 +25,7 @@ config/initializers/rack_attack.rb
config/initializers/smtp_settings.rb
config/resque.yml
config/unicorn.rb
config/mail_room.yml
coverage/*
db/*.sqlite3
db/*.sqlite3-journal
+23
View File
@@ -1,12 +1,34 @@
Please view this file on the master branch, on stable branches it's out of date.
v 8.0.0 (unreleased)
- Improve dropdown positioning on the project home page (Hannes Rosenögger)
- Upgrade browser gem to 1.0.0 to avoid warning in IE11 compatibilty mode (Stan Hu)
- Fix "Reload with full diff" URL button in compare branch view (Stan Hu)
- Remove user OAuth tokens from the database and request new tokens each session (Stan Hu)
- Only show recent push event if the branch still exists or a recent merge request has not been created (Stan Hu)
- Remove satellites
- Better performance for web editor (switched from satellites to rugged)
- Faster merge
- Ability to fetch merge requests from refs/merge-requests/:id
v 7.14.0
- Allow displaying of archived projects in the admin interface (Artem Sidorenko)
- Allow configuration of import sources for new projects (Artem Sidorenko)
- Search for comments should be case insensetive
- Create cross-reference for closing references on commits pushed to non-default branches (Maël Valais)
- Ability to search milestones
- Gracefully handle SMTP user input errors (e.g. incorrect email addresses) to prevent Sidekiq retries (Stan Hu)
- Improve abuse reports management from admin area
- Move dashboard activity to separate page
- Improve performance of git blame
- Limit content width to 1200px for most of pages to improve readability on big screens
v 7.14.1 (unreleased)
- Only include base URL in OmniAuth full_host parameter (Stan Hu)
- Fix Error 500 in API when accessing a group that has an avatar (Stan Hu)
v 7.14.0
- Fix bug where non-project members of the target project could set labels on new merge requests.
- Update default robots.txt rules to disallow crawling of irrelevant pages (Ben Bodenmiller)
- Fix redirection after sign in when using auto_sign_in_with_provider
- Upgrade gitlab_git to 7.2.14 to ignore CRLFs in .gitmodules (Stan Hu)
@@ -295,6 +317,7 @@ v 7.11.0
- Protect OmniAuth request phase against CSRF.
- Don't send notifications to mentioned users that don't have access to the project in question.
- Add search issues/MR by number
- Change plots to bar graphs in commit statistics screen
- Move snippets UI to fluid layout
- Improve UI for sidebar. Increase separation between navigation and content
- Improve new project command options (Ben Bodenmiller)
+5 -1
View File
@@ -35,7 +35,7 @@ gem 'rqrcode-rails3'
gem 'attr_encrypted', '1.3.4'
# Browser detection
gem "browser", '~> 0.8.0'
gem "browser", '~> 1.0.0'
# Extracting information from a git repository
# Provide access to Gitlab::Git library
@@ -276,3 +276,7 @@ end
gem "newrelic_rpm"
gem 'octokit', '3.7.0'
gem "mail_room", "~> 0.4.0"
gem 'email_reply_parser'
+6 -2
View File
@@ -76,7 +76,7 @@ GEM
ruby_parser (~> 3.5.0)
sass (~> 3.0)
terminal-table (~> 1.4)
browser (0.8.0)
browser (1.0.0)
builder (3.2.2)
byebug (3.2.0)
columnize (~> 0.8)
@@ -156,6 +156,7 @@ GEM
dotenv (0.9.0)
dropzonejs-rails (0.7.1)
rails (> 3.1)
email_reply_parser (0.5.8)
email_spec (1.6.0)
launchy (~> 2.1)
mail (~> 2.2)
@@ -374,6 +375,7 @@ GEM
systemu (~> 2.6.2)
mail (2.6.3)
mime-types (>= 1.16, < 3)
mail_room (0.4.0)
method_source (0.8.2)
mime-types (1.25.1)
mimemagic (0.3.0)
@@ -756,7 +758,7 @@ DEPENDENCIES
binding_of_caller
bootstrap-sass (~> 3.0)
brakeman
browser (~> 0.8.0)
browser (~> 1.0.0)
byebug
cal-heatmap-rails (~> 0.0.1)
capybara (~> 2.4.0)
@@ -776,6 +778,7 @@ DEPENDENCIES
diffy (~> 3.0.3)
doorkeeper (= 2.1.3)
dropzonejs-rails
email_reply_parser
email_spec (~> 1.6.0)
enumerize
factory_girl_rails
@@ -810,6 +813,7 @@ DEPENDENCIES
jquery-ui-rails
kaminari (~> 0.15.1)
letter_opener
mail_room (~> 0.4.0)
minitest (~> 5.3.0)
mousetrap-rails
mysql2
+2 -1
View File
@@ -1,2 +1,3 @@
web: bundle exec unicorn_rails -p ${PORT:="3000"} -E ${RAILS_ENV:="development"} -c ${UNICORN_CONFIG:="config/unicorn.rb"}
worker: bundle exec sidekiq -q post_receive -q mailer -q archive_repo -q system_hook -q project_web_hook -q gitlab_shell -q common -q default
worker: bundle exec sidekiq -q post_receive -q mailer -q archive_repo -q system_hook -q project_web_hook -q gitlab_shell -q incoming_email -q common -q default
# mail_room: bundle exec mail_room -q -c config/mail_room.yml
@@ -118,6 +118,12 @@ $ ->
$('.remove-row').bind 'ajax:success', ->
$(this).closest('li').fadeOut()
$('.js-remove-tr').bind 'ajax:before', ->
$(this).hide()
$('.js-remove-tr').bind 'ajax:success', ->
$(this).closest('tr').fadeOut()
# Initialize select2 selects
$('select.select2').select2(width: 'resolve', dropdownAutoWidth: true)
@@ -119,8 +119,9 @@ class @ImageFile
requestImageInfo: (img, callback) ->
domImg = img.get(0)
if domImg.complete
callback.call(this, domImg.naturalWidth, domImg.naturalHeight)
else
img.on 'load', =>
if domImg
if domImg.complete
callback.call(this, domImg.naturalWidth, domImg.naturalHeight)
else
img.on 'load', =>
callback.call(this, domImg.naturalWidth, domImg.naturalHeight)
@@ -51,6 +51,7 @@ class Dispatcher
MergeRequests.init()
when 'dashboard:show', 'root:show'
new Dashboard()
when 'dashboard:activity'
new Activities()
when 'dashboard:projects:starred'
new Activities()
@@ -8,7 +8,7 @@ class @ProjectsList
$(".projects-list-filter").keyup ->
terms = $(this).val()
uiBox = $(this).closest('.panel')
uiBox = $(this).closest('.projects-list-holder')
if terms == "" || terms == undefined
uiBox.find(".projects-list li").show()
else
@@ -7,6 +7,7 @@ class @UsersSelect
@skipLdap = $(select).hasClass('skip_ldap')
@projectId = $(select).data('project-id')
@groupId = $(select).data('group-id')
@showCurrentUser = $(select).data('current-user')
showNullUser = $(select).data('null-user')
showAnyUser = $(select).data('any-user')
showEmailUser = $(select).data('email-user')
@@ -110,6 +111,7 @@ class @UsersSelect
project_id: @projectId
group_id: @groupId
skip_ldap: @skipLdap
current_user: @showCurrentUser
dataType: "json"
).done (users) ->
callback(users)
+5
View File
@@ -20,3 +20,8 @@ html {
.navless-container {
margin-top: 30px;
}
.container-limited {
max-width: $fixed-layout-width;
}
+1 -1
View File
@@ -13,7 +13,7 @@ $code_line_height: 1.5;
$border-color: #E5E5E5;
$background-color: #f5f5f5;
$header-height: 50px;
$readable-width: 1100px;
$fixed-layout-width: 1200px;
/*
@@ -382,3 +382,23 @@ table {
border-color: #EEE !important;
}
}
.center-top-menu {
border-bottom: 1px solid #EEE;
list-style: none;
text-align: center;
padding-bottom: 15px;
margin-bottom: 15px;
li {
display: inline-block;
a {
padding: 10px;
}
&.active a {
color: #666;
}
}
}
+6 -60
View File
@@ -20,16 +20,16 @@ header {
}
&.navbar-gitlab {
padding: 0 20px;
z-index: 100;
margin-bottom: 0;
min-height: $header-height;
border: none;
width: 100%;
border-bottom: 1px solid #EEE;
.container {
.container-fluid {
background: #FFF;
width: 100% !important;
padding: 0;
filter: none;
.nav > li > a {
@@ -64,55 +64,11 @@ header {
}
}
.header-logo {
border-bottom: 1px solid transparent;
float: left;
height: $header-height;
width: $sidebar_width;
overflow: hidden;
transition-duration: .3s;
a {
float: left;
height: $header-height;
width: 100%;
padding: ($header-height - 36 ) / 2 8px;
overflow: hidden;
img {
width: 36px;
height: 36px;
float: left;
}
.gitlab-text-container {
width: 230px;
h3 {
width: 158px;
float: left;
margin: 0;
margin-left: 14px;
font-size: 18px;
line-height: $header-height - 14;
font-weight: normal;
}
}
}
&:hover {
background-color: #EEE;
}
}
.header-content {
border-bottom: 1px solid #EEE;
padding-right: 35px;
height: $header-height;
.title {
margin: 0;
padding: 0 15px 0 35px;
overflow: hidden;
font-size: 18px;
line-height: $header-height;
@@ -168,15 +124,7 @@ header {
}
@mixin collapsed-header {
.header-logo {
width: $sidebar_collapsed_width;
}
.header-content {
.title {
margin-left: 30px;
}
}
margin-left: $sidebar_collapsed_width;
}
@media (max-width: $screen-md-max) {
@@ -191,16 +139,14 @@ header {
}
.header-expanded {
margin-left: $sidebar_width;
}
}
@media (max-width: $screen-xs-max) {
header .container {
header .container-fluid {
font-size: 18px;
.title {
}
.navbar-nav {
margin: 0px;
float: none !important;
@@ -188,3 +188,46 @@
width: $sidebar_width - 2 * 10px;
}
}
.sidebar-wrapper {
.header-logo {
border-bottom: 1px solid transparent;
float: left;
height: $header-height;
width: $sidebar_width;
overflow: hidden;
transition-duration: .3s;
a {
float: left;
height: $header-height;
width: 100%;
padding: ($header-height - 36 ) / 2 8px;
overflow: hidden;
img {
width: 36px;
height: 36px;
float: left;
}
.gitlab-text-container {
width: 230px;
h3 {
width: 158px;
float: left;
margin: 0;
margin-left: 14px;
font-size: 18px;
line-height: $header-height - 14;
font-weight: normal;
}
}
}
&:hover {
background-color: #EEE;
}
}
}
+1 -37
View File
@@ -23,41 +23,6 @@
}
}
.project-row, .group-row {
padding: 0 !important;
font-size: 14px;
line-height: 24px;
a {
display: block;
padding: 8px 15px;
}
.project-name, .group-name {
font-weight: 500;
}
.arrow {
float: right;
margin: 0;
font-size: 20px;
}
.last-activity {
float: right;
font-size: 12px;
color: #AAA;
display: block;
.date {
color: #777;
}
}
}
.project-description {
overflow: hidden;
}
.project-access-icon {
margin-left: 10px;
float: left;
@@ -73,10 +38,9 @@
float: left;
.avatar {
margin-top: -8px;
margin-left: -15px;
@include border-radius(0px);
}
.identicon {
line-height: 40px;
}
@@ -6,3 +6,11 @@
font-size: 30px;
}
}
.explore-trending-block {
.lead {
line-height: 32px;
font-size: 18px;
margin-top: 10px;
}
}
@@ -45,9 +45,3 @@
.btn { font-size: 13px; }
}
.issuable-details {
.description {
max-width: $readable-width;
}
}
@@ -30,14 +30,21 @@
}
}
.project-home-dropdown {
margin: 11px 3px 0;
}
.project-home-desc {
h1 {
margin: 0;
margin-bottom: 10px;
font-size: 26px;
font-weight: bold;
}
p {
font-size: 18px;
color: #666;
display: inline;
}
}
@@ -316,3 +323,34 @@ table.table.protected-branches-list tr.no-border {
pre.light-well {
border-color: #f1f1f1;
}
.projects-search-form {
max-width: 600px;
margin: 0 auto;
margin-bottom: 20px;
input {
border-color: #BBB;
}
}
.project-row {
.project-full-name {
font-weight: bold;
font-size: 15px;
}
.project-description {
color: #888;
font-size: 13px;
p {
margin-bottom: 0;
color: #888;
}
}
}
.my-projects .project-row {
padding: 10px 0;
}
-1
View File
@@ -117,7 +117,6 @@
.readme-holder {
margin: 0 auto;
max-width: $readable-width;
.readme-file-title {
font-size: 14px;
+11 -15
View File
@@ -7,27 +7,23 @@
* $color-dark -
*/
@mixin gitlab-theme($color-light, $color, $color-darker, $color-dark) {
header {
&.navbar-gitlab {
.header-logo {
background-color: $color-darker;
border-color: $color-darker;
.page-with-sidebar {
.header-logo {
background-color: $color-darker;
border-color: $color-darker;
a {
color: $color-light;
}
&:hover {
background-color: $color-dark;
a {
color: $color-light;
}
&:hover {
background-color: $color-dark;
a {
color: #FFF;
}
color: #FFF;
}
}
}
}
.page-with-sidebar {
.collapse-nav a {
color: #FFF;
background: $color;
@@ -4,8 +4,13 @@ class Admin::AbuseReportsController < Admin::ApplicationController
end
def destroy
AbuseReport.find(params[:id]).destroy
abuse_report = AbuseReport.find(params[:id])
redirect_to admin_abuse_reports_path, notice: 'Report was removed'
if params[:remove_user]
abuse_report.user.destroy
end
abuse_report.destroy
render nothing: true
end
end
@@ -29,6 +29,15 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
end
end
import_sources = params[:application_setting][:import_sources]
if import_sources.nil?
params[:application_setting][:import_sources] = []
else
import_sources.map! do |source|
source.to_str
end
end
params.require(:application_setting).permit(
:default_projects_limit,
:default_branch_protection,
@@ -48,6 +57,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
:version_check_enabled,
:user_oauth_applications,
restricted_visibility_levels: [],
import_sources: []
)
end
end
@@ -9,6 +9,7 @@ class Admin::ProjectsController < Admin::ApplicationController
@projects = @projects.where("visibility_level IN (?)", params[:visibility_levels]) if params[:visibility_levels].present?
@projects = @projects.with_push if params[:with_push].present?
@projects = @projects.abandoned if params[:abandoned].present?
@projects = @projects.non_archived unless params[:with_archived].present?
@projects = @projects.search(params[:name]) if params[:name].present?
@projects = @projects.sort(@sort = params[:sort])
@projects = @projects.includes(:namespace).order("namespaces.path, projects.name ASC").page(params[:page]).per(PER_PAGE)
+29 -1
View File
@@ -20,7 +20,7 @@ class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
helper_method :abilities, :can?, :current_application_settings
helper_method :github_import_enabled?, :gitlab_import_enabled?, :bitbucket_import_enabled?
helper_method :import_sources_enabled?, :github_import_enabled?, :github_import_configured?, :gitlab_import_enabled?, :gitlab_import_configured?, :bitbucket_import_enabled?, :bitbucket_import_configured?, :gitorious_import_enabled?, :google_code_import_enabled?, :git_import_enabled?
rescue_from Encoding::CompatibilityError do |exception|
log_exception(exception)
@@ -304,15 +304,43 @@ class ApplicationController < ActionController::Base
@issuable_finder.execute
end
def import_sources_enabled?
!current_application_settings.import_sources.empty?
end
def github_import_enabled?
current_application_settings.import_sources.include?('github')
end
def github_import_configured?
Gitlab::OAuth::Provider.enabled?(:github)
end
def gitlab_import_enabled?
request.host != 'gitlab.com' && current_application_settings.import_sources.include?('gitlab')
end
def gitlab_import_configured?
Gitlab::OAuth::Provider.enabled?(:gitlab)
end
def bitbucket_import_enabled?
current_application_settings.import_sources.include?('bitbucket')
end
def bitbucket_import_configured?
Gitlab::OAuth::Provider.enabled?(:bitbucket) && Gitlab::BitbucketImport.public_key.present?
end
def gitorious_import_enabled?
current_application_settings.import_sources.include?('gitorious')
end
def google_code_import_enabled?
current_application_settings.import_sources.include?('google_code')
end
def git_import_enabled?
current_application_settings.import_sources.include?('git')
end
end
+8 -2
View File
@@ -34,8 +34,14 @@ class AutocompleteController < ApplicationController
@users = @users.search(params[:search]) if params[:search].present?
@users = @users.active
@users = @users.page(params[:page]).per(PER_PAGE)
# Always include current user if available to filter by "Me"
@users = User.find(@users.pluck(:id) + [current_user.id]).uniq if current_user
unless params[:search].present?
# Include current user if available to filter by "Me"
if params[:current_user] && current_user
@users = [*@users, current_user].uniq
end
end
render json: @users, only: [:name, :username, :id], methods: [:avatar_url]
end
+15 -7
View File
@@ -1,6 +1,6 @@
class DashboardController < Dashboard::ApplicationController
before_action :load_projects
before_action :event_filter, only: :show
before_action :event_filter, only: :activity
respond_to :html
@@ -10,13 +10,8 @@ class DashboardController < Dashboard::ApplicationController
respond_to do |format|
format.html
format.json do
load_events
pager_json("events/_events", @events.count)
end
format.atom do
event_filter
load_events
render layout: false
end
@@ -40,6 +35,19 @@ class DashboardController < Dashboard::ApplicationController
end
end
def activity
@last_push = current_user.recent_push
respond_to do |format|
format.html
format.json do
load_events
pager_json("events/_events", @events.count)
end
end
end
protected
def load_projects
@@ -7,6 +7,7 @@ class Explore::ProjectsController < Explore::ApplicationController
@tags = @projects.tags_on(:tags)
@projects = @projects.tagged_with(params[:tag]) if params[:tag].present?
@projects = @projects.where(visibility_level: params[:visibility_level]) if params[:visibility_level].present?
@projects = @projects.non_archived
@projects = @projects.search(params[:search]) if params[:search].present?
@projects = @projects.sort(@sort = params[:sort])
@projects = @projects.includes(:namespace).page(params[:page]).per(PER_PAGE)
@@ -14,6 +15,7 @@ class Explore::ProjectsController < Explore::ApplicationController
def trending
@trending_projects = TrendingProjectsFinder.new.execute(current_user)
@trending_projects = @trending_projects.non_archived
@trending_projects = @trending_projects.page(params[:page]).per(PER_PAGE)
end
+16 -7
View File
@@ -13,10 +13,9 @@ class Import::BitbucketController < Import::BaseController
access_token = client.get_token(request_token, params[:oauth_verifier], callback_import_bitbucket_url)
current_user.bitbucket_access_token = access_token.token
current_user.bitbucket_access_token_secret = access_token.secret
session[:bitbucket_access_token] = access_token.token
session[:bitbucket_access_token_secret] = access_token.secret
current_user.save
redirect_to status_import_bitbucket_url
end
@@ -46,19 +45,20 @@ class Import::BitbucketController < Import::BaseController
namespace = get_or_create_namespace || (render and return)
unless Gitlab::BitbucketImport::KeyAdder.new(repo, current_user).execute
unless Gitlab::BitbucketImport::KeyAdder.new(repo, current_user, access_params).execute
@access_denied = true
render
return
end
@project = Gitlab::BitbucketImport::ProjectCreator.new(repo, namespace, current_user).execute
@project = Gitlab::BitbucketImport::ProjectCreator.new(repo, namespace, current_user, access_params).execute
end
private
def client
@client ||= Gitlab::BitbucketImport::Client.new(current_user.bitbucket_access_token, current_user.bitbucket_access_token_secret)
@client ||= Gitlab::BitbucketImport::Client.new(session[:bitbucket_access_token],
session[:bitbucket_access_token_secret])
end
def verify_bitbucket_import_enabled
@@ -66,7 +66,7 @@ class Import::BitbucketController < Import::BaseController
end
def bitbucket_auth
if current_user.bitbucket_access_token.blank?
if session[:bitbucket_access_token].blank?
go_to_bitbucket_for_permissions
end
end
@@ -81,4 +81,13 @@ class Import::BitbucketController < Import::BaseController
def bitbucket_unauthorized
go_to_bitbucket_for_permissions
end
private
def access_params
{
bitbucket_access_token: session[:bitbucket_access_token],
bitbucket_access_token_secret: session[:bitbucket_access_token_secret]
}
end
end
+10 -6
View File
@@ -5,9 +5,7 @@ class Import::GithubController < Import::BaseController
rescue_from Octokit::Unauthorized, with: :github_unauthorized
def callback
token = client.get_token(params[:code])
current_user.github_access_token = token
current_user.save
session[:github_access_token] = client.get_token(params[:code])
redirect_to status_import_github_url
end
@@ -39,13 +37,13 @@ class Import::GithubController < Import::BaseController
namespace = get_or_create_namespace || (render and return)
@project = Gitlab::GithubImport::ProjectCreator.new(repo, namespace, current_user).execute
@project = Gitlab::GithubImport::ProjectCreator.new(repo, namespace, current_user, access_params).execute
end
private
def client
@client ||= Gitlab::GithubImport::Client.new(current_user.github_access_token)
@client ||= Gitlab::GithubImport::Client.new(session[:github_access_token])
end
def verify_github_import_enabled
@@ -53,7 +51,7 @@ class Import::GithubController < Import::BaseController
end
def github_auth
if current_user.github_access_token.blank?
if session[:github_access_token].blank?
go_to_github_for_permissions
end
end
@@ -65,4 +63,10 @@ class Import::GithubController < Import::BaseController
def github_unauthorized
go_to_github_for_permissions
end
private
def access_params
{ github_access_token: session[:github_access_token] }
end
end
+10 -6
View File
@@ -5,9 +5,7 @@ class Import::GitlabController < Import::BaseController
rescue_from OAuth2::Error, with: :gitlab_unauthorized
def callback
token = client.get_token(params[:code], callback_import_gitlab_url)
current_user.gitlab_access_token = token
current_user.save
session[:gitlab_access_token] = client.get_token(params[:code], callback_import_gitlab_url)
redirect_to status_import_gitlab_url
end
@@ -36,13 +34,13 @@ class Import::GitlabController < Import::BaseController
namespace = get_or_create_namespace || (render and return)
@project = Gitlab::GitlabImport::ProjectCreator.new(repo, namespace, current_user).execute
@project = Gitlab::GitlabImport::ProjectCreator.new(repo, namespace, current_user, access_params).execute
end
private
def client
@client ||= Gitlab::GitlabImport::Client.new(current_user.gitlab_access_token)
@client ||= Gitlab::GitlabImport::Client.new(session[:gitlab_access_token])
end
def verify_gitlab_import_enabled
@@ -50,7 +48,7 @@ class Import::GitlabController < Import::BaseController
end
def gitlab_auth
if current_user.gitlab_access_token.blank?
if session[:gitlab_access_token].blank?
go_to_gitlab_for_permissions
end
end
@@ -62,4 +60,10 @@ class Import::GitlabController < Import::BaseController
def gitlab_unauthorized
go_to_gitlab_for_permissions
end
private
def access_params
{ gitlab_access_token: session[:gitlab_access_token] }
end
end
@@ -1,4 +1,5 @@
class Import::GitoriousController < Import::BaseController
before_action :verify_gitorious_import_enabled
def new
redirect_to client.authorize_url(callback_import_gitorious_url)
@@ -40,4 +41,8 @@ class Import::GitoriousController < Import::BaseController
@client ||= Gitlab::GitoriousImport::Client.new(session[:gitorious_repos])
end
def verify_gitorious_import_enabled
not_found! unless gitorious_import_enabled?
end
end
@@ -1,4 +1,5 @@
class Import::GoogleCodeController < Import::BaseController
before_action :verify_google_code_import_enabled
before_action :user_map, only: [:new_user_map, :create_user_map]
def new
@@ -104,6 +105,10 @@ class Import::GoogleCodeController < Import::BaseController
@client ||= Gitlab::GoogleCodeImport::Client.new(session[:google_code_dump])
end
def verify_google_code_import_enabled
not_found! unless google_code_import_enabled?
end
def user_map
@user_map ||= begin
user_map = client.user_map
+23 -1
View File
@@ -8,6 +8,28 @@ class Projects::BlameController < Projects::ApplicationController
def show
@blob = @repository.blob_at(@commit.id, @path)
@blame = Gitlab::Git::Blame.new(@repository, @commit.id, @path)
@blame = group_blame_lines
end
def group_blame_lines
blame = Gitlab::Git::Blame.new(@repository, @commit.id, @path)
prev_sha = nil
groups = []
current_group = nil
blame.each do |commit, line|
if prev_sha && prev_sha == commit.sha
current_group[:lines] << line
else
groups << current_group if current_group.present?
current_group = { commit: commit, lines: [line] }
end
prev_sha = commit.sha
end
groups << current_group if current_group.present?
groups
end
end
+2 -2
View File
@@ -23,7 +23,7 @@ class SearchController < ApplicationController
@search_results =
if @project
unless %w(blobs notes issues merge_requests wiki_blobs).
unless %w(blobs notes issues merge_requests milestones wiki_blobs).
include?(@scope)
@scope = 'blobs'
end
@@ -36,7 +36,7 @@ class SearchController < ApplicationController
Search::SnippetService.new(current_user, params).execute
else
unless %w(projects issues merge_requests).include?(@scope)
unless %w(projects issues merge_requests milestones).include?(@scope)
@scope = 'projects'
end
Search::GlobalService.new(current_user, params).execute
@@ -43,4 +43,21 @@ module ApplicationSettingsHelper
end
end
end
# Return a group of checkboxes that use Bootstrap's button plugin for a
# toggle button effect.
def import_sources_checkboxes(help_block_id)
Gitlab::ImportSources.options.map do |name, source|
checked = current_application_settings.import_sources.include?(source)
css_class = 'btn'
css_class += ' active' if checked
checkbox_name = 'application_setting[import_sources][]'
label_tag(checkbox_name, class: css_class) do
check_box_tag(checkbox_name, source, checked,
autocomplete: 'off',
'aria-describedby' => help_block_id) + name
end
end
end
end
+1 -1
View File
@@ -10,7 +10,7 @@ module ExploreHelper
options = exist_opts.merge(options)
path = request.path
path = explore_projects_path
path << "?#{options.to_param}"
path
end
+1 -1
View File
@@ -20,7 +20,7 @@ module IconsHelper
end
def boolean_to_icon(value)
if value.to_s == "true"
if value
icon('circle', class: 'cgreen')
else
icon('power-off', class: 'clgray')
+8
View File
@@ -23,4 +23,12 @@ module PageLayoutHelper
@sidebar
end
end
def fluid_layout(enabled = false)
if @fluid_layout.nil?
@fluid_layout = enabled
else
@fluid_layout
end
end
end
+3 -1
View File
@@ -11,6 +11,7 @@ module SelectsHelper
any_user = opts[:any_user] || false
email_user = opts[:email_user] || false
first_user = opts[:first_user] && current_user ? current_user.username : false
current_user = opts[:current_user] || false
project = opts[:project] || @project
html = {
@@ -19,7 +20,8 @@ module SelectsHelper
'data-null-user' => null_user,
'data-any-user' => any_user,
'data-email-user' => email_user,
'data-first-user' => first_user
'data-first-user' => first_user,
'data-current-user' => current_user
}
unless opts[:scope] == :all
+8
View File
@@ -67,6 +67,14 @@ module TabHelper
path.any? do |single_path|
current_path?(single_path)
end
elsif page = options.delete(:page)
unless page.respond_to?(:each)
page = [page]
end
page.any? do |single_page|
current_page?(single_page)
end
else
c = options.delete(:controller)
a = options.delete(:action)
+32
View File
@@ -0,0 +1,32 @@
class BaseMailer < ActionMailer::Base
add_template_helper ApplicationHelper
add_template_helper GitlabMarkdownHelper
attr_accessor :current_user
helper_method :current_user, :can?
default from: Proc.new { default_sender_address.format }
default reply_to: Proc.new { default_reply_to_address.format }
def self.delay
delay_for(2.seconds)
end
def can?
Ability.abilities.allowed?(current_user, action, subject)
end
private
def default_sender_address
address = Mail::Address.new(Gitlab.config.gitlab.email_from)
address.display_name = Gitlab.config.gitlab.email_display_name
address
end
def default_reply_to_address
address = Mail::Address.new(Gitlab.config.gitlab.email_reply_to)
address.display_name = Gitlab.config.gitlab.email_display_name
address
end
end
+21
View File
@@ -0,0 +1,21 @@
class EmailRejectionMailer < BaseMailer
def rejection(reason, original_raw, can_retry = false)
@reason = reason
@original_message = Mail::Message.new(original_raw)
return unless @original_message.from
headers = {
to: @original_message.from,
subject: "[Rejected] #{@original_message.subject}"
}
headers['Message-ID'] = SecureRandom.hex
headers['In-Reply-To'] = @original_message.message_id
headers['References'] = @original_message.message_id
headers['Reply-To'] = @original_message.to.first if can_retry
mail(headers)
end
end
+8
View File
@@ -8,6 +8,8 @@ module Emails
from: sender(@issue.author_id),
to: recipient(recipient_id),
subject: subject("#{@issue.title} (##{@issue.iid})"))
SentNotification.record(@issue, recipient_id, reply_key)
end
def reassigned_issue_email(recipient_id, issue_id, previous_assignee_id, updated_by_user_id)
@@ -19,6 +21,8 @@ module Emails
from: sender(updated_by_user_id),
to: recipient(recipient_id),
subject: subject("#{@issue.title} (##{@issue.iid})"))
SentNotification.record(@issue, recipient_id, reply_key)
end
def closed_issue_email(recipient_id, issue_id, updated_by_user_id)
@@ -30,6 +34,8 @@ module Emails
from: sender(updated_by_user_id),
to: recipient(recipient_id),
subject: subject("#{@issue.title} (##{@issue.iid})"))
SentNotification.record(@issue, recipient_id, reply_key)
end
def issue_status_changed_email(recipient_id, issue_id, status, updated_by_user_id)
@@ -42,6 +48,8 @@ module Emails
from: sender(updated_by_user_id),
to: recipient(recipient_id),
subject: subject("#{@issue.title} (##{@issue.iid})"))
SentNotification.record(@issue, recipient_id, reply_key)
end
end
end
+11 -43
View File
@@ -10,6 +10,8 @@ module Emails
from: sender(@merge_request.author_id),
to: recipient(recipient_id),
subject: subject("#{@merge_request.title} (##{@merge_request.iid})"))
SentNotification.record(@merge_request, recipient_id, reply_key)
end
def reassigned_merge_request_email(recipient_id, merge_request_id, previous_assignee_id, updated_by_user_id)
@@ -23,6 +25,8 @@ module Emails
from: sender(updated_by_user_id),
to: recipient(recipient_id),
subject: subject("#{@merge_request.title} (##{@merge_request.iid})"))
SentNotification.record(@merge_request, recipient_id, reply_key)
end
def closed_merge_request_email(recipient_id, merge_request_id, updated_by_user_id)
@@ -36,6 +40,8 @@ module Emails
from: sender(updated_by_user_id),
to: recipient(recipient_id),
subject: subject("#{@merge_request.title} (##{@merge_request.iid})"))
SentNotification.record(@merge_request, recipient_id, reply_key)
end
def merged_merge_request_email(recipient_id, merge_request_id, updated_by_user_id)
@@ -48,6 +54,8 @@ module Emails
from: sender(updated_by_user_id),
to: recipient(recipient_id),
subject: subject("#{@merge_request.title} (##{@merge_request.iid})"))
SentNotification.record(@merge_request, recipient_id, reply_key)
end
def merge_request_status_email(recipient_id, merge_request_id, status, updated_by_user_id)
@@ -58,52 +66,12 @@ module Emails
@target_url = namespace_project_merge_request_url(@project.namespace,
@project,
@merge_request)
set_reference("merge_request_#{merge_request_id}")
mail_answer_thread(@merge_request,
from: sender(updated_by_user_id),
to: recipient(recipient_id),
subject: subject("#{@merge_request.title} (##{@merge_request.iid}) #{@mr_status}"))
subject: subject("#{@merge_request.title} (##{@merge_request.iid})"))
SentNotification.record(@merge_request, recipient_id, reply_key)
end
end
# Over rides default behaviour to show source/target
# Formats arguments into a String suitable for use as an email subject
#
# extra - Extra Strings to be inserted into the subject
#
# Examples
#
# >> subject('Lorem ipsum')
# => "GitLab Merge Request | Lorem ipsum"
#
# # Automatically inserts Project name:
# Forked MR
# => source project => <Project id: 1, name: "Ruby on Rails", path: "ruby_on_rails", ...>
# => target project => <Project id: 2, name: "My Ror", path: "ruby_on_rails", ...>
# => source branch => source
# => target branch => target
# >> subject('Lorem ipsum')
# => "GitLab Merge Request | Ruby on Rails:source >> My Ror:target | Lorem ipsum "
#
# Non Forked MR
# => source project => <Project id: 1, name: "Ruby on Rails", path: "ruby_on_rails", ...>
# => target project => <Project id: 1, name: "Ruby on Rails", path: "ruby_on_rails", ...>
# => source branch => source
# => target branch => target
# >> subject('Lorem ipsum')
# => "GitLab Merge Request | Ruby on Rails | source >> target | Lorem ipsum "
# # Accepts multiple arguments
# >> subject('Lorem ipsum', 'Dolor sit amet')
# => "GitLab Merge Request | Lorem ipsum | Dolor sit amet"
def subject(*extra)
subject = "Merge Request | "
if @merge_request.for_fork?
subject << "#{@merge_request.source_project.name_with_namespace}:#{merge_request.source_branch} >> #{@merge_request.target_project.name_with_namespace}:#{merge_request.target_branch}"
else
subject << "#{@merge_request.source_project.name_with_namespace} | #{merge_request.source_branch} >> #{merge_request.target_branch}"
end
subject << " | " + extra.join(' | ') if extra.present?
subject
end
end
+6
View File
@@ -11,6 +11,8 @@ module Emails
from: sender(@note.author_id),
to: recipient(recipient_id),
subject: subject("#{@commit.title} (#{@commit.short_id})"))
SentNotification.record(@commit, recipient_id, reply_key)
end
def note_issue_email(recipient_id, note_id)
@@ -24,6 +26,8 @@ module Emails
from: sender(@note.author_id),
to: recipient(recipient_id),
subject: subject("#{@issue.title} (##{@issue.iid})"))
SentNotification.record(@issue, recipient_id, reply_key)
end
def note_merge_request_email(recipient_id, note_id)
@@ -38,6 +42,8 @@ module Emails
from: sender(@note.author_id),
to: recipient(recipient_id),
subject: subject("#{@merge_request.title} (##{@merge_request.iid})"))
SentNotification.record(@merge_request, recipient_id, reply_key)
end
end
end
+33 -40
View File
@@ -1,4 +1,4 @@
class Notify < ActionMailer::Base
class Notify < BaseMailer
include ActionDispatch::Routing::PolymorphicRoutes
include Emails::AdminNotification
@@ -9,22 +9,9 @@ class Notify < ActionMailer::Base
include Emails::Profile
include Emails::Groups
add_template_helper ApplicationHelper
add_template_helper GitlabMarkdownHelper
add_template_helper MergeRequestsHelper
add_template_helper EmailsHelper
attr_accessor :current_user
helper_method :current_user, :can?
default from: Proc.new { default_sender_address.format }
default reply_to: Gitlab.config.gitlab.email_reply_to
# Just send email with 2 seconds delay
def self.delay
delay_for(2.seconds)
end
def test_email(recipient_email, subject, body)
mail(to: recipient_email,
subject: subject,
@@ -49,13 +36,6 @@ class Notify < ActionMailer::Base
private
# The default email address to send emails from
def default_sender_address
address = Mail::Address.new(Gitlab.config.gitlab.email_from)
address.display_name = Gitlab.config.gitlab.email_display_name
address
end
def can_send_from_user_email?(sender)
sender_domain = sender.email.split("@").last
self.class.allowed_email_domains.include?(sender_domain)
@@ -86,14 +66,6 @@ class Notify < ActionMailer::Base
@current_user.notification_email
end
# Set the References header field
#
# local_part - The local part of the referenced message ID
#
def set_reference(local_part)
headers["References"] = "<#{local_part}@#{Gitlab.config.gitlab.host}>"
end
# Formats arguments into a String suitable for use as an email subject
#
# extra - Extra Strings to be inserted into the subject
@@ -127,14 +99,37 @@ class Notify < ActionMailer::Base
"<#{model_name}_#{model.id}@#{Gitlab.config.gitlab.host}>"
end
def mail_thread(model, headers = {})
if @project
headers['X-GitLab-Project'] = @project.name
headers['X-GitLab-Project-Id'] = @project.id
headers['X-GitLab-Project-Path'] = @project.path_with_namespace
end
headers["X-GitLab-#{model.class.name}-ID"] = model.id
if reply_key
headers['X-GitLab-Reply-Key'] = reply_key
address = Mail::Address.new(Gitlab::ReplyByEmail.reply_address(reply_key))
address.display_name = @project.name_with_namespace
headers['Reply-To'] = address
@reply_by_email = true
end
mail(headers)
end
# Send an email that starts a new conversation thread,
# with headers suitable for grouping by thread in email clients.
#
# See: mail_answer_thread
def mail_new_thread(model, headers = {}, &block)
def mail_new_thread(model, headers = {})
headers['Message-ID'] = message_id(model)
headers['X-GitLab-Project'] = "#{@project.name} | " if @project
mail(headers, &block)
mail_thread(model, headers)
end
# Send an email that responds to an existing conversation thread,
@@ -145,19 +140,17 @@ class Notify < ActionMailer::Base
# * have a subject that begin by 'Re: '
# * have a 'In-Reply-To' or 'References' header that references the original 'Message-ID'
#
def mail_answer_thread(model, headers = {}, &block)
def mail_answer_thread(model, headers = {})
headers['Message-ID'] = SecureRandom.hex
headers['In-Reply-To'] = message_id(model)
headers['References'] = message_id(model)
headers['X-GitLab-Project'] = "#{@project.name} | " if @project
if headers[:subject]
headers[:subject].prepend('Re: ')
end
headers[:subject].prepend('Re: ') if headers[:subject]
mail(headers, &block)
mail_thread(model, headers)
end
def can?
Ability.abilities.allowed?(user, action, subject)
def reply_key
@reply_key ||= Gitlab::ReplyByEmail.reply_key
end
end
+14 -1
View File
@@ -23,10 +23,12 @@
# user_oauth_applications :boolean default(TRUE)
# after_sign_out_path :string(255)
# session_expire_delay :integer default(10080), not null
# import_sources :text
#
class ApplicationSetting < ActiveRecord::Base
serialize :restricted_visibility_levels
serialize :import_sources
serialize :restricted_signup_domains, Array
attr_accessor :restricted_signup_domains_raw
@@ -53,6 +55,16 @@ class ApplicationSetting < ActiveRecord::Base
end
end
validates_each :import_sources do |record, attr, value|
unless value.nil?
value.each do |source|
unless Gitlab::ImportSources.options.has_value?(source)
record.errors.add(attr, "'#{source}' is not a import source")
end
end
end
end
def self.current
ApplicationSetting.last
end
@@ -71,7 +83,8 @@ class ApplicationSetting < ActiveRecord::Base
session_expire_delay: Settings.gitlab['session_expire_delay'],
default_project_visibility: Settings.gitlab.default_projects_features['visibility_level'],
default_snippet_visibility: Settings.gitlab.default_projects_features['visibility_level'],
restricted_signup_domains: Settings.gitlab['restricted_signup_domains']
restricted_signup_domains: Settings.gitlab['restricted_signup_domains'],
import_sources: ['github','bitbucket','gitlab','gitorious','google_code','git']
)
end
+1
View File
@@ -17,6 +17,7 @@ require 'carrierwave/orm/activerecord'
require 'file_size_validator'
class Group < Namespace
include Gitlab::ConfigHelper
include Referable
has_many :group_members, dependent: :destroy, as: :source, class_name: 'GroupMember'
+8 -1
View File
@@ -47,6 +47,13 @@ class Milestone < ActiveRecord::Base
state :active
end
class << self
def search(query)
query = "%#{query}%"
where("title like ? or description like ?", query, query)
end
end
def expired?
if due_date
due_date.past?
@@ -54,7 +61,7 @@ class Milestone < ActiveRecord::Base
false
end
end
def open_items_count
self.issues.opened.count + self.merge_requests.opened.count
end
+1 -1
View File
@@ -90,7 +90,7 @@ class Note < ActiveRecord::Base
end
def search(query)
where("note like :query", query: "%#{query}%")
where("LOWER(note) like :query", query: "%#{query.downcase}%")
end
end
+1 -1
View File
@@ -222,7 +222,7 @@ class Project < ActiveRecord::Base
end
def search(query)
joins(:namespace).where('projects.archived = ?', false).
joins(:namespace).
where('LOWER(projects.name) LIKE :query OR
LOWER(projects.path) LIKE :query OR
LOWER(namespaces.name) LIKE :query OR
+50
View File
@@ -0,0 +1,50 @@
class SentNotification < ActiveRecord::Base
belongs_to :project
belongs_to :noteable, polymorphic: true
belongs_to :recipient, class_name: "User"
validate :project, :recipient, :reply_key, presence: true
validate :reply_key, uniqueness: true
validates :noteable_id, presence: true, unless: :for_commit?
validates :commit_id, presence: true, if: :for_commit?
class << self
def for(reply_key)
find_by(reply_key: reply_key)
end
def record(noteable, recipient_id, reply_key)
return unless reply_key
noteable_id = nil
commit_id = nil
if noteable.is_a?(Commit)
commit_id = noteable.id
else
noteable_id = noteable.id
end
create(
project: noteable.project,
noteable_type: noteable.class.name,
noteable_id: noteable_id,
commit_id: commit_id,
recipient_id: recipient_id,
reply_key: reply_key
)
end
end
def for_commit?
noteable_type == "Commit"
end
def noteable
if for_commit?
project.commit(commit_id) rescue nil
else
super
end
end
end
+13 -2
View File
@@ -500,8 +500,19 @@ class User < ActiveRecord::Base
events = recent_events.code_push.where("created_at > ?", Time.now - 2.hours)
events = events.where(project_id: project_id) if project_id
# Take only latest one
events = events.recent.limit(1).first
# Use the latest event that has not been pushed or merged recently
events.recent.find do |event|
project = Project.find_by_id(event.project_id)
next unless project
repo = project.repository
if repo.branch_names.include?(event.branch_name)
merge_requests = MergeRequest.where("created_at >= ?", event.created_at).
where(source_project_id: project.id,
source_branch: event.branch_name)
merge_requests.empty?
end
end
end
def projects_sorted_by_activity
+10 -5
View File
@@ -78,24 +78,29 @@ class GitPushService
# For push with 1k commits it prevents 900+ requests in database
author = nil
# Keep track of the issues that will be actually closed because they are on a default branch.
# Hence, when creating cross-reference notes, the not-closed issues (on non-default branches)
# will also have cross-reference.
actually_closed_issues = []
if issues_to_close.present? && is_default_branch
author ||= commit_user(commit)
actually_closed_issues = issues_to_close
issues_to_close.each do |issue|
Issues::CloseService.new(project, author, {}).execute(issue, commit)
end
end
if project.reference_issue_tracker?
create_cross_reference_notes(commit, issues_to_close)
create_cross_reference_notes(commit, actually_closed_issues)
end
end
end
def create_cross_reference_notes(commit, issues_to_close)
# Create cross-reference notes for any other references. Omit any issues that were referenced in an
# issue-closing phrase, or have already been mentioned from this commit (probably from this commit
# being pushed to a different branch).
# Create cross-reference notes for any other references than those given in issues_to_close.
# Omit any issues that were referenced in an issue-closing phrase, or have already been
# mentioned from this commit (probably from this commit being pushed to a different branch).
refs = commit.references(project, user) - issues_to_close
refs.reject! { |r| commit.has_mentioned?(r) }
@@ -1,11 +1,17 @@
module MergeRequests
class CreateService < MergeRequests::BaseService
def execute
# @project is used to determine whether the user can set the merge request's
# assignee, milestone and labels. Whether they can depends on their
# permissions on the target project.
source_project = @project
@project = Project.find(params[:target_project_id]) if params[:target_project_id]
filter_params
label_params = params[:label_ids]
merge_request = MergeRequest.new(params.except(:label_ids))
merge_request.source_project = project
merge_request.target_project ||= project
merge_request.source_project = source_project
merge_request.target_project ||= source_project
merge_request.author = current_user
if merge_request.save
+3 -3
View File
@@ -13,9 +13,9 @@ module Projects
filename = uploader.image? ? uploader.file.basename : uploader.file.filename
{
'alt' => filename,
'url' => uploader.secure_url,
'is_image' => uploader.image?
alt: filename,
url: uploader.secure_url,
is_image: uploader.image?
}
end
@@ -3,7 +3,7 @@
%tr
%td
- if reporter
= link_to reporter.name, [:admin, reporter]
= link_to reporter.name, reporter
- else
(removed)
%td
@@ -12,12 +12,15 @@
= abuse_report.message
%td
- if user
= link_to user.name, [:admin, user]
= link_to user.name, user
- else
(removed)
%td
- if user
= link_to 'Block', block_admin_user_path(user), data: {confirm: 'USER WILL BE BLOCKED! Are you sure?'}, method: :put, class: "btn btn-xs btn-warning"
= link_to 'Remove user', [:admin, user], data: { confirm: "USER #{user.name} WILL BE REMOVED! Are you sure?" }, method: :delete, class: "btn btn-xs btn-remove"
= link_to 'Remove user & report', admin_abuse_report_path(abuse_report, remove_user: true),
data: { confirm: "USER #{user.name} WILL BE REMOVED! Are you sure?" }, remote: true, method: :delete, class: "btn btn-xs btn-remove js-remove-tr"
%td
= link_to 'Remove report', [:admin, abuse_report], method: :delete, class: "btn btn-xs btn-close"
- if user
= link_to 'Block user', block_admin_user_path(user), data: {confirm: 'USER WILL BE BLOCKED! Are you sure?'}, method: :put, class: "btn btn-xs"
= link_to 'Remove report', [:admin, abuse_report], remote: true, method: :delete, class: "btn btn-xs btn-close js-remove-tr"
@@ -9,7 +9,7 @@
%th Reported at
%th Message
%th User
%th
%th Primary action
%th
= render @abuse_reports
= paginate @abuse_reports
@@ -27,6 +27,20 @@
- restricted_level_checkboxes('restricted-visibility-help').each do |level|
= level
%span.help-block#restricted-visibility-help Selected levels cannot be used by non-admin users for projects or snippets
.form-group
= f.label :import_sources, class: 'control-label col-sm-2'
.col-sm-10
- data_attrs = { toggle: 'buttons' }
.btn-group{ data: data_attrs }
- import_sources_checkboxes('import-sources-help').each do |source|
= source
%span.help-block#import-sources-help
Enabled sources for code import during project creation. OmniAuth must be configured for GitHub
= link_to "(?)", help_page_path("integration", "github")
, Bitbucket
= link_to "(?)", help_page_path("integration", "bitbucket")
and GitLab.com
= link_to "(?)", help_page_path("integration", "gitlab")
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
@@ -55,6 +55,10 @@
OmniAuth
%span.light.pull-right
= boolean_to_icon Gitlab.config.omniauth.enabled
%p
Reply by email
%span.light.pull-right
= boolean_to_icon Gitlab::ReplyByEmail.enabled?
.col-md-4
%h4
Components
+6
View File
@@ -23,6 +23,10 @@
= label_tag :abandoned do
= check_box_tag :abandoned, 1, params[:abandoned]
%span No activity over 6 month
.checkbox
= label_tag :with_archived do
= check_box_tag :with_archived, 1, params[:with_archived]
%span Show archived projects
%fieldset
%strong Visibility level:
@@ -73,6 +77,8 @@
= visibility_level_icon(project.visibility_level)
= link_to project.name_with_namespace, [:admin, project.namespace.becomes(Namespace), project]
.pull-right
- if project.archived
%span.label.label-warning archived
%span.label.label-gray
= repository_size(project)
= link_to 'Edit', edit_namespace_project_path(project.namespace, project), id: "edit_#{dom_id(project)}", class: "btn btn-sm"
@@ -0,0 +1,7 @@
%ul.center-top-menu
= nav_link(page: [dashboard_groups_path]) do
= link_to dashboard_groups_path, title: 'Your groups', data: {placement: 'right'} do
Your Groups
= nav_link(page: [explore_groups_path]) do
= link_to explore_groups_path, title: 'Explore groups', data: {toggle: 'tooltip', placement: 'bottom'} do
Explore Groups
+6 -3
View File
@@ -1,5 +1,5 @@
.panel.panel-default
.panel-heading.clearfix
.projects-list-holder
.projects-search-form
.input-group
= search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'projects-list-filter form-control'
- if current_user.can_create_project?
@@ -7,4 +7,7 @@
= link_to new_project_path, class: 'btn btn-success' do
New project
= render 'shared/projects_list', projects: @projects, projects_limit: 20
%ul.projects-list.bordered-list.my-projects
- @projects.each do |project|
%li.project-row
= render partial: 'shared/project', locals: { project: project, avatar: true, stars: true }
@@ -0,0 +1,10 @@
%ul.center-top-menu
= nav_link(path: ['dashboard#show', 'root#show']) do
= link_to dashboard_path, title: 'Home', class: 'shortcuts-activity', data: {placement: 'right'} do
Your Projects
= nav_link(page: starred_dashboard_projects_path) do
= link_to starred_dashboard_projects_path, title: 'Starred Projects', data: {placement: 'right'} do
Starred Projects
= nav_link(page: [explore_root_path, trending_explore_projects_path, starred_explore_projects_path, explore_projects_path]) do
= link_to explore_root_path, title: 'Explore', data: {toggle: 'tooltip', placement: 'bottom'} do
Explore Projects
+6
View File
@@ -0,0 +1,6 @@
= content_for :meta_tags do
- if current_user
= auto_discovery_link_tag(:atom, dashboard_url(format: :atom, private_token: current_user.private_token), title: "All activity")
%section.activities
= render 'activities'
+5 -6
View File
@@ -1,14 +1,13 @@
- page_title "Groups"
%h3.page-title
Group Membership
= render 'dashboard/groups_head'
.slead
Group members have access to all group projects.
- if current_user.can_create_group?
%span.pull-right.hidden-xs
= link_to new_group_path, class: "btn btn-new" do
= link_to new_group_path, class: "btn btn-new btn-sm" do
%i.fa.fa-plus
New Group
%p.light
Group members have access to all group projects.
%hr
.panel.panel-default
.panel-heading
%strong Groups
@@ -1,12 +1,14 @@
- page_title "Starred Projects"
= render 'dashboard/projects_head'
- if @projects.any?
= render 'shared/show_aside'
.dashboard.row
%section.activities.col-md-8
%section.activities.col-md-7
= render 'dashboard/activities'
%aside.col-md-4
.panel.panel-default
%aside.col-md-5
.panel.panel-default.projects-list-holder
.panel-heading.clearfix
.input-group
= search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'projects-list-filter form-control'
+6 -8
View File
@@ -2,14 +2,12 @@
- if current_user
= auto_discovery_link_tag(:atom, dashboard_url(format: :atom, private_token: current_user.private_token), title: "All activity")
= render 'dashboard/projects_head'
- if @last_push
= render "events/event_last_push", event: @last_push
- if @projects.any?
= render 'shared/show_aside'
.dashboard.row
%section.activities.col-md-8
= render 'activities'
%aside.col-md-4
= render 'sidebar'
= render 'projects'
- else
= render "zero_authorized_projects"
@@ -0,0 +1,4 @@
%p
Unfortunately, your email message to GitLab could not be processed.
= markdown @reason
@@ -0,0 +1,4 @@
Unfortunately, your email message to GitLab could not be processed.
= @reason
+1 -1
View File
@@ -9,6 +9,6 @@
#{time_ago_with_tooltip(event.created_at)}
.pull-right
= link_to new_mr_path_from_push_event(event), title: "New Merge Request", class: "btn btn-create btn-sm" do
= link_to new_mr_path_from_push_event(event), title: "New Merge Request", class: "btn btn-info btn-sm" do
Create Merge Request
%hr
+3 -4
View File
@@ -1,5 +1,7 @@
- page_title "Groups"
.clearfix
- if current_user
= render 'dashboard/groups_head'
.clearfix.append-bottom-10
.pull-left
= form_tag explore_groups_path, method: :get, class: 'form-inline form-tiny' do |f|
= hidden_field_tag :sort, @sort
@@ -28,15 +30,12 @@
= link_to explore_groups_path(sort: sort_value_oldest_updated) do
= sort_title_oldest_updated
%hr
%ul.bordered-list
- @groups.each do |group|
%li
.clearfix
%h4
= link_to group_path(id: group.path) do
%i.fa.fa-users
= group.name
.clearfix
%p
@@ -0,0 +1,27 @@
.dropdown.inline
%button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'}
%span.light sort:
- if @sort.present?
= sort_options_hash[@sort]
- elsif current_page?(trending_explore_projects_path) || current_page?(explore_root_path)
Trending projects
- elsif current_page?(starred_explore_projects_path)
Most stars
- else
= sort_title_recently_created
%b.caret
%ul.dropdown-menu
%li
= link_to trending_explore_projects_path do
Trending projects
= link_to starred_explore_projects_path do
Most stars
= link_to explore_projects_filter_path(sort: sort_value_recently_created) do
= sort_title_recently_created
= link_to explore_projects_filter_path(sort: sort_value_oldest_created) do
= sort_title_oldest_created
= link_to explore_projects_filter_path(sort: sort_value_recently_updated) do
= sort_title_recently_updated
= link_to explore_projects_filter_path(sort: sort_value_oldest_updated) do
= sort_title_oldest_updated
+1 -19
View File
@@ -46,22 +46,4 @@
= link_to explore_projects_filter_path(tag: tag.name) do
%i.fa.fa-tag
= tag.name
.dropdown.inline
%button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'}
%span.light sort:
- if @sort.present?
= sort_options_hash[@sort]
- else
= sort_title_recently_created
%b.caret
%ul.dropdown-menu
%li
= link_to explore_projects_filter_path(sort: sort_value_recently_created) do
= sort_title_recently_created
= link_to explore_projects_filter_path(sort: sort_value_oldest_created) do
= sort_title_oldest_created
= link_to explore_projects_filter_path(sort: sort_value_recently_updated) do
= sort_title_recently_updated
= link_to explore_projects_filter_path(sort: sort_value_oldest_updated) do
= sort_title_oldest_updated
= render 'explore/projects/dropdown'
@@ -1,24 +0,0 @@
%li
%h4.project-title
.project-access-icon
= visibility_level_icon(project.visibility_level)
= link_to project.name_with_namespace, [project.namespace.becomes(Namespace), project]
%span.pull-right
%i.fa.fa-star
= project.star_count
.project-info
- if project.description.present?
.project-description.str-truncated
= markdown(project.description, pipeline: :description)
.repo-info
- unless project.empty_repo?
= link_to pluralize(round_commit_count(project), 'commit'), namespace_project_commits_path(project.namespace, project, project.default_branch)
&middot;
= link_to pluralize(project.repository.branch_names.count, 'branch'), namespace_project_branches_path(project.namespace, project)
&middot;
= link_to pluralize(project.repository.tag_names.count, 'tag'), namespace_project_tags_path(project.namespace, project)
- else
%i.fa.fa-exclamation-triangle
Empty repository
@@ -0,0 +1,6 @@
%ul.projects-list.bordered-list.my-projects.public-projects
- projects.each do |project|
%li.project-row
= render partial: 'shared/project', locals: { project: project, avatar: true, stars: true }
- unless projects.present?
.nothing-here-block No such projects
+5 -9
View File
@@ -1,12 +1,8 @@
- page_title "Projects"
- if current_user
= render 'dashboard/projects_head'
.clearfix
= render 'filter'
%hr
.public-projects
%ul.bordered-list.top-list
= render @projects
- unless @projects.present?
.nothing-here-block No public projects
= paginate @projects, theme: "gitlab"
%br
= render 'projects', projects: @projects
= paginate @projects, theme: "gitlab"
+6 -6
View File
@@ -1,11 +1,11 @@
- page_title "Starred Projects"
- if current_user
= render 'dashboard/projects_head'
.explore-trending-block
%p.lead
.lead
%i.fa.fa-star
See most starred projects
%hr
.public-projects
%ul.bordered-list
= render @starred_projects
.pull-right
= render 'explore/projects/dropdown'
= render 'projects', projects: @starred_projects
= paginate @starred_projects, theme: 'gitlab'
@@ -1,4 +1,6 @@
- page_title "Trending Projects"
- if current_user
= render 'dashboard/projects_head'
.explore-title
%h3
Explore GitLab
@@ -6,10 +8,9 @@
Discover projects and groups. Share your projects with others
%hr
.explore-trending-block
%p.lead
.lead
%i.fa.fa-comments-o
See most discussed projects for last month
%hr
.public-projects
%ul.bordered-list
= render @trending_projects
.pull-right
= render 'explore/projects/dropdown'
= render 'projects', projects: @trending_projects
+1 -1
View File
@@ -1,4 +1,4 @@
.panel.panel-default
.panel.panel-default.projects-list-holder
.panel-heading.clearfix
.input-group
= search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'projects-list-filter form-control'
+6 -3
View File
@@ -12,11 +12,14 @@
- @projects.each do |project|
%li
.list-item-name
= visibility_level_icon(project.visibility_level)
%strong= link_to project.name_with_namespace, namespace_project_path(project.namespace, project)
%span{ class: visibility_level_color(project.visibility_level) }
= visibility_level_icon(project.visibility_level)
%strong= link_to project.name_with_namespace, project
.pull-right
- if project.archived
%span.label.label-warning archived
%span.label.label-gray
= repository_size(project)
.pull-right
= link_to 'Members', namespace_project_project_members_path(project.namespace, project), id: "edit_#{dom_id(project)}", class: "btn btn-sm"
= link_to 'Edit', edit_namespace_project_path(project.namespace, project), id: "edit_#{dom_id(project)}", class: "btn btn-sm"
= link_to 'Remove', project, data: { confirm: remove_project_message(project)}, method: :delete, class: "btn btn-sm btn-remove"
+2 -2
View File
@@ -17,7 +17,7 @@
= render 'shared/show_aside'
.row
%section.activities.col-md-8
%section.activities.col-md-7
.hidden-xs
- if current_user
= render "events/event_last_push", event: @last_push
@@ -33,7 +33,7 @@
.content_list
= spinner
%aside.side.col-md-4
%aside.side.col-md-5
= render "projects", projects: @projects
%br
= render "shared_projects", projects: @shared_projects
+6 -1
View File
@@ -1,6 +1,11 @@
.page-with-sidebar{ class: nav_sidebar_class }
= render "layouts/broadcast"
.sidebar-wrapper.nicescroll
.header-logo
= link_to root_path, class: 'home', title: 'Dashboard', id: 'js-shortcuts-home', data: {toggle: 'tooltip', placement: 'bottom'} do
= brand_header_logo
.gitlab-text-container
%h3 GitLab
- if defined?(sidebar) && sidebar
= render "layouts/nav/#{sidebar}"
- elsif current_user
@@ -13,7 +18,7 @@
.username
= current_user.username
.content-wrapper
.container-fluid
%div{ class: fluid_layout ? "container-fluid" : "container-fluid container-limited" }
.content
= render "layouts/flash"
.clearfix
+5 -2
View File
@@ -1,5 +1,8 @@
- page_title "Explore"
- header_title "Explore GitLab", explore_root_path
- sidebar "explore"
- if current_user
- header_title "Dashboard", root_path
- else
- header_title "Explore GitLab", explore_root_path
- sidebar "dashboard"
= render template: "layouts/application"
+1 -18
View File
@@ -1,10 +1,5 @@
%header.navbar.navbar-fixed-top.navbar-gitlab{ class: nav_header_class }
.container
.header-logo
= link_to root_path, class: 'home', title: 'Dashboard', id: 'js-shortcuts-home', data: {toggle: 'tooltip', placement: 'bottom'} do
= brand_header_logo
.gitlab-text-container
%h3 GitLab
%div{ class: fluid_layout ? "container-fluid" : "container-fluid container-limited" }
.header-content
%button.navbar-toggle{type: 'button'}
%span.sr-only Toggle navigation
@@ -17,15 +12,6 @@
%li.visible-sm.visible-xs
= link_to search_path, title: 'Search', data: {toggle: 'tooltip', placement: 'bottom'} do
= icon('search')
%li.hidden-xs
= link_to help_path, title: 'Help', data: {toggle: 'tooltip', placement: 'bottom'} do
= icon('question-circle fw')
%li
= link_to explore_root_path, title: 'Explore', data: {toggle: 'tooltip', placement: 'bottom'} do
= icon('globe fw')
%li
= link_to user_snippets_path(current_user), title: 'Your snippets', data: {toggle: 'tooltip', placement: 'bottom'} do
= icon('clipboard fw')
- if current_user.is_admin?
%li
= link_to admin_root_path, title: 'Admin area', data: {toggle: 'tooltip', placement: 'bottom'} do
@@ -34,9 +20,6 @@
%li.hidden-xs
= link_to new_project_path, title: 'New project', data: {toggle: 'tooltip', placement: 'bottom'} do
= icon('plus fw')
%li
= link_to profile_path, title: 'Profile settings', data: {toggle: 'tooltip', placement: 'bottom'} do
= icon('cog fw')
%li
= link_to destroy_user_session_path, class: 'logout', method: :delete, title: 'Sign out', data: {toggle: 'tooltip', placement: 'bottom'} do
= icon('sign-out')
+1 -6
View File
@@ -1,10 +1,5 @@
%header.navbar.navbar-fixed-top.navbar-gitlab{ class: nav_header_class }
.container
.header-logo
= link_to explore_root_path, class: "home" do
= brand_header_logo
.gitlab-text-container
%h3 GitLab
%div{ class: fluid_layout ? "container-fluid" : "container-fluid container-limited" }
.header-content
- unless current_controller?('sessions')
.pull-right
+37 -25
View File
@@ -1,36 +1,48 @@
%ul.nav.nav-sidebar
= nav_link(path: ['dashboard#show', 'root#show'], html_options: {class: 'home'}) do
= link_to dashboard_path, title: 'Home', class: 'shortcuts-activity', data: {placement: 'right'} do
= nav_link(path: ['dashboard#show', 'root#show', 'projects#trending', 'projects#starred', 'projects#index'], html_options: {class: 'home'}) do
= link_to (current_user ? root_path : explore_root_path), title: 'Home', class: 'shortcuts-activity', data: {placement: 'right'} do
= icon('home fw')
%span
Projects
= nav_link(path: 'dashboard#activity') do
= link_to activity_dashboard_path, title: 'Activity', data: {placement: 'right'} do
= icon('dashboard fw')
%span
Your Projects
= nav_link(path: 'projects#starred') do
= link_to starred_dashboard_projects_path, title: 'Starred Projects', data: {placement: 'right'} do
= icon('star fw')
%span
Starred Projects
Activity
= nav_link(controller: :groups) do
= link_to dashboard_groups_path, title: 'Groups', data: {placement: 'right'} do
= link_to (current_user ? dashboard_groups_path : explore_groups_path), title: 'Groups', data: {placement: 'right'} do
= icon('group fw')
%span
Groups
= nav_link(controller: :milestones) do
= link_to dashboard_milestones_path, title: 'Milestones', data: {placement: 'right'} do
= icon('clock-o fw')
- if current_user
= nav_link(controller: :milestones) do
= link_to dashboard_milestones_path, title: 'Milestones', data: {placement: 'right'} do
= icon('clock-o fw')
%span
Milestones
= nav_link(path: 'dashboard#issues') do
= link_to assigned_issues_dashboard_path, title: 'Issues', class: 'shortcuts-issues', data: {placement: 'right'} do
= icon('exclamation-circle fw')
%span
Issues
%span.count= current_user.assigned_issues.opened.count
= nav_link(path: 'dashboard#merge_requests') do
= link_to assigned_mrs_dashboard_path, title: 'Merge Requests', class: 'shortcuts-merge_requests', data: {placement: 'right'} do
= icon('tasks fw')
%span
Merge Requests
%span.count= current_user.assigned_merge_requests.opened.count
= nav_link(controller: :snippets) do
= link_to (current_user ? user_snippets_path(current_user) : snippets_path), title: 'Your snippets', data: {placement: 'right'} do
= icon('clipboard fw')
%span
Milestones
= nav_link(path: 'dashboard#issues') do
= link_to assigned_issues_dashboard_path, title: 'Issues', class: 'shortcuts-issues', data: {placement: 'right'} do
= icon('exclamation-circle fw')
%span
Issues
%span.count= current_user.assigned_issues.opened.count
= nav_link(path: 'dashboard#merge_requests') do
= link_to assigned_mrs_dashboard_path, title: 'Merge Requests', class: 'shortcuts-merge_requests', data: {placement: 'right'} do
= icon('tasks fw')
%span
Merge Requests
%span.count= current_user.assigned_merge_requests.opened.count
Snippets
- if current_user
= nav_link(controller: :profile) do
= link_to profile_path, title: 'Profile settings', data: {toggle: 'tooltip', placement: 'bottom'} do
= icon('user fw')
%span
Profile
= nav_link(controller: :help) do
= link_to help_path, title: 'Help', data: {placement: 'right'} do
= icon('question-circle fw')
-18
View File
@@ -1,18 +0,0 @@
%ul.nav.nav-sidebar
= nav_link(path: 'projects#trending') do
= link_to explore_root_path, title: 'Trending Projects', data: {placement: 'right'} do
= icon('comments fw')
%span Trending Projects
= nav_link(path: 'projects#starred') do
= link_to starred_explore_projects_path, title: 'Most-starred Projects', data: {placement: 'right'} do
= icon('star fw')
%span Most-starred Projects
= nav_link(path: 'projects#index') do
= link_to explore_projects_path, title: 'All Projects', data: {placement: 'right'} do
= icon('bookmark fw')
%span All Projects
= nav_link(controller: :groups) do
= link_to explore_groups_path, title: 'All Groups', data: {placement: 'right'} do
= icon('group fw')
%span All Groups
-12
View File
@@ -1,12 +0,0 @@
%ul.nav.nav-sidebar
- if current_user
= nav_link(path: user_snippets_path(current_user), html_options: {class: 'home'}) do
= link_to user_snippets_path(current_user), title: 'Your snippets', data: {placement: 'right'} do
= icon('dashboard fw')
%span
Your Snippets
= nav_link(path: snippets_path) do
= link_to snippets_path, title: 'Discover snippets', data: {placement: 'right'} do
= icon('globe fw')
%span
Discover Snippets
+5 -1
View File
@@ -36,7 +36,11 @@
&mdash;
%br
- if @target_url
#{link_to "View it on GitLab", @target_url}
- if @reply_by_email
Reply to this email directly or
#{link_to "view it on GitLab", @target_url}.
- else
#{link_to "View it on GitLab", @target_url}
= email_action @target_url
- if @project && !@disable_footer
You're receiving this notification because you are a member of the #{link_to_unless @target_url, @project.name_with_namespace, namespace_project_url(@project.namespace, @project)} project team.
+5 -2
View File
@@ -1,5 +1,8 @@
- page_title 'Snippets'
- header_title 'Snippets', snippets_path
- sidebar "snippets"
- if current_user
- header_title "Dashboard", root_path
- else
- header_title 'Snippets', snippets_path
- sidebar "dashboard"
= render template: "layouts/application"
@@ -1,6 +1,8 @@
%p.slead
Should you ever lose your phone, each of these recovery codes can be used one
time each to regain access to your account. Please save them in a safe place.
time each to regain access to your account. Please save them in a safe place, or you
%b will
lose access to your account.
.codes.well
%ul
@@ -5,9 +5,9 @@
%a.close{href: "#", "data-dismiss" => "modal"} ×
%h3 Import projects from Bitbucket
.modal-body
To enable importing projects from Bitbucket,
To enable importing projects from Bitbucket,
- if current_user.admin?
you need to
as administrator you need to configure
- else
your GitLab administrator needs to
== #{link_to 'setup OAuth integration', 'https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/integration/bitbucket.md'}.
ask your GitLab administrator to configure
== #{link_to 'OAuth integration', help_page_path("integration", "bitbucket")}.
@@ -5,9 +5,9 @@
%a.close{href: "#", "data-dismiss" => "modal"} ×
%h3 Import projects from GitHub
.modal-body
To enable importing projects from GitHub,
To enable importing projects from GitHub,
- if current_user.admin?
you need to
as administrator you need to configure
- else
your GitLab administrator needs to
== #{link_to 'setup OAuth integration', 'https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/integration/github.md'}.
ask your Gitlab administrator to configure
== #{link_to 'OAuth integration', help_page_path("integration", "github")}.
@@ -5,9 +5,9 @@
%a.close{href: "#", "data-dismiss" => "modal"} ×
%h3 Import projects from GitLab.com
.modal-body
To enable importing projects from GitLab.com,
To enable importing projects from GitLab.com,
- if current_user.admin?
you need to
as administrator you need to configure
- else
your GitLab administrator needs to
== #{link_to 'setup OAuth integration', 'https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/integration/gitlab.md'}.
ask your GitLab administrator to configure
== #{link_to 'OAuth integration', help_page_path("integration", "gitlab")}.
+1 -1
View File
@@ -2,7 +2,7 @@
.project-home-panel.clearfix{:class => ("empty-project" if empty_repo)}
.project-identicon-holder
= project_icon(@project, alt: '', class: 'project-avatar avatar s90')
.project-home-desc.lead
.project-home-desc
%h1= @project.name
- if @project.description.present?
= markdown(@project.description, pipeline: :description)
+20 -18
View File
@@ -13,30 +13,32 @@
.file-content.blame.highlight
%table
- current_line = 1
- @blame.each do |raw_commit, line|
- @blame.each do |blame_group|
%tr
%td.blame-commit
.commit
- unless @prev_commit && @prev_commit.sha == raw_commit.sha
- commit = Commit.new(raw_commit, @project)
.commit-row-title
%strong
= link_to_gfm truncate(commit.title, length: 35), namespace_project_commit_path(@project.namespace, @project, commit.id), class: "cdark"
.pull-right
= link_to commit.short_id, namespace_project_commit_path(@project.namespace, @project, commit), class: "monospace"
&nbsp;
.light
= commit_author_link(commit, avatar: false)
authored
#{time_ago_with_tooltip(commit.committed_date)}
- @prev_commit = raw_commit
- commit = Commit.new(blame_group[:commit], @project)
.commit-row-title
%strong
= link_to_gfm truncate(commit.title, length: 35), namespace_project_commit_path(@project.namespace, @project, commit.id), class: "cdark"
.pull-right
= link_to commit.short_id, namespace_project_commit_path(@project.namespace, @project, commit), class: "monospace"
&nbsp;
.light
= commit_author_link(commit, avatar: false)
authored
#{time_ago_with_tooltip(commit.committed_date, skip_js: true)}
%td.lines.blame-numbers
%pre
= current_line
- current_line += 1
- line_count = blame_group[:lines].count
- (current_line...(current_line + line_count)).each do |i|
= i
\
- current_line += line_count
%td.lines
%pre{class: 'code highlight white'}
%code
:erb
<%= highlight(@blob.name, line, nowrap: true, continue: true).html_safe %>
- blame_group[:lines].each do |line|
:erb
<%= highlight(@blob.name, line, nowrap: true, continue: true).html_safe %>
@@ -2,7 +2,7 @@
%span.dropdown
%a.dropdown-toggle.btn.btn-new{href: '#', "data-toggle" => "dropdown"}
= icon('plus')
%ul.dropdown-menu
%ul.dropdown-menu.dropdown-menu-right.project-home-dropdown
- if can?(current_user, :create_issue, @project)
%li
= link_to url_for_new_issue do
@@ -1,4 +1,5 @@
- page_title "Deploy Keys"
%h3.page-title
Deploy keys allow read-only access to the repository

Some files were not shown because too many files have changed in this diff Show More