Commit fe86c8df authored by Douwe Maan's avatar Douwe Maan

Merge branch 'master' into joelkoglin/gitlab-ce-feature_fix_ldap_auth_issue_993

parents d92f4280 a429eb4d
...@@ -25,6 +25,7 @@ config/initializers/rack_attack.rb ...@@ -25,6 +25,7 @@ config/initializers/rack_attack.rb
config/initializers/smtp_settings.rb config/initializers/smtp_settings.rb
config/resque.yml config/resque.yml
config/unicorn.rb config/unicorn.rb
config/mail_room.yml
coverage/* coverage/*
db/*.sqlite3 db/*.sqlite3
db/*.sqlite3-journal db/*.sqlite3-journal
......
Please view this file on the master branch, on stable branches it's out of date. Please view this file on the master branch, on stable branches it's out of date.
v 8.0.0 (unreleased) v 8.0.0 (unreleased)
- Upgrade gitlab_git to 7.2.15 to fix `git blame` errors with ISO-encoded files (Stan Hu)
- Prevent too many redirects upon login when home page URL is set to external_url (Stan Hu)
- 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)
- 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) - Only show recent push event if the branch still exists or a recent merge request has not been created (Stan Hu)
- Remove satellites - Remove satellites
- Better performance for web editor (switched from satellites to rugged) - Better performance for web editor (switched from satellites to rugged)
...@@ -9,8 +14,26 @@ v 8.0.0 (unreleased) ...@@ -9,8 +14,26 @@ v 8.0.0 (unreleased)
- Allow displaying of archived projects in the admin interface (Artem Sidorenko) - Allow displaying of archived projects in the admin interface (Artem Sidorenko)
- Allow configuration of import sources for new projects (Artem Sidorenko) - Allow configuration of import sources for new projects (Artem Sidorenko)
- Search for comments should be case insensetive - Search for comments should be case insensetive
- Create cross-reference for closing references on commits pushed to non-default branches (Maël Valais)
v 7.14.0 (unreleased) - Ability to search milestones
- Gracefully handle SMTP user input errors (e.g. incorrect email addresses) to prevent Sidekiq retries (Stan Hu)
- 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
- Fix 500 error when submit project snippet without body
- Improve search page usability
- Bring more UI consistency in way how projects, snippets and groups lists are rendered
- Make all profiles public
v 7.14.1
- Improve abuse reports management from admin area
- Fix "Reload with full diff" URL button in compare branch view (Stan Hu)
- 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)
- Ability to enable SSL verification for Webhooks
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) - 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 - 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) - Upgrade gitlab_git to 7.2.14 to ignore CRLFs in .gitmodules (Stan Hu)
...@@ -294,6 +317,7 @@ v 7.11.0 ...@@ -294,6 +317,7 @@ v 7.11.0
- Protect OmniAuth request phase against CSRF. - Protect OmniAuth request phase against CSRF.
- Don't send notifications to mentioned users that don't have access to the project in question. - Don't send notifications to mentioned users that don't have access to the project in question.
- Add search issues/MR by number - Add search issues/MR by number
- Change plots to bar graphs in commit statistics screen
- Move snippets UI to fluid layout - Move snippets UI to fluid layout
- Improve UI for sidebar. Increase separation between navigation and content - Improve UI for sidebar. Increase separation between navigation and content
- Improve new project command options (Ben Bodenmiller) - Improve new project command options (Ben Bodenmiller)
......
...@@ -34,11 +34,11 @@ gem 'rqrcode-rails3' ...@@ -34,11 +34,11 @@ gem 'rqrcode-rails3'
gem 'attr_encrypted', '1.3.4' gem 'attr_encrypted', '1.3.4'
# Browser detection # Browser detection
gem "browser", '~> 0.8.0' gem "browser", '~> 1.0.0'
# Extracting information from a git repository # Extracting information from a git repository
# Provide access to Gitlab::Git library # Provide access to Gitlab::Git library
gem "gitlab_git", '~> 7.2.14' gem "gitlab_git", '~> 7.2.15'
# Ruby/Rack Git Smart-HTTP Server Handler # Ruby/Rack Git Smart-HTTP Server Handler
# GitLab fork with a lot of changes (improved thread-safety, better memory usage etc) # GitLab fork with a lot of changes (improved thread-safety, better memory usage etc)
...@@ -272,3 +272,7 @@ end ...@@ -272,3 +272,7 @@ end
gem "newrelic_rpm" gem "newrelic_rpm"
gem 'octokit', '3.7.0' gem 'octokit', '3.7.0'
gem "mail_room", "~> 0.4.1"
gem 'email_reply_parser'
...@@ -76,7 +76,7 @@ GEM ...@@ -76,7 +76,7 @@ GEM
ruby_parser (~> 3.5.0) ruby_parser (~> 3.5.0)
sass (~> 3.0) sass (~> 3.0)
terminal-table (~> 1.4) terminal-table (~> 1.4)
browser (0.8.0) browser (1.0.0)
builder (3.2.2) builder (3.2.2)
byebug (3.2.0) byebug (3.2.0)
columnize (~> 0.8) columnize (~> 0.8)
...@@ -156,6 +156,7 @@ GEM ...@@ -156,6 +156,7 @@ GEM
dotenv (0.9.0) dotenv (0.9.0)
dropzonejs-rails (0.7.1) dropzonejs-rails (0.7.1)
rails (> 3.1) rails (> 3.1)
email_reply_parser (0.5.8)
email_spec (1.6.0) email_spec (1.6.0)
launchy (~> 2.1) launchy (~> 2.1)
mail (~> 2.2) mail (~> 2.2)
...@@ -275,7 +276,7 @@ GEM ...@@ -275,7 +276,7 @@ GEM
mime-types (~> 1.19) mime-types (~> 1.19)
gitlab_emoji (0.1.0) gitlab_emoji (0.1.0)
gemojione (~> 2.0) gemojione (~> 2.0)
gitlab_git (7.2.14) gitlab_git (7.2.15)
activesupport (~> 4.0) activesupport (~> 4.0)
charlock_holmes (~> 0.6) charlock_holmes (~> 0.6)
gitlab-linguist (~> 3.0) gitlab-linguist (~> 3.0)
...@@ -371,6 +372,7 @@ GEM ...@@ -371,6 +372,7 @@ GEM
systemu (~> 2.6.2) systemu (~> 2.6.2)
mail (2.6.3) mail (2.6.3)
mime-types (>= 1.16, < 3) mime-types (>= 1.16, < 3)
mail_room (0.4.1)
method_source (0.8.2) method_source (0.8.2)
mime-types (1.25.1) mime-types (1.25.1)
mimemagic (0.3.0) mimemagic (0.3.0)
...@@ -753,7 +755,7 @@ DEPENDENCIES ...@@ -753,7 +755,7 @@ DEPENDENCIES
binding_of_caller binding_of_caller
bootstrap-sass (~> 3.0) bootstrap-sass (~> 3.0)
brakeman brakeman
browser (~> 0.8.0) browser (~> 1.0.0)
byebug byebug
cal-heatmap-rails (~> 0.0.1) cal-heatmap-rails (~> 0.0.1)
capybara (~> 2.4.0) capybara (~> 2.4.0)
...@@ -773,6 +775,7 @@ DEPENDENCIES ...@@ -773,6 +775,7 @@ DEPENDENCIES
diffy (~> 3.0.3) diffy (~> 3.0.3)
doorkeeper (= 2.1.3) doorkeeper (= 2.1.3)
dropzonejs-rails dropzonejs-rails
email_reply_parser
email_spec (~> 1.6.0) email_spec (~> 1.6.0)
enumerize enumerize
factory_girl_rails factory_girl_rails
...@@ -787,7 +790,7 @@ DEPENDENCIES ...@@ -787,7 +790,7 @@ DEPENDENCIES
gitlab-grack (~> 2.0.2) gitlab-grack (~> 2.0.2)
gitlab-linguist (~> 3.0.1) gitlab-linguist (~> 3.0.1)
gitlab_emoji (~> 0.1) gitlab_emoji (~> 0.1)
gitlab_git (~> 7.2.14) gitlab_git (~> 7.2.15)
gitlab_meta (= 7.0) gitlab_meta (= 7.0)
gitlab_omniauth-ldap (= 1.2.1) gitlab_omniauth-ldap (= 1.2.1)
gollum-lib (~> 4.0.2) gollum-lib (~> 4.0.2)
...@@ -805,6 +808,7 @@ DEPENDENCIES ...@@ -805,6 +808,7 @@ DEPENDENCIES
jquery-ui-rails jquery-ui-rails
kaminari (~> 0.15.1) kaminari (~> 0.15.1)
letter_opener letter_opener
mail_room (~> 0.4.1)
minitest (~> 5.3.0) minitest (~> 5.3.0)
mousetrap-rails mousetrap-rails
mysql2 mysql2
......
web: bundle exec unicorn_rails -p ${PORT:="3000"} -E ${RAILS_ENV:="development"} -c ${UNICORN_CONFIG:="config/unicorn.rb"} 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
...@@ -116,6 +116,12 @@ $ -> ...@@ -116,6 +116,12 @@ $ ->
$('.remove-row').bind 'ajax:success', -> $('.remove-row').bind 'ajax:success', ->
$(this).closest('li').fadeOut() $(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 # Initialize select2 selects
$('select.select2').select2(width: 'resolve', dropdownAutoWidth: true) $('select.select2').select2(width: 'resolve', dropdownAutoWidth: true)
......
...@@ -51,10 +51,10 @@ class Dispatcher ...@@ -51,10 +51,10 @@ class Dispatcher
MergeRequests.init() MergeRequests.init()
when 'dashboard:show', 'root:show' when 'dashboard:show', 'root:show'
new Dashboard() new Dashboard()
when 'dashboard:activity'
new Activities() new Activities()
when 'dashboard:projects:starred' when 'dashboard:projects:starred'
new Activities() new Activities()
new ProjectsList()
when 'projects:commit:show' when 'projects:commit:show'
new Commit() new Commit()
new Diff() new Diff()
...@@ -69,7 +69,6 @@ class Dispatcher ...@@ -69,7 +69,6 @@ class Dispatcher
when 'groups:show' when 'groups:show'
new Activities() new Activities()
shortcut_handler = new ShortcutsNavigation() shortcut_handler = new ShortcutsNavigation()
new ProjectsList()
when 'groups:group_members:index' when 'groups:group_members:index'
new GroupMembers() new GroupMembers()
new UsersSelect() new UsersSelect()
...@@ -95,8 +94,6 @@ class Dispatcher ...@@ -95,8 +94,6 @@ class Dispatcher
when 'users:show' when 'users:show'
new User() new User()
new Activities() new Activities()
when 'admin:users:show'
new ProjectsList()
switch path.first() switch path.first()
when 'admin' when 'admin'
......
...@@ -8,7 +8,7 @@ class @ProjectsList ...@@ -8,7 +8,7 @@ class @ProjectsList
$(".projects-list-filter").keyup -> $(".projects-list-filter").keyup ->
terms = $(this).val() terms = $(this).val()
uiBox = $(this).closest('.panel') uiBox = $(this).closest('.projects-list-holder')
if terms == "" || terms == undefined if terms == "" || terms == undefined
uiBox.find(".projects-list li").show() uiBox.find(".projects-list li").show()
else else
......
# Applies a syntax highlighting color scheme CSS class to any element with the
# `js-syntax-highlight` class
#
# ### Example Markup
#
# <div class="js-syntax-highlight"></div>
#
$(document).on 'ready page:load', ->
$('.js-syntax-highlight').addClass(gon.user_color_scheme)
...@@ -6,6 +6,7 @@ class @UsersSelect ...@@ -6,6 +6,7 @@ class @UsersSelect
$('.ajax-users-select').each (i, select) => $('.ajax-users-select').each (i, select) =>
@projectId = $(select).data('project-id') @projectId = $(select).data('project-id')
@groupId = $(select).data('group-id') @groupId = $(select).data('group-id')
@showCurrentUser = $(select).data('current-user')
showNullUser = $(select).data('null-user') showNullUser = $(select).data('null-user')
showAnyUser = $(select).data('any-user') showAnyUser = $(select).data('any-user')
showEmailUser = $(select).data('email-user') showEmailUser = $(select).data('email-user')
...@@ -108,6 +109,7 @@ class @UsersSelect ...@@ -108,6 +109,7 @@ class @UsersSelect
active: true active: true
project_id: @projectId project_id: @projectId
group_id: @groupId group_id: @groupId
current_user: @showCurrentUser
dataType: "json" dataType: "json"
).done (users) -> ).done (users) ->
callback(users) callback(users)
......
...@@ -20,3 +20,8 @@ html { ...@@ -20,3 +20,8 @@ html {
.navless-container { .navless-container {
margin-top: 30px; margin-top: 30px;
} }
.container-limited {
max-width: $fixed-layout-width;
}
...@@ -157,3 +157,41 @@ ...@@ -157,3 +157,41 @@
white-space: nowrap; white-space: nowrap;
max-width: $max_width; max-width: $max_width;
} }
/*
* Base mixin for lists in GitLab
*/
@mixin basic-list {
margin: 5px 0px;
padding: 0px;
list-style: none;
li {
padding: 10px 0;
border-bottom: 1px solid #EEE;
overflow: hidden;
display: block;
margin: 0px;
&:last-child {
border:none
}
&.active {
background: #f9f9f9;
a {
font-weight: bold;
}
}
&.hide {
display: none;
}
&.light {
a {
color: #777;
}
}
}
}
...@@ -13,7 +13,7 @@ $code_line_height: 1.5; ...@@ -13,7 +13,7 @@ $code_line_height: 1.5;
$border-color: #E5E5E5; $border-color: #E5E5E5;
$background-color: #f5f5f5; $background-color: #f5f5f5;
$header-height: 50px; $header-height: 50px;
$readable-width: 1100px; $fixed-layout-width: 1200px;
/* /*
......
...@@ -132,10 +132,6 @@ p.time { ...@@ -132,10 +132,6 @@ p.time {
text-shadow: none; text-shadow: none;
} }
.highlight_word {
background: #fafe3d;
}
.thin_area{ .thin_area{
height: 150px; height: 150px;
} }
...@@ -375,9 +371,9 @@ table { ...@@ -375,9 +371,9 @@ table {
} }
.center-top-menu { .center-top-menu {
border-bottom: 1px solid #EEE;
list-style: none; list-style: none;
text-align: center; text-align: center;
margin-top: 5px;
padding-bottom: 15px; padding-bottom: 15px;
margin-bottom: 15px; margin-bottom: 15px;
...@@ -385,7 +381,7 @@ table { ...@@ -385,7 +381,7 @@ table {
display: inline-block; display: inline-block;
a { a {
padding: 10px; padding: 15px;
} }
&.active a { &.active a {
......
...@@ -20,16 +20,16 @@ header { ...@@ -20,16 +20,16 @@ header {
} }
&.navbar-gitlab { &.navbar-gitlab {
padding: 0 20px;
z-index: 100; z-index: 100;
margin-bottom: 0; margin-bottom: 0;
min-height: $header-height; min-height: $header-height;
border: none; border: none;
width: 100%; border-bottom: 1px solid #EEE;
.container { .container-fluid {
background: #FFF; background: #FFF;
width: 100% !important; width: 100% !important;
padding: 0;
filter: none; filter: none;
.nav > li > a { .nav > li > a {
...@@ -64,55 +64,11 @@ header { ...@@ -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 { .header-content {
border-bottom: 1px solid #EEE;
padding-right: 35px;
height: $header-height; height: $header-height;
.title { .title {
margin: 0; margin: 0;
padding: 0 15px 0 35px;
overflow: hidden; overflow: hidden;
font-size: 18px; font-size: 18px;
line-height: $header-height; line-height: $header-height;
...@@ -168,15 +124,7 @@ header { ...@@ -168,15 +124,7 @@ header {
} }
@mixin collapsed-header { @mixin collapsed-header {
.header-logo { margin-left: $sidebar_collapsed_width;
width: $sidebar_collapsed_width;
}
.header-content {
.title {
margin-left: 30px;
}
}
} }
@media (max-width: $screen-md-max) { @media (max-width: $screen-md-max) {
...@@ -191,16 +139,14 @@ header { ...@@ -191,16 +139,14 @@ header {
} }
.header-expanded { .header-expanded {
margin-left: $sidebar_width;
} }
} }
@media (max-width: $screen-xs-max) { @media (max-width: $screen-xs-max) {
header .container { header .container-fluid {
font-size: 18px; font-size: 18px;
.title {
}
.navbar-nav { .navbar-nav {
margin: 0px; margin: 0px;
float: none !important; float: none !important;
......
...@@ -93,28 +93,12 @@ ol, ul { ...@@ -93,28 +93,12 @@ ol, ul {
/** light list with border-bottom between li **/ /** light list with border-bottom between li **/
ul.bordered-list { ul.bordered-list {
margin: 5px 0px; @include basic-list;
padding: 0px;
li {
padding: 5px 0;
border-bottom: 1px solid #EEE;
overflow: hidden;
display: block;
margin: 0px;
&:last-child { border:none }
&.active {
background: #f9f9f9;
a { font-weight: bold; }
}
&.light {
a { color: #777; }
}
}
&.top-list { &.top-list {
li:first-child { li:first-child {
padding-top: 0; padding-top: 0;
h4, h5 { h4, h5 {
margin-top: 0; margin-top: 0;
} }
......
...@@ -188,3 +188,46 @@ ...@@ -188,3 +188,46 @@
width: $sidebar_width - 2 * 10px; 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;
}
}
}
...@@ -21,6 +21,12 @@ pre.code.highlight.dark, ...@@ -21,6 +21,12 @@ pre.code.highlight.dark,
background-color: #557 !important; background-color: #557 !important;
} }
// Search result highlight
span.highlight_word {
background: #ffe792;
color: #000000;
}
.hll { background-color: #373b41 } .hll { background-color: #373b41 }
.c { color: #969896 } /* Comment */ .c { color: #969896 } /* Comment */
.err { color: #cc6666 } /* Error */ .err { color: #cc6666 } /* Error */
......
...@@ -21,6 +21,12 @@ pre.code.monokai, ...@@ -21,6 +21,12 @@ pre.code.monokai,
background-color: #49483e !important; background-color: #49483e !important;
} }
// Search result highlight
span.highlight_word {
background: #ffe792;
color: #000000;
}
.hll { background-color: #49483e } .hll { background-color: #49483e }
.c { color: #75715e } /* Comment */ .c { color: #75715e } /* Comment */
.err { color: #960050; background-color: #1e0010 } /* Error */ .err { color: #960050; background-color: #1e0010 } /* Error */
......
...@@ -21,6 +21,11 @@ pre.code.highlight.solarized-dark, ...@@ -21,6 +21,11 @@ pre.code.highlight.solarized-dark,
background-color: #174652 !important; background-color: #174652 !important;
} }
// Search result highlight
span.highlight_word {
background: #094554;
}
/* Solarized Dark /* Solarized Dark
For use with Jekyll and Pygments For use with Jekyll and Pygments
......
...@@ -21,6 +21,11 @@ pre.code.highlight.solarized-light, ...@@ -21,6 +21,11 @@ pre.code.highlight.solarized-light,
background-color: #ddd8c5 !important; background-color: #ddd8c5 !important;
} }
// Search result highlight
span.highlight_word {
background: #eee8d5;
}
/* Solarized Light /* Solarized Light
For use with Jekyll and Pygments For use with Jekyll and Pygments
......
...@@ -21,6 +21,11 @@ pre.code.highlight.white, ...@@ -21,6 +21,11 @@ pre.code.highlight.white,
background-color: #f8eec7 !important; background-color: #f8eec7 !important;
} }
// Search result highlight
span.highlight_word {
background: #fafe3d;
}
.hll { background-color: #f8f8f8 } .hll { background-color: #f8f8f8 }
.c { color: #999988; font-style: italic; } .c { color: #999988; font-style: italic; }
.err { color: #a61717; background-color: #e3d2d2; } .err { color: #a61717; background-color: #e3d2d2; }
......
...@@ -23,41 +23,6 @@ ...@@ -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 { .project-access-icon {
margin-left: 10px; margin-left: 10px;
float: left; float: left;
...@@ -73,10 +38,9 @@ ...@@ -73,10 +38,9 @@
float: left; float: left;
.avatar { .avatar {
margin-top: -8px;
margin-left: -15px;
@include border-radius(0px); @include border-radius(0px);
} }
.identicon { .identicon {
line-height: 40px; line-height: 40px;
} }
......
...@@ -45,9 +45,3 @@ ...@@ -45,9 +45,3 @@
.btn { font-size: 13px; } .btn { font-size: 13px; }
} }
.issuable-details {
.description {
max-width: $readable-width;
}
}
...@@ -30,14 +30,21 @@ ...@@ -30,14 +30,21 @@
} }
} }
.project-home-dropdown {
margin: 11px 3px 0;
}
.project-home-desc { .project-home-desc {
h1 { h1 {
margin: 0; margin: 0;
margin-bottom: 10px; margin-bottom: 10px;
font-size: 26px; font-size: 26px;
font-weight: bold;
} }
p { p {
font-size: 18px;
color: #666;
display: inline; display: inline;
} }
} }
...@@ -155,78 +162,6 @@ ul.nav.nav-projects-tabs { ...@@ -155,78 +162,6 @@ ul.nav.nav-projects-tabs {
margin: 0px; margin: 0px;
} }
.my-projects,
.public-projects {
li {
.project-info {
margin-bottom: 10px;
overflow: hidden;
}
.access-icon {
color: #AAA;
margin-left: 10px;
i {
color: #AAA;
}
}
}
}
.public-clone {
background: #EEE;
color: #777;
padding: 6px 10px;
margin: 1px;
font-weight: normal;
}
.public-projects .repo-info {
color: #777;
a {
color: #777;
}
}
.project-side {
.project-fork-icon {
float: left;
font-size: 26px;
margin-right: 10px;
line-height: 1.5;
}
.panel {
@include border-radius(3px);
.panel-heading, .panel-footer {
font-weight: normal;
background-color: transparent;
color: #666;
border-color: #EEE;
}
.actions {
margin-top: 10px;
}
.nav-pills a {
padding: 10px;
font-weight: bold;
color: $gl-link-color;
}
.nav {
margin-bottom: 15px;
}
}
.ci-status-image {
max-height: 22px;
}
}
.transfer-project .select2-container { .transfer-project .select2-container {
min-width: 200px; min-width: 200px;
} }
...@@ -316,3 +251,43 @@ table.table.protected-branches-list tr.no-border { ...@@ -316,3 +251,43 @@ table.table.protected-branches-list tr.no-border {
pre.light-well { pre.light-well {
border-color: #f1f1f1; border-color: #f1f1f1;
} }
.projects-search-form {
max-width: 600px;
margin: 0 auto;
margin-bottom: 20px;
input {
border-color: #BBB;
}
}
/*
* Projects list rendered on dashboard and user page
*/
.projects-list {
@include basic-list;
.project-row {
.project-full-name {
@include str-truncated;
font-weight: bold;
font-size: 15px;
}
.project-description {
color: #888;
font-size: 13px;
p {
@include str-truncated;
margin-bottom: 0;
color: #888;
}
}
}
}
.panel .projects-list li {
padding: 10px 15px;
}
.search-results { .search-results {
.search-result-row { .search-result-row {
border-bottom: 1px solid #EEE; border-bottom: 1px solid #DDD;
padding-bottom: 10px; padding-bottom: 15px;
margin-bottom: 10px; margin-bottom: 15px;
} }
} }
.search-holder {
max-width: 600px;
margin: 0 auto;
margin-bottom: 20px;
input {
border-color: #BBB;
font-weight: bold;
}
}
...@@ -6,3 +6,27 @@ ...@@ -6,3 +6,27 @@
.snippet-form-holder .file-holder .file-title { .snippet-form-holder .file-holder .file-title {
padding: 2px; padding: 2px;
} }
.snippet-row {
.snippet-title {
font-size: 15px;
font-weight: bold;
line-height: 20px;
margin-bottom: 2px;
.monospace {
font-weight: normal;
}
}
.snippet-info {
color: #888;
font-size: 13px;
line-height: 24px;
a {
color: #888;
}
}
}
...@@ -117,7 +117,6 @@ ...@@ -117,7 +117,6 @@
.readme-holder { .readme-holder {
margin: 0 auto; margin: 0 auto;
max-width: $readable-width;
.readme-file-title { .readme-file-title {
font-size: 14px; font-size: 14px;
......
...@@ -7,8 +7,7 @@ ...@@ -7,8 +7,7 @@
* $color-dark - * $color-dark -
*/ */
@mixin gitlab-theme($color-light, $color, $color-darker, $color-dark) { @mixin gitlab-theme($color-light, $color, $color-darker, $color-dark) {
header { .page-with-sidebar {
&.navbar-gitlab {
.header-logo { .header-logo {
background-color: $color-darker; background-color: $color-darker;
border-color: $color-darker; border-color: $color-darker;
...@@ -24,10 +23,7 @@ ...@@ -24,10 +23,7 @@
} }
} }
} }
}
}
.page-with-sidebar {
.collapse-nav a { .collapse-nav a {
color: #FFF; color: #FFF;
background: $color; background: $color;
......
...@@ -4,8 +4,13 @@ class Admin::AbuseReportsController < Admin::ApplicationController ...@@ -4,8 +4,13 @@ class Admin::AbuseReportsController < Admin::ApplicationController
end end
def destroy 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
end end
...@@ -39,6 +39,6 @@ class Admin::HooksController < Admin::ApplicationController ...@@ -39,6 +39,6 @@ class Admin::HooksController < Admin::ApplicationController
end end
def hook_params def hook_params
params.require(:hook).permit(:url) params.require(:hook).permit(:url, :enable_ssl_verification)
end end
end end
...@@ -55,7 +55,9 @@ class ApplicationController < ActionController::Base ...@@ -55,7 +55,9 @@ class ApplicationController < ActionController::Base
def authenticate_user!(*args) def authenticate_user!(*args)
# If user is not signed-in and tries to access root_path - redirect him to landing page # If user is not signed-in and tries to access root_path - redirect him to landing page
if current_application_settings.home_page_url.present? # Don't redirect to the default URL to prevent endless redirections
if current_application_settings.home_page_url.present? &&
current_application_settings.home_page_url.chomp('/') != Gitlab.config.gitlab['url'].chomp('/')
if current_user.nil? && root_path == request.path if current_user.nil? && root_path == request.path
redirect_to current_application_settings.home_page_url and return redirect_to current_application_settings.home_page_url and return
end end
...@@ -190,11 +192,12 @@ class ApplicationController < ActionController::Base ...@@ -190,11 +192,12 @@ class ApplicationController < ActionController::Base
end end
def add_gon_variables def add_gon_variables
gon.default_issues_tracker = Project.new.default_issue_tracker.to_param
gon.api_version = API::API.version gon.api_version = API::API.version
gon.relative_url_root = Gitlab.config.gitlab.relative_url_root
gon.default_avatar_url = URI::join(Gitlab.config.gitlab.url, ActionController::Base.helpers.image_path('no_avatar.png')).to_s gon.default_avatar_url = URI::join(Gitlab.config.gitlab.url, ActionController::Base.helpers.image_path('no_avatar.png')).to_s
gon.max_file_size = current_application_settings.max_attachment_size; gon.default_issues_tracker = Project.new.default_issue_tracker.to_param
gon.max_file_size = current_application_settings.max_attachment_size
gon.relative_url_root = Gitlab.config.gitlab.relative_url_root
gon.user_color_scheme = Gitlab::ColorSchemes.for_user(current_user).css_class
if current_user if current_user
gon.current_user_id = current_user.id gon.current_user_id = current_user.id
......
...@@ -33,8 +33,14 @@ class AutocompleteController < ApplicationController ...@@ -33,8 +33,14 @@ class AutocompleteController < ApplicationController
@users = @users.search(params[:search]) if params[:search].present? @users = @users.search(params[:search]) if params[:search].present?
@users = @users.active @users = @users.active
@users = @users.page(params[:page]).per(PER_PAGE) @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] render json: @users, only: [:name, :username, :id], methods: [:avatar_url]
end end
......
class DashboardController < Dashboard::ApplicationController class DashboardController < Dashboard::ApplicationController
before_action :load_projects before_action :load_projects
before_action :event_filter, only: :show before_action :event_filter, only: :activity
respond_to :html respond_to :html
...@@ -10,13 +10,8 @@ class DashboardController < Dashboard::ApplicationController ...@@ -10,13 +10,8 @@ class DashboardController < Dashboard::ApplicationController
respond_to do |format| respond_to do |format|
format.html format.html
format.json do
load_events
pager_json("events/_events", @events.count)
end
format.atom do format.atom do
event_filter
load_events load_events
render layout: false render layout: false
end end
...@@ -40,6 +35,19 @@ class DashboardController < Dashboard::ApplicationController ...@@ -40,6 +35,19 @@ class DashboardController < Dashboard::ApplicationController
end end
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 protected
def load_projects def load_projects
......
...@@ -13,10 +13,9 @@ class Import::BitbucketController < Import::BaseController ...@@ -13,10 +13,9 @@ class Import::BitbucketController < Import::BaseController
access_token = client.get_token(request_token, params[:oauth_verifier], callback_import_bitbucket_url) access_token = client.get_token(request_token, params[:oauth_verifier], callback_import_bitbucket_url)
current_user.bitbucket_access_token = access_token.token session[:bitbucket_access_token] = access_token.token
current_user.bitbucket_access_token_secret = access_token.secret session[:bitbucket_access_token_secret] = access_token.secret
current_user.save
redirect_to status_import_bitbucket_url redirect_to status_import_bitbucket_url
end end
...@@ -46,19 +45,20 @@ class Import::BitbucketController < Import::BaseController ...@@ -46,19 +45,20 @@ class Import::BitbucketController < Import::BaseController
namespace = get_or_create_namespace || (render and return) 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 @access_denied = true
render render
return return
end end
@project = Gitlab::BitbucketImport::ProjectCreator.new(repo, namespace, current_user).execute @project = Gitlab::BitbucketImport::ProjectCreator.new(repo, namespace, current_user, access_params).execute
end end
private private
def client 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 end
def verify_bitbucket_import_enabled def verify_bitbucket_import_enabled
...@@ -66,7 +66,7 @@ class Import::BitbucketController < Import::BaseController ...@@ -66,7 +66,7 @@ class Import::BitbucketController < Import::BaseController
end end
def bitbucket_auth def bitbucket_auth
if current_user.bitbucket_access_token.blank? if session[:bitbucket_access_token].blank?
go_to_bitbucket_for_permissions go_to_bitbucket_for_permissions
end end
end end
...@@ -81,4 +81,13 @@ class Import::BitbucketController < Import::BaseController ...@@ -81,4 +81,13 @@ class Import::BitbucketController < Import::BaseController
def bitbucket_unauthorized def bitbucket_unauthorized
go_to_bitbucket_for_permissions go_to_bitbucket_for_permissions
end end
private
def access_params
{
bitbucket_access_token: session[:bitbucket_access_token],
bitbucket_access_token_secret: session[:bitbucket_access_token_secret]
}
end
end end
...@@ -5,9 +5,7 @@ class Import::GithubController < Import::BaseController ...@@ -5,9 +5,7 @@ class Import::GithubController < Import::BaseController
rescue_from Octokit::Unauthorized, with: :github_unauthorized rescue_from Octokit::Unauthorized, with: :github_unauthorized
def callback def callback
token = client.get_token(params[:code]) session[:github_access_token] = client.get_token(params[:code])
current_user.github_access_token = token
current_user.save
redirect_to status_import_github_url redirect_to status_import_github_url
end end
...@@ -39,13 +37,13 @@ class Import::GithubController < Import::BaseController ...@@ -39,13 +37,13 @@ class Import::GithubController < Import::BaseController
namespace = get_or_create_namespace || (render and return) 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 end
private private
def client def client
@client ||= Gitlab::GithubImport::Client.new(current_user.github_access_token) @client ||= Gitlab::GithubImport::Client.new(session[:github_access_token])
end end
def verify_github_import_enabled def verify_github_import_enabled
...@@ -53,7 +51,7 @@ class Import::GithubController < Import::BaseController ...@@ -53,7 +51,7 @@ class Import::GithubController < Import::BaseController
end end
def github_auth def github_auth
if current_user.github_access_token.blank? if session[:github_access_token].blank?
go_to_github_for_permissions go_to_github_for_permissions
end end
end end
...@@ -65,4 +63,10 @@ class Import::GithubController < Import::BaseController ...@@ -65,4 +63,10 @@ class Import::GithubController < Import::BaseController
def github_unauthorized def github_unauthorized
go_to_github_for_permissions go_to_github_for_permissions
end end
private
def access_params
{ github_access_token: session[:github_access_token] }
end
end end
...@@ -5,9 +5,7 @@ class Import::GitlabController < Import::BaseController ...@@ -5,9 +5,7 @@ class Import::GitlabController < Import::BaseController
rescue_from OAuth2::Error, with: :gitlab_unauthorized rescue_from OAuth2::Error, with: :gitlab_unauthorized
def callback def callback
token = client.get_token(params[:code], callback_import_gitlab_url) session[:gitlab_access_token] = client.get_token(params[:code], callback_import_gitlab_url)
current_user.gitlab_access_token = token
current_user.save
redirect_to status_import_gitlab_url redirect_to status_import_gitlab_url
end end
...@@ -36,13 +34,13 @@ class Import::GitlabController < Import::BaseController ...@@ -36,13 +34,13 @@ class Import::GitlabController < Import::BaseController
namespace = get_or_create_namespace || (render and return) 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 end
private private
def client def client
@client ||= Gitlab::GitlabImport::Client.new(current_user.gitlab_access_token) @client ||= Gitlab::GitlabImport::Client.new(session[:gitlab_access_token])
end end
def verify_gitlab_import_enabled def verify_gitlab_import_enabled
...@@ -50,7 +48,7 @@ class Import::GitlabController < Import::BaseController ...@@ -50,7 +48,7 @@ class Import::GitlabController < Import::BaseController
end end
def gitlab_auth def gitlab_auth
if current_user.gitlab_access_token.blank? if session[:gitlab_access_token].blank?
go_to_gitlab_for_permissions go_to_gitlab_for_permissions
end end
end end
...@@ -62,4 +60,10 @@ class Import::GitlabController < Import::BaseController ...@@ -62,4 +60,10 @@ class Import::GitlabController < Import::BaseController
def gitlab_unauthorized def gitlab_unauthorized
go_to_gitlab_for_permissions go_to_gitlab_for_permissions
end end
private
def access_params
{ gitlab_access_token: session[:gitlab_access_token] }
end
end end
...@@ -53,6 +53,7 @@ class Projects::HooksController < Projects::ApplicationController ...@@ -53,6 +53,7 @@ class Projects::HooksController < Projects::ApplicationController
end end
def hook_params def hook_params
params.require(:hook).permit(:url, :push_events, :issues_events, :merge_requests_events, :tag_push_events, :note_events) params.require(:hook).permit(:url, :push_events, :issues_events,
:merge_requests_events, :tag_push_events, :note_events, :enable_ssl_verification)
end end
end end
...@@ -8,7 +8,7 @@ class Projects::ServicesController < Projects::ApplicationController ...@@ -8,7 +8,7 @@ class Projects::ServicesController < Projects::ApplicationController
:push_events, :issues_events, :merge_requests_events, :tag_push_events, :push_events, :issues_events, :merge_requests_events, :tag_push_events,
:note_events, :send_from_committer_email, :disable_diffs, :external_wiki_url, :note_events, :send_from_committer_email, :disable_diffs, :external_wiki_url,
:notify, :color, :notify, :color,
:server_host, :server_port, :default_irc_uri] :server_host, :server_port, :default_irc_uri, :enable_ssl_verification]
# Authorize # Authorize
before_action :authorize_admin_project! before_action :authorize_admin_project!
before_action :service, only: [:edit, :update, :test] before_action :service, only: [:edit, :update, :test]
......
...@@ -30,9 +30,14 @@ class Projects::SnippetsController < Projects::ApplicationController ...@@ -30,9 +30,14 @@ class Projects::SnippetsController < Projects::ApplicationController
def create def create
@snippet = CreateSnippetService.new(@project, current_user, @snippet = CreateSnippetService.new(@project, current_user,
snippet_params).execute snippet_params).execute
if @snippet.valid?
respond_with(@snippet, respond_with(@snippet,
location: namespace_project_snippet_path(@project.namespace, location: namespace_project_snippet_path(@project.namespace,
@project, @snippet)) @project, @snippet))
else
render :new
end
end end
def edit def edit
......
...@@ -23,7 +23,7 @@ class SearchController < ApplicationController ...@@ -23,7 +23,7 @@ class SearchController < ApplicationController
@search_results = @search_results =
if @project if @project
unless %w(blobs notes issues merge_requests wiki_blobs). unless %w(blobs notes issues merge_requests milestones wiki_blobs).
include?(@scope) include?(@scope)
@scope = 'blobs' @scope = 'blobs'
end end
...@@ -36,7 +36,7 @@ class SearchController < ApplicationController ...@@ -36,7 +36,7 @@ class SearchController < ApplicationController
Search::SnippetService.new(current_user, params).execute Search::SnippetService.new(current_user, params).execute
else else
unless %w(projects issues merge_requests).include?(@scope) unless %w(projects issues merge_requests milestones).include?(@scope)
@scope = 'projects' @scope = 'projects'
end end
Search::GlobalService.new(current_user, params).execute Search::GlobalService.new(current_user, params).execute
......
...@@ -51,10 +51,6 @@ class UsersController < ApplicationController ...@@ -51,10 +51,6 @@ class UsersController < ApplicationController
def set_user def set_user
@user = User.find_by_username!(params[:username]) @user = User.find_by_username!(params[:username])
unless current_user || @user.public_profile?
return authenticate_user!
end
end end
def authorized_projects_ids def authorized_projects_ids
......
...@@ -2,13 +2,21 @@ class TrendingProjectsFinder ...@@ -2,13 +2,21 @@ class TrendingProjectsFinder
def execute(current_user, start_date = nil) def execute(current_user, start_date = nil)
start_date ||= Date.today - 1.month start_date ||= Date.today - 1.month
projects = projects_for(current_user)
# Determine trending projects based on comments count # Determine trending projects based on comments count
# for period of time - ex. month # for period of time - ex. month
projects.joins(:notes).where('notes.created_at > ?', start_date). trending_project_ids = Note.
select("projects.*, count(notes.id) as ncount"). select("notes.project_id, count(notes.project_id) as pcount").
group("projects.id").reorder("ncount DESC") where('notes.created_at > ?', start_date).
group("project_id").
reorder("pcount DESC").
map(&:project_id)
sql_order_ids = trending_project_ids.reverse.
map { |project_id| "id = #{project_id}" }.join(", ")
# Get list of projects that user allowed to see
projects = projects_for(current_user)
projects.where(id: trending_project_ids).reorder(sql_order_ids)
end end
private private
......
...@@ -58,7 +58,7 @@ module GitlabMarkdownHelper ...@@ -58,7 +58,7 @@ module GitlabMarkdownHelper
@options = options @options = options
# see https://github.com/vmg/redcarpet#darling-i-packed-you-a-couple-renderers-for-lunch # see https://github.com/vmg/redcarpet#darling-i-packed-you-a-couple-renderers-for-lunch
rend = Redcarpet::Render::GitlabHTML.new(self, user_color_scheme_class, options) rend = Redcarpet::Render::GitlabHTML.new(self, options)
# see https://github.com/vmg/redcarpet#and-its-like-really-simple-to-use # see https://github.com/vmg/redcarpet#and-its-like-really-simple-to-use
@markdown = Redcarpet::Markdown.new(rend, MARKDOWN_OPTIONS) @markdown = Redcarpet::Markdown.new(rend, MARKDOWN_OPTIONS)
......
...@@ -20,7 +20,7 @@ module IconsHelper ...@@ -20,7 +20,7 @@ module IconsHelper
end end
def boolean_to_icon(value) def boolean_to_icon(value)
if value.to_s == "true" if value
icon('circle', class: 'cgreen') icon('circle', class: 'cgreen')
else else
icon('power-off', class: 'clgray') icon('power-off', class: 'clgray')
......
...@@ -23,4 +23,12 @@ module PageLayoutHelper ...@@ -23,4 +23,12 @@ module PageLayoutHelper
@sidebar @sidebar
end end
end end
def fluid_layout(enabled = false)
if @fluid_layout.nil?
@fluid_layout = enabled
else
@fluid_layout
end
end
end end
# Helper methods for per-User preferences # Helper methods for per-User preferences
module PreferencesHelper module PreferencesHelper
COLOR_SCHEMES = {
1 => 'white',
2 => 'dark',
3 => 'solarized-light',
4 => 'solarized-dark',
5 => 'monokai',
}
COLOR_SCHEMES.default = 'white'
# Helper method to access the COLOR_SCHEMES
#
# The keys are the `color_scheme_ids`
# The values are the `name` of the scheme.
#
# The preview images are `name-scheme-preview.png`
# The stylesheets should use the css class `.name`
def color_schemes
COLOR_SCHEMES.freeze
end
# Maps `dashboard` values to more user-friendly option text # Maps `dashboard` values to more user-friendly option text
DASHBOARD_CHOICES = { DASHBOARD_CHOICES = {
projects: 'Your Projects (default)', projects: 'Your Projects (default)',
...@@ -50,12 +30,11 @@ module PreferencesHelper ...@@ -50,12 +30,11 @@ module PreferencesHelper
end end
def user_application_theme def user_application_theme
theme = Gitlab::Themes.by_id(current_user.try(:theme_id)) Gitlab::Themes.for_user(current_user).css_class
theme.css_class
end end
def user_color_scheme_class def user_color_scheme
COLOR_SCHEMES[current_user.try(:color_scheme_id)] if defined?(current_user) Gitlab::ColorSchemes.for_user(current_user).css_class
end end
def prefer_readme? def prefer_readme?
......
...@@ -10,6 +10,7 @@ module SelectsHelper ...@@ -10,6 +10,7 @@ module SelectsHelper
any_user = opts[:any_user] || false any_user = opts[:any_user] || false
email_user = opts[:email_user] || false email_user = opts[:email_user] || false
first_user = opts[:first_user] && current_user ? current_user.username : false first_user = opts[:first_user] && current_user ? current_user.username : false
current_user = opts[:current_user] || false
project = opts[:project] || @project project = opts[:project] || @project
html = { html = {
...@@ -18,7 +19,8 @@ module SelectsHelper ...@@ -18,7 +19,8 @@ module SelectsHelper
'data-null-user' => null_user, 'data-null-user' => null_user,
'data-any-user' => any_user, 'data-any-user' => any_user,
'data-email-user' => email_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 unless opts[:scope] == :all
......
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
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,6 +8,8 @@ module Emails ...@@ -8,6 +8,8 @@ module Emails
from: sender(@issue.author_id), from: sender(@issue.author_id),
to: recipient(recipient_id), to: recipient(recipient_id),
subject: subject("#{@issue.title} (##{@issue.iid})")) subject: subject("#{@issue.title} (##{@issue.iid})"))
SentNotification.record(@issue, recipient_id, reply_key)
end end
def reassigned_issue_email(recipient_id, issue_id, previous_assignee_id, updated_by_user_id) def reassigned_issue_email(recipient_id, issue_id, previous_assignee_id, updated_by_user_id)
...@@ -19,6 +21,8 @@ module Emails ...@@ -19,6 +21,8 @@ module Emails
from: sender(updated_by_user_id), from: sender(updated_by_user_id),
to: recipient(recipient_id), to: recipient(recipient_id),
subject: subject("#{@issue.title} (##{@issue.iid})")) subject: subject("#{@issue.title} (##{@issue.iid})"))
SentNotification.record(@issue, recipient_id, reply_key)
end end
def closed_issue_email(recipient_id, issue_id, updated_by_user_id) def closed_issue_email(recipient_id, issue_id, updated_by_user_id)
...@@ -30,6 +34,8 @@ module Emails ...@@ -30,6 +34,8 @@ module Emails
from: sender(updated_by_user_id), from: sender(updated_by_user_id),
to: recipient(recipient_id), to: recipient(recipient_id),
subject: subject("#{@issue.title} (##{@issue.iid})")) subject: subject("#{@issue.title} (##{@issue.iid})"))
SentNotification.record(@issue, recipient_id, reply_key)
end end
def issue_status_changed_email(recipient_id, issue_id, status, updated_by_user_id) def issue_status_changed_email(recipient_id, issue_id, status, updated_by_user_id)
...@@ -42,6 +48,8 @@ module Emails ...@@ -42,6 +48,8 @@ module Emails
from: sender(updated_by_user_id), from: sender(updated_by_user_id),
to: recipient(recipient_id), to: recipient(recipient_id),
subject: subject("#{@issue.title} (##{@issue.iid})")) subject: subject("#{@issue.title} (##{@issue.iid})"))
SentNotification.record(@issue, recipient_id, reply_key)
end end
end end
end end
...@@ -10,6 +10,8 @@ module Emails ...@@ -10,6 +10,8 @@ module Emails
from: sender(@merge_request.author_id), from: sender(@merge_request.author_id),
to: recipient(recipient_id), to: recipient(recipient_id),
subject: subject("#{@merge_request.title} (##{@merge_request.iid})")) subject: subject("#{@merge_request.title} (##{@merge_request.iid})"))
SentNotification.record(@merge_request, recipient_id, reply_key)
end end
def reassigned_merge_request_email(recipient_id, merge_request_id, previous_assignee_id, updated_by_user_id) def reassigned_merge_request_email(recipient_id, merge_request_id, previous_assignee_id, updated_by_user_id)
...@@ -23,6 +25,8 @@ module Emails ...@@ -23,6 +25,8 @@ module Emails
from: sender(updated_by_user_id), from: sender(updated_by_user_id),
to: recipient(recipient_id), to: recipient(recipient_id),
subject: subject("#{@merge_request.title} (##{@merge_request.iid})")) subject: subject("#{@merge_request.title} (##{@merge_request.iid})"))
SentNotification.record(@merge_request, recipient_id, reply_key)
end end
def closed_merge_request_email(recipient_id, merge_request_id, updated_by_user_id) def closed_merge_request_email(recipient_id, merge_request_id, updated_by_user_id)
...@@ -36,6 +40,8 @@ module Emails ...@@ -36,6 +40,8 @@ module Emails
from: sender(updated_by_user_id), from: sender(updated_by_user_id),
to: recipient(recipient_id), to: recipient(recipient_id),
subject: subject("#{@merge_request.title} (##{@merge_request.iid})")) subject: subject("#{@merge_request.title} (##{@merge_request.iid})"))
SentNotification.record(@merge_request, recipient_id, reply_key)
end end
def merged_merge_request_email(recipient_id, merge_request_id, updated_by_user_id) def merged_merge_request_email(recipient_id, merge_request_id, updated_by_user_id)
...@@ -48,6 +54,8 @@ module Emails ...@@ -48,6 +54,8 @@ module Emails
from: sender(updated_by_user_id), from: sender(updated_by_user_id),
to: recipient(recipient_id), to: recipient(recipient_id),
subject: subject("#{@merge_request.title} (##{@merge_request.iid})")) subject: subject("#{@merge_request.title} (##{@merge_request.iid})"))
SentNotification.record(@merge_request, recipient_id, reply_key)
end end
def merge_request_status_email(recipient_id, merge_request_id, status, updated_by_user_id) def merge_request_status_email(recipient_id, merge_request_id, status, updated_by_user_id)
...@@ -58,52 +66,12 @@ module Emails ...@@ -58,52 +66,12 @@ module Emails
@target_url = namespace_project_merge_request_url(@project.namespace, @target_url = namespace_project_merge_request_url(@project.namespace,
@project, @project,
@merge_request) @merge_request)
set_reference("merge_request_#{merge_request_id}")
mail_answer_thread(@merge_request, mail_answer_thread(@merge_request,
from: sender(updated_by_user_id), from: sender(updated_by_user_id),
to: recipient(recipient_id), to: recipient(recipient_id),
subject: subject("#{@merge_request.title} (##{@merge_request.iid}) #{@mr_status}")) subject: subject("#{@merge_request.title} (##{@merge_request.iid})"))
end
end
# Over rides default behaviour to show source/target SentNotification.record(@merge_request, recipient_id, reply_key)
# 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 end
subject << " | " + extra.join(' | ') if extra.present?
subject
end end
end end
...@@ -11,6 +11,8 @@ module Emails ...@@ -11,6 +11,8 @@ module Emails
from: sender(@note.author_id), from: sender(@note.author_id),
to: recipient(recipient_id), to: recipient(recipient_id),
subject: subject("#{@commit.title} (#{@commit.short_id})")) subject: subject("#{@commit.title} (#{@commit.short_id})"))
SentNotification.record(@commit, recipient_id, reply_key)
end end
def note_issue_email(recipient_id, note_id) def note_issue_email(recipient_id, note_id)
...@@ -24,6 +26,8 @@ module Emails ...@@ -24,6 +26,8 @@ module Emails
from: sender(@note.author_id), from: sender(@note.author_id),
to: recipient(recipient_id), to: recipient(recipient_id),
subject: subject("#{@issue.title} (##{@issue.iid})")) subject: subject("#{@issue.title} (##{@issue.iid})"))
SentNotification.record(@issue, recipient_id, reply_key)
end end
def note_merge_request_email(recipient_id, note_id) def note_merge_request_email(recipient_id, note_id)
...@@ -38,6 +42,8 @@ module Emails ...@@ -38,6 +42,8 @@ module Emails
from: sender(@note.author_id), from: sender(@note.author_id),
to: recipient(recipient_id), to: recipient(recipient_id),
subject: subject("#{@merge_request.title} (##{@merge_request.iid})")) subject: subject("#{@merge_request.title} (##{@merge_request.iid})"))
SentNotification.record(@merge_request, recipient_id, reply_key)
end end
end end
end end
class Notify < ActionMailer::Base class Notify < BaseMailer
include ActionDispatch::Routing::PolymorphicRoutes include ActionDispatch::Routing::PolymorphicRoutes
include Emails::Issues include Emails::Issues
...@@ -8,22 +8,9 @@ class Notify < ActionMailer::Base ...@@ -8,22 +8,9 @@ class Notify < ActionMailer::Base
include Emails::Profile include Emails::Profile
include Emails::Groups include Emails::Groups
add_template_helper ApplicationHelper
add_template_helper GitlabMarkdownHelper
add_template_helper MergeRequestsHelper add_template_helper MergeRequestsHelper
add_template_helper EmailsHelper 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) def test_email(recipient_email, subject, body)
mail(to: recipient_email, mail(to: recipient_email,
subject: subject, subject: subject,
...@@ -48,13 +35,6 @@ class Notify < ActionMailer::Base ...@@ -48,13 +35,6 @@ class Notify < ActionMailer::Base
private 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) def can_send_from_user_email?(sender)
sender_domain = sender.email.split("@").last sender_domain = sender.email.split("@").last
self.class.allowed_email_domains.include?(sender_domain) self.class.allowed_email_domains.include?(sender_domain)
...@@ -85,14 +65,6 @@ class Notify < ActionMailer::Base ...@@ -85,14 +65,6 @@ class Notify < ActionMailer::Base
@current_user.notification_email @current_user.notification_email
end 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 # Formats arguments into a String suitable for use as an email subject
# #
# extra - Extra Strings to be inserted into the subject # extra - Extra Strings to be inserted into the subject
...@@ -126,14 +98,37 @@ class Notify < ActionMailer::Base ...@@ -126,14 +98,37 @@ class Notify < ActionMailer::Base
"<#{model_name}_#{model.id}@#{Gitlab.config.gitlab.host}>" "<#{model_name}_#{model.id}@#{Gitlab.config.gitlab.host}>"
end 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, # Send an email that starts a new conversation thread,
# with headers suitable for grouping by thread in email clients. # with headers suitable for grouping by thread in email clients.
# #
# See: mail_answer_thread # See: mail_answer_thread
def mail_new_thread(model, headers = {}, &block) def mail_new_thread(model, headers = {})
headers['Message-ID'] = message_id(model) headers['Message-ID'] = message_id(model)
headers['X-GitLab-Project'] = "#{@project.name} | " if @project
mail(headers, &block) mail_thread(model, headers)
end end
# Send an email that responds to an existing conversation thread, # Send an email that responds to an existing conversation thread,
...@@ -144,19 +139,17 @@ class Notify < ActionMailer::Base ...@@ -144,19 +139,17 @@ class Notify < ActionMailer::Base
# * have a subject that begin by 'Re: ' # * have a subject that begin by 'Re: '
# * have a 'In-Reply-To' or 'References' header that references the original 'Message-ID' # * 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['In-Reply-To'] = message_id(model)
headers['References'] = message_id(model) headers['References'] = message_id(model)
headers['X-GitLab-Project'] = "#{@project.name} | " if @project
if headers[:subject] headers[:subject].prepend('Re: ') if headers[:subject]
headers[:subject].prepend('Re: ')
end
mail(headers, &block) mail_thread(model, headers)
end end
def can? def reply_key
Ability.abilities.allowed?(user, action, subject) @reply_key ||= Gitlab::ReplyByEmail.reply_key
end end
end end
...@@ -17,6 +17,7 @@ require 'carrierwave/orm/activerecord' ...@@ -17,6 +17,7 @@ require 'carrierwave/orm/activerecord'
require 'file_size_validator' require 'file_size_validator'
class Group < Namespace class Group < Namespace
include Gitlab::ConfigHelper
include Referable include Referable
has_many :group_members, dependent: :destroy, as: :source, class_name: 'GroupMember' has_many :group_members, dependent: :destroy, as: :source, class_name: 'GroupMember'
......
...@@ -25,6 +25,7 @@ class WebHook < ActiveRecord::Base ...@@ -25,6 +25,7 @@ class WebHook < ActiveRecord::Base
default_value_for :note_events, false default_value_for :note_events, false
default_value_for :merge_requests_events, false default_value_for :merge_requests_events, false
default_value_for :tag_push_events, false default_value_for :tag_push_events, false
default_value_for :enable_ssl_verification, false
# HTTParty timeout # HTTParty timeout
default_timeout Gitlab.config.gitlab.webhook_timeout default_timeout Gitlab.config.gitlab.webhook_timeout
...@@ -41,7 +42,7 @@ class WebHook < ActiveRecord::Base ...@@ -41,7 +42,7 @@ class WebHook < ActiveRecord::Base
"Content-Type" => "application/json", "Content-Type" => "application/json",
"X-Gitlab-Event" => hook_name.singularize.titleize "X-Gitlab-Event" => hook_name.singularize.titleize
}, },
verify: false) verify: enable_ssl_verification)
else else
post_url = url.gsub("#{parsed_url.userinfo}@", "") post_url = url.gsub("#{parsed_url.userinfo}@", "")
auth = { auth = {
...@@ -54,7 +55,7 @@ class WebHook < ActiveRecord::Base ...@@ -54,7 +55,7 @@ class WebHook < ActiveRecord::Base
"Content-Type" => "application/json", "Content-Type" => "application/json",
"X-Gitlab-Event" => hook_name.singularize.titleize "X-Gitlab-Event" => hook_name.singularize.titleize
}, },
verify: false, verify: enable_ssl_verification,
basic_auth: auth) basic_auth: auth)
end end
rescue SocketError, Errno::ECONNRESET, Errno::ECONNREFUSED, Net::OpenTimeout => e rescue SocketError, Errno::ECONNRESET, Errno::ECONNREFUSED, Net::OpenTimeout => e
......
...@@ -47,6 +47,13 @@ class Milestone < ActiveRecord::Base ...@@ -47,6 +47,13 @@ class Milestone < ActiveRecord::Base
state :active state :active
end end
class << self
def search(query)
query = "%#{query}%"
where("title like ? or description like ?", query, query)
end
end
def expired? def expired?
if due_date if due_date
due_date.past? due_date.past?
......
...@@ -23,7 +23,7 @@ require "addressable/uri" ...@@ -23,7 +23,7 @@ require "addressable/uri"
class BuildkiteService < CiService class BuildkiteService < CiService
ENDPOINT = "https://buildkite.com" ENDPOINT = "https://buildkite.com"
prop_accessor :project_url, :token prop_accessor :project_url, :token, :enable_ssl_verification
validates :project_url, presence: true, if: :activated? validates :project_url, presence: true, if: :activated?
validates :token, presence: true, if: :activated? validates :token, presence: true, if: :activated?
...@@ -37,6 +37,7 @@ class BuildkiteService < CiService ...@@ -37,6 +37,7 @@ class BuildkiteService < CiService
def compose_service_hook def compose_service_hook
hook = service_hook || build_service_hook hook = service_hook || build_service_hook
hook.url = webhook_url hook.url = webhook_url
hook.enable_ssl_verification = enable_ssl_verification
hook.save hook.save
end end
...@@ -96,7 +97,11 @@ class BuildkiteService < CiService ...@@ -96,7 +97,11 @@ class BuildkiteService < CiService
{ type: 'text', { type: 'text',
name: 'project_url', name: 'project_url',
placeholder: "#{ENDPOINT}/example/project" } placeholder: "#{ENDPOINT}/example/project" },
{ type: 'checkbox',
name: 'enable_ssl_verification',
title: "Enable SSL verification" }
] ]
end end
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
class GitlabCiService < CiService class GitlabCiService < CiService
API_PREFIX = "api/v1" API_PREFIX = "api/v1"
prop_accessor :project_url, :token prop_accessor :project_url, :token, :enable_ssl_verification
validates :project_url, validates :project_url,
presence: true, presence: true,
format: { with: /\A#{URI.regexp(%w(http https))}\z/, message: "should be a valid url" }, if: :activated? format: { with: /\A#{URI.regexp(%w(http https))}\z/, message: "should be a valid url" }, if: :activated?
...@@ -34,6 +34,7 @@ class GitlabCiService < CiService ...@@ -34,6 +34,7 @@ class GitlabCiService < CiService
def compose_service_hook def compose_service_hook
hook = service_hook || build_service_hook hook = service_hook || build_service_hook
hook.url = [project_url, "/build", "?token=#{token}"].join("") hook.url = [project_url, "/build", "?token=#{token}"].join("")
hook.enable_ssl_verification = enable_ssl_verification
hook.save hook.save
end end
...@@ -136,7 +137,8 @@ class GitlabCiService < CiService ...@@ -136,7 +137,8 @@ class GitlabCiService < CiService
def fields def fields
[ [
{ type: 'text', name: 'token', placeholder: 'GitLab CI project specific token' }, { type: 'text', name: 'token', placeholder: 'GitLab CI project specific token' },
{ type: 'text', name: 'project_url', placeholder: 'http://ci.gitlabhq.com/projects/3' } { type: 'text', name: 'project_url', placeholder: 'http://ci.gitlabhq.com/projects/3' },
{ type: 'checkbox', name: 'enable_ssl_verification', title: "Enable SSL verification" }
] ]
end end
......
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
...@@ -637,10 +637,6 @@ class User < ActiveRecord::Base ...@@ -637,10 +637,6 @@ class User < ActiveRecord::Base
email.start_with?('temp-email-for-oauth') email.start_with?('temp-email-for-oauth')
end end
def public_profile?
authorized_projects.public_only.any?
end
def avatar_url(size = nil) def avatar_url(size = nil)
if avatar.present? if avatar.present?
[gitlab_config.url, avatar.url].join [gitlab_config.url, avatar.url].join
......
...@@ -78,24 +78,29 @@ class GitPushService ...@@ -78,24 +78,29 @@ class GitPushService
# For push with 1k commits it prevents 900+ requests in database # For push with 1k commits it prevents 900+ requests in database
author = nil 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 if issues_to_close.present? && is_default_branch
author ||= commit_user(commit) author ||= commit_user(commit)
actually_closed_issues = issues_to_close
issues_to_close.each do |issue| issues_to_close.each do |issue|
Issues::CloseService.new(project, author, {}).execute(issue, commit) Issues::CloseService.new(project, author, {}).execute(issue, commit)
end end
end end
if project.default_issues_tracker? if project.default_issues_tracker?
create_cross_reference_notes(commit, issues_to_close) create_cross_reference_notes(commit, actually_closed_issues)
end end
end end
end end
def create_cross_reference_notes(commit, issues_to_close) 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 # Create cross-reference notes for any other references than those given in issues_to_close.
# issue-closing phrase, or have already been mentioned from this commit (probably from this commit # Omit any issues that were referenced in an issue-closing phrase, or have already been
# being pushed to a different branch). # mentioned from this commit (probably from this commit being pushed to a different branch).
refs = commit.references(project, user) - issues_to_close refs = commit.references(project, user) - issues_to_close
refs.reject! { |r| commit.has_mentioned?(r) } refs.reject! { |r| commit.has_mentioned?(r) }
......
module MergeRequests module MergeRequests
class CreateService < MergeRequests::BaseService class CreateService < MergeRequests::BaseService
def execute 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 filter_params
label_params = params[:label_ids] label_params = params[:label_ids]
merge_request = MergeRequest.new(params.except(:label_ids)) merge_request = MergeRequest.new(params.except(:label_ids))
merge_request.source_project = project merge_request.source_project = source_project
merge_request.target_project ||= project merge_request.target_project ||= source_project
merge_request.author = current_user merge_request.author = current_user
if merge_request.save if merge_request.save
......
...@@ -13,9 +13,9 @@ module Projects ...@@ -13,9 +13,9 @@ module Projects
filename = uploader.image? ? uploader.file.basename : uploader.file.filename filename = uploader.image? ? uploader.file.basename : uploader.file.filename
{ {
'alt' => filename, alt: filename,
'url' => uploader.secure_url, url: uploader.secure_url,
'is_image' => uploader.image? is_image: uploader.image?
} }
end end
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
%tr %tr
%td %td
- if reporter - if reporter
= link_to reporter.name, [:admin, reporter] = link_to reporter.name, reporter
- else - else
(removed) (removed)
%td %td
...@@ -12,12 +12,15 @@ ...@@ -12,12 +12,15 @@
= abuse_report.message = abuse_report.message
%td %td
- if user - if user
= link_to user.name, [:admin, user] = link_to user.name, user
- else - else
(removed) (removed)
%td %td
- if user - 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 & report', admin_abuse_report_path(abuse_report, remove_user: true),
= 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" 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 %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 @@ ...@@ -9,7 +9,7 @@
%th Reported at %th Reported at
%th Message %th Message
%th User %th User
%th %th Primary action
%th %th
= render @abuse_reports = render @abuse_reports
= paginate @abuse_reports = paginate @abuse_reports
......
...@@ -55,6 +55,10 @@ ...@@ -55,6 +55,10 @@
OmniAuth OmniAuth
%span.light.pull-right %span.light.pull-right
= boolean_to_icon Gitlab.config.omniauth.enabled = boolean_to_icon Gitlab.config.omniauth.enabled
%p
Reply by email
%span.light.pull-right
= boolean_to_icon Gitlab::ReplyByEmail.enabled?
.col-md-4 .col-md-4
%h4 %h4
Components Components
......
...@@ -18,6 +18,13 @@ ...@@ -18,6 +18,13 @@
= f.label :url, "URL:", class: 'control-label' = f.label :url, "URL:", class: 'control-label'
.col-sm-10 .col-sm-10
= f.text_field :url, class: "form-control" = f.text_field :url, class: "form-control"
.form-group
= f.label :enable_ssl_verification, "SSL verification", class: 'control-label checkbox'
.col-sm-10
.checkbox
= f.label :enable_ssl_verification do
= f.check_box :enable_ssl_verification
%strong Enable SSL verification
.form-actions .form-actions
= f.submit "Add System Hook", class: "btn btn-create" = f.submit "Add System Hook", class: "btn btn-create"
%hr %hr
...@@ -32,6 +39,7 @@ ...@@ -32,6 +39,7 @@
.list-item-name .list-item-name
= link_to admin_hook_path(hook) do = link_to admin_hook_path(hook) do
%strong= hook.url %strong= hook.url
%p SSL Verification: #{hook.enable_ssl_verification ? "enabled" : "disabled"}
.pull-right .pull-right
= link_to 'Test Hook', admin_hook_test_path(hook), class: "btn btn-sm" = link_to 'Test Hook', admin_hook_test_path(hook), class: "btn btn-sm"
......
.panel.panel-default .projects-list-holder
.panel-heading.clearfix .projects-search-form
.input-group .input-group
= search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'projects-list-filter form-control' = search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'projects-list-filter form-control'
- if current_user.can_create_project? - if current_user.can_create_project?
...@@ -7,4 +7,4 @@ ...@@ -7,4 +7,4 @@
= link_to new_project_path, class: 'btn btn-success' do = link_to new_project_path, class: 'btn btn-success' do
New project New project
= render 'shared/projects_list', projects: @projects, projects_limit: 20 = render 'shared/projects/list', projects: @projects
= 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'
...@@ -8,32 +8,9 @@ ...@@ -8,32 +8,9 @@
= link_to new_group_path, class: "btn btn-new btn-sm" do = link_to new_group_path, class: "btn btn-new btn-sm" do
%i.fa.fa-plus %i.fa.fa-plus
New Group New Group
.panel.panel-default %ul.bordered-list
.panel-heading
%strong Groups
(#{@group_members.count})
%ul.well-list
- @group_members.each do |group_member| - @group_members.each do |group_member|
- group = group_member.group - group = group_member.group
%li = render 'shared/groups/group', group: group, group_member: group_member
.pull-right.hidden-xs
- if can?(current_user, :admin_group, group)
= link_to edit_group_path(group), class: "btn-sm btn btn-grouped" do
%i.fa.fa-cogs
Settings
= link_to leave_group_group_members_path(group), data: { confirm: leave_group_message(group.name) }, method: :delete, class: "btn-sm btn btn-grouped", title: 'Leave this group' do
%i.fa.fa-sign-out
Leave
= image_tag group_icon(group), class: "avatar s40 avatar-tile hidden-xs"
= link_to group, class: 'group-name' do
%strong= group.name
as
%strong #{group_member.human_access}
%div.light
#{pluralize(group.projects.count, "project")}, #{pluralize(group.users.count, "user")}
= paginate @group_members = paginate @group_members
...@@ -5,10 +5,10 @@ ...@@ -5,10 +5,10 @@
= render 'shared/show_aside' = render 'shared/show_aside'
.dashboard.row .dashboard.row
%section.activities.col-md-8 %section.activities.col-md-7
= render 'dashboard/activities' = render 'dashboard/activities'
%aside.col-md-4 %aside.col-md-5
.panel.panel-default .panel.panel-default.projects-list-holder
.panel-heading.clearfix .panel-heading.clearfix
.input-group .input-group
= search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'projects-list-filter form-control' = search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'projects-list-filter form-control'
...@@ -17,8 +17,7 @@ ...@@ -17,8 +17,7 @@
= link_to new_project_path, class: 'btn btn-success' do = link_to new_project_path, class: 'btn btn-success' do
New project New project
= render 'shared/projects_list', projects: @projects, = render 'shared/projects/list', projects: @projects, projects_limit: 20
projects_limit: 20, stars: true, avatar: false
- else - else
%h3 You don't have starred projects yet %h3 You don't have starred projects yet
......
...@@ -4,14 +4,10 @@ ...@@ -4,14 +4,10 @@
= render 'dashboard/projects_head' = render 'dashboard/projects_head'
- if @projects.any? - if @last_push
= render 'shared/show_aside' = render "events/event_last_push", event: @last_push
.dashboard.row
%section.activities.col-md-8
= render 'activities'
%aside.col-md-4
= render 'sidebar'
- if @projects.any?
= render 'projects'
- else - else
= render "zero_authorized_projects" = render "zero_authorized_projects"
%p
Unfortunately, your email message to GitLab could not be processed.
= markdown @reason
Unfortunately, your email message to GitLab could not be processed.
= @reason
...@@ -9,6 +9,6 @@ ...@@ -9,6 +9,6 @@
#{time_ago_with_tooltip(event.created_at)} #{time_ago_with_tooltip(event.created_at)}
.pull-right .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 Create Merge Request
%hr %hr
...@@ -32,17 +32,7 @@ ...@@ -32,17 +32,7 @@
%ul.bordered-list %ul.bordered-list
- @groups.each do |group| - @groups.each do |group|
%li = render 'shared/groups/group', group: group
.clearfix
%h4
= link_to group_path(id: group.path) do
= group.name
.clearfix
%p
= truncate group.description, length: 150
.clearfix
%p.light
#{pluralize(group.members.size, 'member')}, #{pluralize(group.projects.count, 'project')}
- unless @groups.present? - unless @groups.present?
.nothing-here-block No public groups .nothing-here-block No public groups
......
%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
- if projects.any?
.public-projects
= render 'shared/projects/list', projects: projects
- else
.nothing-here-block
No such projects
...@@ -4,10 +4,5 @@ ...@@ -4,10 +4,5 @@
.clearfix .clearfix
= render 'filter' = render 'filter'
%br %br
.public-projects = render 'projects', projects: @projects
%ul.bordered-list.top-list = paginate @projects, theme: "gitlab"
= render @projects
- unless @projects.present?
.nothing-here-block No public projects
= paginate @projects, theme: "gitlab"
...@@ -7,8 +7,5 @@ ...@@ -7,8 +7,5 @@
See most starred projects See most starred projects
.pull-right .pull-right
= render 'explore/projects/dropdown' = render 'explore/projects/dropdown'
.public-projects = render 'projects', projects: @starred_projects
%ul.bordered-list
= render @starred_projects
= paginate @starred_projects, theme: 'gitlab' = paginate @starred_projects, theme: 'gitlab'
...@@ -13,6 +13,4 @@ ...@@ -13,6 +13,4 @@
See most discussed projects for last month See most discussed projects for last month
.pull-right .pull-right
= render 'explore/projects/dropdown' = render 'explore/projects/dropdown'
.public-projects = render 'projects', projects: @trending_projects
%ul.bordered-list
= render @trending_projects
.panel.panel-default .panel.panel-default.projects-list-holder
.panel-heading.clearfix .panel-heading.clearfix
.input-group .input-group
= search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'projects-list-filter form-control' = search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'projects-list-filter form-control'
...@@ -7,4 +7,4 @@ ...@@ -7,4 +7,4 @@
= link_to new_project_path(namespace_id: @group.id), class: 'btn btn-success' do = link_to new_project_path(namespace_id: @group.id), class: 'btn btn-success' do
New project New project
= render 'shared/projects_list', projects: @projects, projects_limit: 20 = render 'shared/projects/list', projects: @projects, projects_limit: 20
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
= render 'shared/show_aside' = render 'shared/show_aside'
.row .row
%section.activities.col-md-8 %section.activities.col-md-7
.hidden-xs .hidden-xs
- if current_user - if current_user
= render "events/event_last_push", event: @last_push = render "events/event_last_push", event: @last_push
...@@ -33,5 +33,5 @@ ...@@ -33,5 +33,5 @@
.content_list .content_list
= spinner = spinner
%aside.side.col-md-4 %aside.side.col-md-5
= render "projects", projects: @projects = render "projects", projects: @projects
.page-with-sidebar{ class: nav_sidebar_class } .page-with-sidebar{ class: nav_sidebar_class }
= render "layouts/broadcast" = render "layouts/broadcast"
.sidebar-wrapper.nicescroll .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 - if defined?(sidebar) && sidebar
= render "layouts/nav/#{sidebar}" = render "layouts/nav/#{sidebar}"
- elsif current_user - elsif current_user
...@@ -13,7 +18,7 @@ ...@@ -13,7 +18,7 @@
.username .username
= current_user.username = current_user.username
.content-wrapper .content-wrapper
.container-fluid %div{ class: fluid_layout ? "container-fluid" : "container-fluid container-limited" }
.content .content
= render "layouts/flash" = render "layouts/flash"
.clearfix .clearfix
......
%header.navbar.navbar-fixed-top.navbar-gitlab{ class: nav_header_class } %header.navbar.navbar-fixed-top.navbar-gitlab{ class: nav_header_class }
.container %div{ class: fluid_layout ? "container-fluid" : "container-fluid container-limited" }
.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
.header-content .header-content
%button.navbar-toggle{type: 'button'} %button.navbar-toggle{type: 'button'}
%span.sr-only Toggle navigation %span.sr-only Toggle navigation
...@@ -17,15 +12,6 @@ ...@@ -17,15 +12,6 @@
%li.visible-sm.visible-xs %li.visible-sm.visible-xs
= link_to search_path, title: 'Search', data: {toggle: 'tooltip', placement: 'bottom'} do = link_to search_path, title: 'Search', data: {toggle: 'tooltip', placement: 'bottom'} do
= icon('search') = 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? - if current_user.is_admin?
%li %li
= link_to admin_root_path, title: 'Admin area', data: {toggle: 'tooltip', placement: 'bottom'} do = link_to admin_root_path, title: 'Admin area', data: {toggle: 'tooltip', placement: 'bottom'} do
...@@ -34,9 +20,6 @@ ...@@ -34,9 +20,6 @@
%li.hidden-xs %li.hidden-xs
= link_to new_project_path, title: 'New project', data: {toggle: 'tooltip', placement: 'bottom'} do = link_to new_project_path, title: 'New project', data: {toggle: 'tooltip', placement: 'bottom'} do
= icon('plus fw') = icon('plus fw')
-#%li
= link_to profile_path, title: 'Profile settings', data: {toggle: 'tooltip', placement: 'bottom'} do
= icon('cog fw')
%li %li
= link_to destroy_user_session_path, class: 'logout', method: :delete, title: 'Sign out', data: {toggle: 'tooltip', placement: 'bottom'} do = link_to destroy_user_session_path, class: 'logout', method: :delete, title: 'Sign out', data: {toggle: 'tooltip', placement: 'bottom'} do
= icon('sign-out') = icon('sign-out')
......
%header.navbar.navbar-fixed-top.navbar-gitlab{ class: nav_header_class } %header.navbar.navbar-fixed-top.navbar-gitlab{ class: nav_header_class }
.container %div{ class: fluid_layout ? "container-fluid" : "container-fluid container-limited" }
.header-logo
= link_to explore_root_path, class: "home" do
= brand_header_logo
.gitlab-text-container
%h3 GitLab
.header-content .header-content
- unless current_controller?('sessions') - unless current_controller?('sessions')
.pull-right .pull-right
......
%ul.nav.nav-sidebar %ul.nav.nav-sidebar
= nav_link(path: ['dashboard#show', 'root#show', 'projects#trending', 'projects#starred', 'projects#index'], html_options: {class: 'home'}) 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 = link_to (current_user ? root_path : explore_root_path), title: 'Home', class: 'shortcuts-activity', data: {placement: 'right'} do
= icon('dashboard fw') = icon('home fw')
%span %span
Projects Projects
= nav_link(path: 'dashboard#activity') do
= link_to activity_dashboard_path, title: 'Activity', data: {placement: 'right'} do
= icon('dashboard fw')
%span
Activity
= nav_link(controller: :groups) do = nav_link(controller: :groups) do
= link_to (current_user ? dashboard_groups_path : explore_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') = icon('group fw')
...@@ -29,7 +34,7 @@ ...@@ -29,7 +34,7 @@
%span.count= current_user.assigned_merge_requests.opened.count %span.count= current_user.assigned_merge_requests.opened.count
= nav_link(controller: :snippets) do = nav_link(controller: :snippets) do
= link_to (current_user ? user_snippets_path(current_user) : snippets_path), title: 'Your snippets', data: {placement: 'right'} do = link_to (current_user ? user_snippets_path(current_user) : snippets_path), title: 'Your snippets', data: {placement: 'right'} do
= icon('dashboard fw') = icon('clipboard fw')
%span %span
Snippets Snippets
- if current_user - if current_user
......
...@@ -100,7 +100,7 @@ ...@@ -100,7 +100,7 @@
- if project_nav_tab? :snippets - if project_nav_tab? :snippets
= nav_link(controller: :snippets) do = nav_link(controller: :snippets) do
= link_to namespace_project_snippets_path(@project.namespace, @project), title: 'Snippets', class: 'shortcuts-snippets', data: {placement: 'right'} do = link_to namespace_project_snippets_path(@project.namespace, @project), title: 'Snippets', class: 'shortcuts-snippets', data: {placement: 'right'} do
= icon('file-text-o fw') = icon('clipboard fw')
%span %span
Snippets Snippets
......
...@@ -36,6 +36,10 @@ ...@@ -36,6 +36,10 @@
&mdash; &mdash;
%br %br
- if @target_url - if @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} #{link_to "View it on GitLab", @target_url}
= email_action @target_url = email_action @target_url
- if @project && !@disable_footer - if @project && !@disable_footer
......
...@@ -48,7 +48,7 @@ ...@@ -48,7 +48,7 @@
= f.radio_button :notification_level, Notification::N_WATCH = f.radio_button :notification_level, Notification::N_WATCH
.level-title .level-title
Watch Watch
%p You will receive all notifications from projects in which you participate %p You will receive notifications for any activity
.form-actions .form-actions
= f.submit 'Save changes', class: "btn btn-create" = f.submit 'Save changes', class: "btn btn-create"
......
...@@ -22,11 +22,11 @@ ...@@ -22,11 +22,11 @@
.panel-heading .panel-heading
Syntax highlighting theme Syntax highlighting theme
.panel-body .panel-body
- color_schemes.each do |color_scheme_id, color_scheme| - Gitlab::ColorSchemes.each do |scheme|
= label_tag do = label_tag do
.preview= image_tag "#{color_scheme}-scheme-preview.png" .preview= image_tag "#{scheme.css_class}-scheme-preview.png"
= f.radio_button :color_scheme_id, color_scheme_id = f.radio_button :color_scheme_id, scheme.id
= color_scheme.tr('-_', ' ').titleize = scheme.name
.panel.panel-default .panel.panel-default
.panel-heading .panel-heading
......
...@@ -100,11 +100,6 @@ ...@@ -100,11 +100,6 @@
%hr %hr
= link_to 'Remove avatar', profile_avatar_path, data: { confirm: "Avatar will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-sm remove-avatar" = link_to 'Remove avatar', profile_avatar_path, data: { confirm: "Avatar will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-sm remove-avatar"
- if @user.public_profile?
.alert.alert-info
%h4 Public profile
%p Your profile is publicly visible because you joined public project(s)
.row .row
.col-md-7 .col-md-7
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
.project-home-panel.clearfix{:class => ("empty-project" if empty_repo)} .project-home-panel.clearfix{:class => ("empty-project" if empty_repo)}
.project-identicon-holder .project-identicon-holder
= project_icon(@project, alt: '', class: 'project-avatar avatar s90') = project_icon(@project, alt: '', class: 'project-avatar avatar s90')
.project-home-desc.lead .project-home-desc
%h1= @project.name %h1= @project.name
- if @project.description.present? - if @project.description.present?
= markdown(@project.description, pipeline: :description) = markdown(@project.description, pipeline: :description)
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
.light .light
= commit_author_link(commit, avatar: false) = commit_author_link(commit, avatar: false)
authored authored
#{time_ago_with_tooltip(commit.committed_date)} #{time_ago_with_tooltip(commit.committed_date, skip_js: true)}
%td.lines.blame-numbers %td.lines.blame-numbers
%pre %pre
- line_count = blame_group[:lines].count - line_count = blame_group[:lines].count
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
%span.dropdown %span.dropdown
%a.dropdown-toggle.btn.btn-new{href: '#', "data-toggle" => "dropdown"} %a.dropdown-toggle.btn.btn-new{href: '#', "data-toggle" => "dropdown"}
= icon('plus') = icon('plus')
%ul.dropdown-menu %ul.dropdown-menu.dropdown-menu-right.project-home-dropdown
- if can?(current_user, :create_issue, @project) - if can?(current_user, :create_issue, @project)
%li %li
= link_to url_for_new_issue do = link_to url_for_new_issue do
......
- page_title "Deploy Keys" - page_title "Deploy Keys"
%h3.page-title %h3.page-title
Deploy keys allow read-only access to the repository Deploy keys allow read-only access to the repository
......
- if params[:view] == 'parallel'
- fluid_layout true
.prepend-top-20.append-bottom-20 .prepend-top-20.append-bottom-20
.pull-right .pull-right
.btn-group .btn-group
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
Too many changes to show. Too many changes to show.
.pull-right .pull-right
- unless diff_hard_limit_enabled? - unless diff_hard_limit_enabled?
= link_to "Reload with full diff", url_for(params.merge(force_show_diff: true, format: :html)), class: "btn btn-sm btn-warning" = link_to "Reload with full diff", url_for(params.merge(force_show_diff: true, format: nil)), class: "btn btn-sm btn-warning"
- if current_controller?(:commit) or current_controller?(:merge_requests) - if current_controller?(:commit) or current_controller?(:merge_requests)
- if current_controller?(:commit) - if current_controller?(:commit)
......
...@@ -50,39 +50,42 @@ ...@@ -50,39 +50,42 @@
datasets : [{ datasets : [{
fillColor : "rgba(220,220,220,0.5)", fillColor : "rgba(220,220,220,0.5)",
strokeColor : "rgba(220,220,220,1)", strokeColor : "rgba(220,220,220,1)",
pointColor : "rgba(220,220,220,1)", barStrokeWidth: 1,
pointStrokeColor : "#EEE", barValueSpacing: 1,
barDatasetSpacing: 1,
data : #{@commits_per_time.values.to_json} data : #{@commits_per_time.values.to_json}
}] }]
} }
ctx = $("#hour-chart").get(0).getContext("2d"); ctx = $("#hour-chart").get(0).getContext("2d");
new Chart(ctx).Line(data,{"scaleOverlay": true, responsive: true, pointHitDetectionRadius: 2}) new Chart(ctx).Bar(data,{"scaleOverlay": true, responsive: true, pointHitDetectionRadius: 2})
data = { data = {
labels : #{@commits_per_week_days.keys.to_json}, labels : #{@commits_per_week_days.keys.to_json},
datasets : [{ datasets : [{
fillColor : "rgba(220,220,220,0.5)", fillColor : "rgba(220,220,220,0.5)",
strokeColor : "rgba(220,220,220,1)", strokeColor : "rgba(220,220,220,1)",
pointColor : "rgba(220,220,220,1)", barStrokeWidth: 1,
pointStrokeColor : "#EEE", barValueSpacing: 1,
barDatasetSpacing: 1,
data : #{@commits_per_week_days.values.to_json} data : #{@commits_per_week_days.values.to_json}
}] }]
} }
ctx = $("#weekday-chart").get(0).getContext("2d"); ctx = $("#weekday-chart").get(0).getContext("2d");
new Chart(ctx).Line(data,{"scaleOverlay": true, responsive: true, pointHitDetectionRadius: 2}) new Chart(ctx).Bar(data,{"scaleOverlay": true, responsive: true, pointHitDetectionRadius: 2})
data = { data = {
labels : #{@commits_per_month.keys.to_json}, labels : #{@commits_per_month.keys.to_json},
datasets : [{ datasets : [{
fillColor : "rgba(220,220,220,0.5)", fillColor : "rgba(220,220,220,0.5)",
strokeColor : "rgba(220,220,220,1)", strokeColor : "rgba(220,220,220,1)",
pointColor : "rgba(220,220,220,1)", barStrokeWidth: 1,
pointStrokeColor : "#EEE", barValueSpacing: 1,
barDatasetSpacing: 1,
data : #{@commits_per_month.values.to_json} data : #{@commits_per_month.values.to_json}
}] }]
} }
ctx = $("#month-chart").get(0).getContext("2d"); ctx = $("#month-chart").get(0).getContext("2d");
new Chart(ctx).Line(data, {"scaleOverlay": true, responsive: true, pointHitDetectionRadius: 2}) new Chart(ctx).Bar(data, {"scaleOverlay": true, responsive: true, pointHitDetectionRadius: 2})
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment