Commit 999a374f authored by Valery Sizov's avatar Valery Sizov

Merge branch 'emoji-picker-search'into emoji_picker_frequently_used

parents d794ae8e e557c8d0
......@@ -76,7 +76,7 @@ Style/BlockEndNewline:
Description: 'Put end statement of multiline block on its own line.'
Enabled: true
Style/Blocks:
Style/BlockDelimiters:
Description: >-
Avoid using {...} for multi-line blocks (multiline chaining is
always ugly).
......@@ -232,6 +232,10 @@ Style/EvenOdd:
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#predicate-methods'
Enabled: false
Style/ExtraSpacing:
Description: 'Do not use unnecessary spacing.'
Enabled: false
Style/FileName:
Description: 'Use snake_case for source file names.'
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#snake-case-files'
......@@ -431,6 +435,14 @@ Style/OpMethod:
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#other-arg'
Enabled: false
Style/ParallelAssignment:
Description: >-
Check for simple usages of parallel assignment.
It will only warn when the number of variables
matches on both sides of the assignment.
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#parallel-assignment'
Enabled: false
Style/ParenthesesAroundCondition:
Description: >-
Don't use parentheses around the condition of an
......@@ -669,6 +681,13 @@ Style/TrailingWhitespace:
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-trailing-whitespace'
Enabled: false
Style/TrailingUnderscoreVariable:
Description: >-
Checks for the usage of unneeded trailing underscores at the
end of parallel variable assignment.
AllowNamedUnderscoreVariables: true
Enabled: false
Style/TrivialAccessors:
Description: 'Prefer attr_* methods to trivial readers/writers.'
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#attr_family'
......@@ -690,11 +709,6 @@ Style/UnneededPercentQ:
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#percent-q'
Enabled: false
Style/UnneededPercentX:
Description: 'Checks for %x when `` would do.'
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#percent-x'
Enabled: false
Style/VariableInterpolation:
Description: >-
Don't interpolate global, instance and class variables
......@@ -778,6 +792,10 @@ Metrics/MethodLength:
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#short-methods'
Enabled: false
Metrics/ModuleLength:
Description: 'Avoid modules longer than 100 lines of code.'
Enabled: false
#################### Lint ################################
### Warnings
......@@ -961,6 +979,12 @@ Rails/ActionFilter:
Description: 'Enforces consistent use of action filter methods.'
Enabled: true
Rails/Date:
Description: >-
Checks the correct usage of date aware methods,
such as Date.today, Date.current etc.
Enabled: false
Rails/DefaultScope:
Description: 'Checks if the argument passed to default_scope is a block.'
Enabled: false
......@@ -987,6 +1011,12 @@ Rails/ScopeArgs:
Description: 'Checks the arguments of ActiveRecord scopes.'
Enabled: false
Rails/TimeZone:
Description: 'Checks the correct usage of time zone aware methods.'
StyleGuide: 'https://github.com/bbatsov/rails-style-guide#time'
Reference: 'http://danilenko.org/2012/7/6/rails_timezones'
Enabled: false
Rails/Validation:
Description: 'Use validates :attribute, hash of validations.'
Enabled: false
......
......@@ -4,11 +4,23 @@ v 8.4.0 (unreleased)
- Add "Frequently used" category to emoji picker
v 8.3.0 (unreleased)
- Fix Error 500 when doing a search in dashboard before visiting any project (Stan Hu)
- Implement new UI for group page
- Implement search inside emoji picker
- Add project permissions to all project API endpoints (Stan Hu)
v 8.3.0
- Add CAS support (tduehr)
- Bump rack-attack to 4.3.1 for security fix (Stan Hu)
- API support for starred projects for authorized user (Zeger-Jan van de Weg)
- Add link to merge request on build detail page.
- Add open_issues_count to project API (Stan Hu)
- Expand character set of usernames created by Omniauth (Corey Hinshaw)
- Add button to automatically merge a merge request when the build succeeds (Zeger-Jan van de Weg)
- Merge when build succeeds (Zeger-Jan van de Weg)
- Provide better diagnostic message upon project creation errors (Stan Hu)
- Bump devise to 3.5.3 to fix reset token expiring after account creation (Stan Hu)
- Remove api credentials from link to build_page
- Deprecate GitLabCiService making it to always be inactive
- Bump gollum-lib to 4.1.0 (Stan Hu)
- Fix broken group avatar upload under "New group" (Stan Hu)
- Update project repositorize size and commit count during import:repos task (Stan Hu)
......@@ -20,13 +32,16 @@ v 8.3.0 (unreleased)
- Fix 500 error when update group member permission
- Trim leading and trailing whitespace of milestone and issueable titles (Jose Corcuera)
- Recognize issue/MR/snippet/commit links as references
- Backport JIRA features from EE to CE
- Add ignore whitespace change option to commit view
- Fire update hook from GitLab
- Allow account unlock via email
- Style warning about mentioning many people in a comment
- Fix: sort milestones by due date once again (Greg Smethells)
- Migrate all CI::Services and CI::WebHooks to Services and WebHooks
- Don't show project fork event as "imported"
- Add API endpoint to fetch merge request commits list
- Don't create CI status for refs that doesn't have .gitlab-ci.yml, even if the builds are enabled
- Expose events API with comment information and author info
- Fix: Ensure "Remove Source Branch" button is not shown when branch is being deleted. #3583
- Run custom Git hooks when branch is created or deleted.
......@@ -58,6 +73,7 @@ v 8.3.0 (unreleased)
- Do not show build status unless builds are enabled and `.gitlab-ci.yml` is present
- Persist runners registration token in database
- Fix online editor should not remove newlines at the end of the file
- Expose Git's version in the admin area
v 8.2.3
- Fix application settings cache not expiring after changes (Stan Hu)
......@@ -65,8 +81,6 @@ v 8.2.3
- Update documentation for "Guest" permissions
- Properly convert Emoji-only comments into Award Emojis
- Enable devise paranoid mode to prevent user enumeration attack
v 8.2.3
- Webhook payload has an added, modified and removed properties for each commit
- Fix 500 error when creating a merge request that removes a submodule
......
......@@ -358,7 +358,7 @@ available at [http://contributor-covenant.org/version/1/1/0/](http://contributor
[core team]: https://about.gitlab.com/core-team/
[getting help page]: https://about.gitlab.com/getting-help/
[Codetriage]: http://www.codetriage.com/gitlabhq/gitlabhq
[up-for-grabs]: https://gitlab.com/gitlab-org/gitlab-ce/issues?label_name=up+for+grabs
[up-for-grabs]: https://gitlab.com/gitlab-org/gitlab-ce/issues?label_name=up-for-grabs
[medium-up-for-grabs]: https://medium.com/@kentcdodds/first-timers-only-78281ea47455
[ce-tracker]: https://gitlab.com/gitlab-org/gitlab-ce/issues
[ee-tracker]: https://gitlab.com/gitlab-org/gitlab-ee/issues
......
......@@ -23,6 +23,7 @@ gem 'devise-async', '~> 0.9.0'
gem 'doorkeeper', '~> 2.2.0'
gem 'omniauth', '~> 1.2.2'
gem 'omniauth-bitbucket', '~> 0.0.2'
gem 'omniauth-cas3', '~> 1.1.2'
gem 'omniauth-facebook', '~> 3.0.0'
gem 'omniauth-github', '~> 1.1.1'
gem 'omniauth-gitlab', '~> 1.0.0'
......@@ -101,6 +102,9 @@ gem 'wikicloth', '0.8.1'
gem 'asciidoctor', '~> 1.5.2'
gem 'rouge', '~> 1.10.1'
# See https://groups.google.com/forum/#!topic/ruby-security-ann/aSbgDiwb24s
gem 'nokogiri', '1.6.7.1'
# Diffs
gem 'diffy', '~> 3.0.3'
......@@ -175,7 +179,7 @@ gem "sanitize", '~> 2.0'
gem 'babosa', '~> 1.0.2'
# Protect against bruteforcing
gem "rack-attack", '~> 4.3.0'
gem "rack-attack", '~> 4.3.1'
# Ace editor
gem 'ace-rails-ap', '~> 2.0.1'
......@@ -186,7 +190,7 @@ gem 'mousetrap-rails', '~> 1.4.6'
# Detect and convert string character encoding
gem 'charlock_holmes', '~> 0.7.3'
gem "sass-rails", '~> 4.0.5'
gem "sass-rails", '~> 5.0.0'
gem "coffee-rails", '~> 4.1.0'
gem "uglifier", '~> 2.7.2'
gem 'turbolinks', '~> 2.5.0'
......@@ -198,9 +202,9 @@ gem 'font-awesome-rails', '~> 4.2'
gem 'gitlab_emoji', '~> 0.2.0'
gem 'gon', '~> 6.0.1'
gem 'jquery-atwho-rails', '~> 1.3.2'
gem 'jquery-rails', '~> 3.1.3'
gem 'jquery-rails', '~> 4.0.0'
gem 'jquery-scrollto-rails', '~> 1.4.3'
gem 'jquery-ui-rails', '~> 4.2.1'
gem 'jquery-ui-rails', '~> 5.0.0'
gem 'nprogress-rails', '~> 0.1.6.7'
gem 'raphael-rails', '~> 2.1.2'
gem 'request_store', '~> 1.2.0'
......@@ -215,7 +219,7 @@ group :development do
gem "annotate", "~> 2.6.0"
gem "letter_opener", '~> 1.1.2'
gem 'quiet_assets', '~> 1.0.2'
gem 'rerun', '~> 0.10.0'
gem 'rerun', '~> 0.11.0'
gem 'bullet', require: false
gem 'rblineprof', platform: :mri, require: false
gem 'web-console', '~> 2.0'
......@@ -251,7 +255,7 @@ group :development, :test do
gem 'capybara', '~> 2.4.0'
gem 'capybara-screenshot', '~> 1.0.0'
gem 'poltergeist', '~> 1.6.0'
gem 'poltergeist', '~> 1.8.1'
gem 'teaspoon', '~> 1.0.0'
gem 'teaspoon-jasmine', '~> 2.2.0'
......@@ -261,7 +265,7 @@ group :development, :test do
gem 'spring-commands-spinach', '~> 1.0.0'
gem 'spring-commands-teaspoon', '~> 0.0.2'
gem 'rubocop', '~> 0.28.0', require: false
gem 'rubocop', '~> 0.35.0', require: false
gem 'coveralls', '~> 0.8.2', require: false
gem 'simplecov', '~> 0.10.0', require: false
gem 'flog', require: false
......
......@@ -117,23 +117,6 @@ GEM
activemodel (>= 3.2.0)
activesupport (>= 3.2.0)
json (>= 1.7)
celluloid (0.17.2)
celluloid-essentials
celluloid-extras
celluloid-fsm
celluloid-pool
celluloid-supervision
timers (>= 4.1.1)
celluloid-essentials (0.20.5)
timers (>= 4.1.1)
celluloid-extras (0.20.5)
timers (>= 4.1.1)
celluloid-fsm (0.20.5)
timers (>= 4.1.1)
celluloid-pool (0.20.5)
timers (>= 4.1.1)
celluloid-supervision (0.20.5)
timers (>= 4.1.1)
charlock_holmes (0.7.3)
chunky_png (1.3.5)
cliver (0.3.2)
......@@ -369,7 +352,6 @@ GEM
hipchat (1.5.2)
httparty
mimemagic
hitimes (1.2.3)
html-pipeline (1.11.0)
activesupport (>= 2)
nokogiri (~> 1.4)
......@@ -390,15 +372,16 @@ GEM
inflecto (0.0.2)
ipaddress (0.8.0)
jquery-atwho-rails (1.3.2)
jquery-rails (3.1.4)
railties (>= 3.0, < 5.0)
jquery-rails (4.0.5)
rails-dom-testing (~> 1.0)
railties (>= 4.2.0)
thor (>= 0.14, < 2.0)
jquery-scrollto-rails (1.4.3)
railties (> 3.1, < 5.0)
jquery-turbolinks (2.1.0)
railties (>= 3.1.0)
turbolinks
jquery-ui-rails (4.2.1)
jquery-ui-rails (5.0.5)
railties (>= 3.2.16)
json (1.8.3)
jwt (1.5.2)
......@@ -410,8 +393,7 @@ GEM
addressable (~> 2.3)
letter_opener (1.1.2)
launchy (~> 2.2)
listen (2.9.0)
celluloid (>= 0.15.2)
listen (3.0.5)
rb-fsevent (>= 0.9.3)
rb-inotify (>= 0.9)
loofah (2.0.3)
......@@ -424,7 +406,7 @@ GEM
method_source (0.8.2)
mime-types (1.25.1)
mimemagic (0.3.0)
mini_portile (0.6.2)
mini_portile2 (2.0.0)
minitest (5.7.0)
mousetrap-rails (1.4.6)
multi_json (1.11.2)
......@@ -439,8 +421,8 @@ GEM
grape
newrelic_rpm
newrelic_rpm (3.9.4.245)
nokogiri (1.6.6.4)
mini_portile (~> 0.6.0)
nokogiri (1.6.7.1)
mini_portile2 (~> 2.0.0.rc2)
nprogress-rails (0.1.6.7)
oauth (0.4.7)
oauth2 (1.0.0)
......@@ -458,6 +440,10 @@ GEM
multi_json (~> 1.7)
omniauth (~> 1.1)
omniauth-oauth (~> 1.0)
omniauth-cas3 (1.1.3)
addressable (~> 2.3)
nokogiri (~> 1.6.6)
omniauth (~> 1.2)
omniauth-facebook (3.0.0)
omniauth-oauth2 (~> 1.2)
omniauth-github (1.1.2)
......@@ -507,13 +493,13 @@ GEM
parser (2.2.3.0)
ast (>= 1.1, < 3.0)
pg (0.18.4)
poltergeist (1.6.0)
poltergeist (1.8.1)
capybara (~> 2.1)
cliver (~> 0.3.1)
multi_json (~> 1.0)
websocket-driver (>= 0.2.0)
posix-spawn (0.3.11)
powerpack (0.0.9)
powerpack (0.1.1)
pry (0.10.3)
coderay (~> 1.1.0)
method_source (~> 0.8.1)
......@@ -526,7 +512,7 @@ GEM
rack (1.6.4)
rack-accept (0.4.5)
rack (>= 0.4)
rack-attack (4.3.0)
rack-attack (4.3.1)
rack
rack-cors (0.4.0)
rack-mount (0.8.3)
......@@ -601,8 +587,8 @@ GEM
redis-store (1.1.7)
redis (>= 2.2)
request_store (1.2.1)
rerun (0.10.0)
listen (~> 2.7, >= 2.7.3)
rerun (0.11.0)
listen (~> 3.0)
responders (2.1.0)
railties (>= 4.2.0, < 5)
rest-client (1.8.0)
......@@ -637,12 +623,13 @@ GEM
rspec-mocks (~> 3.3.0)
rspec-support (~> 3.3.0)
rspec-support (3.3.0)
rubocop (0.28.0)
rubocop (0.35.1)
astrolabe (~> 1.3)
parser (>= 2.2.0.pre.7, < 3.0)
powerpack (~> 0.0.6)
parser (>= 2.2.3.0, < 3.0)
powerpack (~> 0.1)
rainbow (>= 1.99.1, < 3.0)
ruby-progressbar (~> 1.4)
ruby-progressbar (~> 1.7)
tins (<= 1.6.0)
ruby-fogbugz (0.2.1)
crack (~> 0.4)
ruby-progressbar (1.7.5)
......@@ -661,12 +648,13 @@ GEM
safe_yaml (1.0.4)
sanitize (2.1.0)
nokogiri (>= 1.4.4)
sass (3.2.19)
sass-rails (4.0.5)
sass (3.4.20)
sass-rails (5.0.4)
railties (>= 4.0.0, < 5.0)
sass (~> 3.2.2)
sprockets (~> 2.8, < 3.0)
sprockets-rails (~> 2.0)
sass (~> 3.1)
sprockets (>= 2.8, < 4.0)
sprockets-rails (>= 2.0, < 4.0)
tilt (>= 1.1, < 3)
sawyer (0.6.0)
addressable (~> 2.3.5)
faraday (~> 0.8, < 0.10)
......@@ -758,8 +746,6 @@ GEM
thor (0.19.1)
thread_safe (0.3.5)
tilt (1.4.1)
timers (4.1.1)
hitimes
timfel-krb5-auth (0.8.3)
tinder (1.10.1)
eventmachine (~> 1.0)
......@@ -894,10 +880,10 @@ DEPENDENCIES
html-pipeline (~> 1.11.0)
httparty (~> 0.13.3)
jquery-atwho-rails (~> 1.3.2)
jquery-rails (~> 3.1.3)
jquery-rails (~> 4.0.0)
jquery-scrollto-rails (~> 1.4.3)
jquery-turbolinks (~> 2.1.0)
jquery-ui-rails (~> 4.2.1)
jquery-ui-rails (~> 5.0.0)
kaminari (~> 0.16.3)
letter_opener (~> 1.1.2)
mail_room (~> 0.6.1)
......@@ -908,11 +894,13 @@ DEPENDENCIES
net-ssh (~> 3.0.1)
newrelic-grape
newrelic_rpm (~> 3.9.4.245)
nokogiri (= 1.6.7.1)
nprogress-rails (~> 0.1.6.7)
oauth2 (~> 1.0.0)
octokit (~> 3.7.0)
omniauth (~> 1.2.2)
omniauth-bitbucket (~> 0.0.2)
omniauth-cas3 (~> 1.1.2)
omniauth-facebook (~> 3.0.0)
omniauth-github (~> 1.1.1)
omniauth-gitlab (~> 1.0.0)
......@@ -925,10 +913,10 @@ DEPENDENCIES
org-ruby (~> 0.9.12)
paranoia (~> 2.0)
pg (~> 0.18.2)
poltergeist (~> 1.6.0)
poltergeist (~> 1.8.1)
pry-rails
quiet_assets (~> 1.0.2)
rack-attack (~> 4.3.0)
rack-attack (~> 4.3.1)
rack-cors (~> 0.4.0)
rack-oauth2 (~> 1.2.1)
rails (= 4.2.4)
......@@ -940,15 +928,15 @@ DEPENDENCIES
redis-namespace
redis-rails (~> 4.0.0)
request_store (~> 1.2.0)
rerun (~> 0.10.0)
rerun (~> 0.11.0)
responders (~> 2.0)
rouge (~> 1.10.1)
rqrcode-rails3 (~> 0.1.7)
rspec-rails (~> 3.3.0)
rubocop (~> 0.28.0)
rubocop (~> 0.35.0)
ruby-fogbugz (~> 0.2.1)
sanitize (~> 2.0)
sass-rails (~> 4.0.5)
sass-rails (~> 5.0.0)
sdoc (~> 0.3.20)
seed-fu (~> 2.3.5)
select2-rails (~> 3.5.9)
......
8.3.0.pre
8.4.0.pre
......@@ -5,7 +5,7 @@
# the compiled file.
#
#= require jquery
#= require jquery.ui.all
#= require jquery-ui
#= require jquery_ujs
#= require jquery.cookie
#= require jquery.endless-scroll
......
......@@ -11,6 +11,7 @@ class @AwardsHandler
$(".emoji-menu").hide()
@renderFrequentlyUsedBlock()
@setupSearch()
addAward: (emoji) ->
emoji = @normilizeEmojiName(emoji)
......@@ -80,7 +81,7 @@ class @AwardsHandler
nodes = []
nodes.push("<div class='award active' title='me'>")
nodes.push("<div class='icon emoji-icon " + emojiCssClass + "' data-emoji='" + emoji + "'></div>")
nodes.push("<div class='icon emoji-icon #{emojiCssClass}' data-emoji='#{emoji}'></div>")
nodes.push("<div class='counter'>1</div>")
nodes.push("</div>")
......@@ -89,13 +90,19 @@ class @AwardsHandler
$(".award").tooltip()
resolveNameToCssClass: (emoji) ->
unicodeName = $(".emoji-menu-content [data-emoji='?']".replace("?", emoji)).data("unicode-name")
emoji_icon = $(".emoji-menu-content [data-emoji='#{emoji}']")
"emoji-" + unicodeName
if emoji_icon.length > 0
unicodeName = emoji_icon.data("unicode-name")
else
# Find by alias
unicodeName = $(".emoji-menu-content [data-aliases*=':#{emoji}:']").data("unicode-name")
"emoji-#{unicodeName}"
postEmoji: (emoji, callback) ->
$.post @post_emoji_url, { note: {
note: ":" + emoji + ":"
note: ":#{emoji}:"
noteable_type: @noteable_type
noteable_id: @noteable_id
}},(data) ->
......@@ -103,7 +110,7 @@ class @AwardsHandler
callback.call()
findEmojiIcon: (emoji) ->
$(".award [data-emoji='" + emoji + "']")
$(".award [data-emoji='#{emoji}']")
scrollToAwards: ->
$('body, html').animate({
......@@ -134,3 +141,22 @@ class @AwardsHandler
$(".emoji-menu-content").prepend(ul).prepend($("<h4>").text("Frequently used"))
setupSearch: ->
$("input.emoji-search").keyup (ev) =>
term = $(ev.target).val()
# Clean previous search results
$("ul.emoji-search,h5.emoji-search").remove()
if term
# Generate search result block
h5 = $("<h5>").text("Search results").addClass("emoji-search")
found_emojis = @searchEmojis(term).show()
ul = $("<ul>").addClass("emoji-search").append(found_emojis)
$(".emoji-menu-content ul, .emoji-menu-content h5").hide()
$(".emoji-menu-content").append(h5).append(ul)
else
$(".emoji-menu-content").children().show()
searchEmojis: (term)->
$(".emoji-menu-content [data-emoji*='#{term}']").closest("li").clone()
......@@ -18,7 +18,7 @@ class @IssuableContext
$('.issuable-affix').affix offset:
top: ->
@top = ($('.issuable-affix').offset().top - 60)
@top = ($('.issuable-affix').offset().top - 70)
bottom: ->
@bottom = $('.footer').outerHeight(true)
......
......@@ -10,12 +10,12 @@ class @Issue
@initTaskList()
initTaskList: ->
$('.issue-details .js-task-list-container').taskList('enable')
$(document).on 'tasklist:changed', '.issue-details .js-task-list-container', @updateTaskList
$('.detail-page-description .js-task-list-container').taskList('enable')
$(document).on 'tasklist:changed', '.detail-page-description .js-task-list-container', @updateTaskList
disableTaskList: ->
$('.issue-details .js-task-list-container').taskList('disable')
$(document).off 'tasklist:changed', '.issue-details .js-task-list-container'
$('.detail-page-description .js-task-list-container').taskList('disable')
$(document).off 'tasklist:changed', '.detail-page-description .js-task-list-container'
# TODO (rspeicher): Make the issue description inline-editable like a note so
# that we can re-use its form here
......
......@@ -40,12 +40,12 @@ class @MergeRequest
this.$('.all-commits').removeClass 'hide'
initTaskList: ->
$('.merge-request-details .js-task-list-container').taskList('enable')
$(document).on 'tasklist:changed', '.merge-request-details .js-task-list-container', @updateTaskList
$('.detail-page-description .js-task-list-container').taskList('enable')
$(document).on 'tasklist:changed', '.detail-page-description .js-task-list-container', @updateTaskList
disableTaskList: ->
$('.merge-request-details .js-task-list-container').taskList('disable')
$(document).off 'tasklist:changed', '.merge-request-details .js-task-list-container'
$('.detail-page-description .js-task-list-container').taskList('disable')
$(document).off 'tasklist:changed', '.detail-page-description .js-task-list-container'
# TODO (rspeicher): Make the merge request description inline-editable like a
# note so that we can re-use its form here
......
......@@ -2,8 +2,8 @@
* This is a manifest file that'll automatically include all the stylesheets available in this directory
* and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
* the top of the compiled file, but it's generally better to create a new file per style scope.
*= require jquery.ui.datepicker
*= require jquery.ui.autocomplete
*= require jquery-ui/datepicker
*= require jquery-ui/autocomplete
*= require jquery.atwho
*= require select2
*= require_self
......@@ -48,4 +48,4 @@
/*
* Styles for JS behaviors.
*/
@import "behaviors.scss";
\ No newline at end of file
@import "behaviors.scss";
......@@ -76,7 +76,7 @@
.cover-block {
text-align: center;
background: #f7f8fa;
background: $background-color;
margin: -$gl-padding;
margin-bottom: 0;
padding: 44px $gl-padding;
......
@mixin btn-default {
@include border-radius(2px);
@include border-radius(3px);
border-width: 1px;
border-style: solid;
text-transform: uppercase;
font-size: 13px;
font-weight: 600;
font-size: 15px;
font-weight: 500;
line-height: 18px;
padding: 11px $gl-padding;
letter-spacing: .4px;
......@@ -18,7 +17,7 @@
@mixin btn-middle {
@include btn-default;
@include border-radius(2px);
@include border-radius(3px);
padding: 11px 24px;
}
......@@ -51,6 +50,10 @@
@include btn-color($blue-light, $border-blue-light, $blue-normal, $border-blue-normal, $blue-dark, $border-blue-dark, #FFFFFF);
}
@mixin btn-blue-medium {
@include btn-color($blue-medium-light, $border-blue-light, $blue-medium, $border-blue-normal, $blue-medium-dark, $border-blue-dark, #FFFFFF);
}
@mixin btn-orange {
@include btn-color($orange-light, $border-orange-light, $orange-normal, $border-orange-normal, $orange-dark, $border-orange-dark, #FFFFFF);
}
......@@ -60,7 +63,7 @@
}
@mixin btn-gray {
@include btn-color($gray-light, $border-gray-light, $gray-normal, $border-gray-normal, $gray-dark, $border-gray-dark, #313236);
@include btn-color($gray-light, $border-gray-light, $gray-normal, $border-gray-light, $gray-dark, $border-gray-dark, #313236);
}
@mixin btn-white {
......@@ -75,6 +78,10 @@
padding: 5px 10px;
}
&.btn-nr {
padding: 7px 10px;
}
&.btn-xs {
padding: 1px 5px;
}
......@@ -91,11 +98,15 @@
@include btn-gray;
}
&.btn-primary,
&.btn-primary {
@include btn-blue-medium;
}
&.btn-info {
@include btn-blue;
}
&.btn-close,
&.btn-warning {
@include btn-orange;
}
......@@ -110,20 +121,8 @@
float: right;
}
&.btn-close {
color: $gl-danger;
border-color: $gl-danger;
&:hover {
color: #B94A48;
}
}
&.btn-reopen {
color: $gl-success;
border-color: $gl-success;
&:hover {
color: #468847;
}
/* should be same as parent class for now */
}
&.btn-grouped {
......
......@@ -374,7 +374,7 @@ table {
}
}
.center-top-menu {
.center-top-menu, .left-top-menu {
@include nav-menu;
text-align: center;
margin-top: 5px;
......@@ -401,6 +401,16 @@ table {
border-bottom: 1px solid $border-color;
height: 57px;
}
&.wide {
margin-left: -$gl-padding;
margin-right: -$gl-padding;
}
}
.left-top-menu {
text-align: left;
border-bottom: 1px solid #EEE;
}
.center-middle-menu {
......
......@@ -4,8 +4,8 @@
*
*/
.issue-box {
@include border-radius(2px);
.status-box {
@include border-radius(3px);
display: block;
float: left;
......@@ -14,22 +14,22 @@
margin-right: 10px;
font-size: $gl-font-size;
&.issue-box-closed {
&.status-box-closed {
background-color: $gl-danger;
color: #FFF;
}
&.issue-box-merged {
&.status-box-merged {
background-color: $gl-primary;
color: #FFF;
}
&.issue-box-open {
background-color: #019875;
&.status-box-open {
background-color: $green-light;
color: #FFF;
}
&.issue-box-expired {
&.status-box-expired {
background: #cea61b;
color: #FFF;
}
......
......@@ -5,7 +5,7 @@ html {
}
body {
background-color: #EAEBEC !important;
background-color: #F3F3F3 !important;
&.navless {
background-color: white !important;
......
......@@ -143,7 +143,11 @@ ul.controls {
> li {
float: left;
padding-right: 10px;
margin-right: 10px;
&:last-child {
margin-right: 0;
}
.author_link {
display: inline-block;
......
......@@ -87,7 +87,7 @@
.new_note,
.edit_note,
.issuable-description,
.detail-page-description,
.milestone-description,
.wiki-content,
.merge-request-form {
......
......@@ -123,7 +123,6 @@
padding: 0;
margin: 0;
list-style: none;
margin-top: 5px;
height: 56px;
li {
......@@ -131,9 +130,9 @@
a {
padding: 14px;
font-size: 17px;
font-size: 15px;
line-height: 28px;
color: #7f8fa4;
color: #959494;
border-bottom: 2px solid transparent;
&:hover, &:active, &:focus {
......@@ -143,8 +142,8 @@
}
&.active a {
color: #4c4e54;
border-bottom: 2px solid #1cacfc;
color: #616060;
border-bottom: 2px solid #4688f1;
}
.badge {
......
......@@ -81,7 +81,7 @@
display: none;
}
.center-top-menu {
.center-top-menu, .left-top-menu {
li a {
font-size: 14px;
padding: 19px 10px;
......
......@@ -3,7 +3,6 @@
.panel-heading {
padding: 7px $gl-padding;
line-height: 42px !important;
}
.panel-body {
......@@ -15,3 +14,7 @@
}
}
}
.container-blank .panel .panel-heading {
line-height: 42px !important;
}
......@@ -10,8 +10,7 @@
margin-left: -$gl-padding;
margin-right: -$gl-padding;
color: $gl-gray;
border-bottom: 1px solid #ECEEF1;
border-right: 1px solid #ECEEF1;
border-bottom: 1px solid $border-white-light;
&:target {
background: $hover;
......
$hover: #FFFAF1;
$hover: #faf9f9;
$gl-text-color: #54565B;
$gl-text-green: #4A2;
$gl-text-red: #D12F19;
$gl-text-orange: #D90;
$gl-header-color: #4c4e54;
$gl-header-color: #323232;
$gl-link-color: #333c48;
$md-text-color: #444;
$md-link-color: #3084bb;
......@@ -15,13 +15,14 @@ $sidebar_width: 230px;
$avatar_radius: 50%;
$code_font_size: 13px;
$code_line_height: 1.5;
$border-color: #dce0e6;
$border-color: #efeff1;
$table-border-color: #eef0f2;
$background-color: #F7F8FA;
$background-color: #faf9f9;
$header-height: 58px;
$fixed-layout-width: 1200px;
$gl-gray: #7f8fa4;
$fixed-layout-width: 1280px;
$gl-gray: #5a5a5a;
$gl-padding: 16px;
$gl-padding-top:10px;
$gl-avatar-size: 46px;
/*
......@@ -29,12 +30,12 @@ $gl-avatar-size: 46px;
*/
$white-light: #FFFFFF;
$white-normal: #DCE0E5;
$white-dark: #E4E7ED;
$white-normal: #ededed;
$white-dark: #ededed;
$gray-light: #F0F2F5;
$gray-normal: #DCE0E5;
$gray-dark: #E4E7ED;
$gray-light: #f7f7f7;
$gray-normal: #ededed;
$gray-dark: #ededed;
$green-light: #31AF64;
$green-normal: #2FAA60;
......@@ -44,6 +45,10 @@ $blue-light: #2EA8E5;
$blue-normal: #2D9FD8;
$blue-dark: #2897CE;
$blue-medium-light: #3498CB;
$blue-medium: #2F8EBF;
$blue-medium-dark: #2D86B4;
$orange-light: #FC6443;
$orange-normal: #E75E40;
$orange-dark: #CE5237;
......@@ -52,11 +57,11 @@ $red-light: #F43263;
$red-normal: #E52C5A;
$red-dark: #D22852;
$border-white-light: #E3E7EC;
$border-white-light: #F1F2F4;
$border-white-normal: #D6DAE2;
$border-white-dark: #C6CACF;
$border-gray-light: #DCE0E5;
$border-gray-light: #d1d1d1;
$border-gray-normal: #D6DAE2;
$border-gray-dark: #C6CACF;
......@@ -76,6 +81,8 @@ $border-red-light: #E52C5A;
$border-red-normal: #D22852;
$border-red-dark: #CA264F;
/* header */
$light-grey-header: #faf9f9;
/*
* State colors:
......
......@@ -90,13 +90,19 @@
height: 300px;
overflow-y: scroll;
h4 {
h5 {
clear: left;
}
ul {
list-style-type: none;
margin-left: -20px;
margin-bottom: 20px;
overflow: auto;
}
input.emoji-search{
background: image-url(/assets/icon-search.png) 240px no-repeat;
}
li {
......
.detail-page-header {
margin: -$gl-padding;
padding: 7px $gl-padding;
margin-bottom: 0px;
border-bottom: 1px solid $border-color;
color: #5c5d5e;
font-size: 16px;
line-height: 34px;
.author {
color: #5c5d5e;
}
.identifier {
color: #5c5d5e;
}
}
.detail-page-description {
.title {
margin: 0;
font-size: 23px;
color: #313236;
}
.description {
margin-top: 6px;
p:last-child {
margin-bottom: 0;
}
}
}
......@@ -4,7 +4,7 @@ The source: gemojione gem.
*/
.emoji-icon{
background-image: url(emoji.png);
background-image: image-url(emoji.png);
background-repeat: no-repeat;
}
......
......@@ -18,7 +18,7 @@
&.affix {
position: fixed;
top: 60px;
top: 70px;
margin-right: 35px;
}
}
......@@ -36,33 +36,12 @@
}
.issuable-details {
.issue-title {
margin: 0;
font-size: 23px;
color: #313236;
}
.description {
margin-top: 6px;
p:last-child {
margin-bottom: 0;
}
}
section {
border-right: 1px solid #ECEEF1;
border-right: 1px solid $border-white-light;
> .tab-content {
.issuable-discussion {
margin-right: 1px;
}
.issue-discussion > .gray-content-block,
> .gray-content-block {
margin-top: 0;
border-top: none;
margin-right: -15px;
}
}
}
......@@ -136,21 +115,3 @@
margin-right: 2px;
}
}
.issuable-title {
margin: -$gl-padding;
padding: 7px $gl-padding;
margin-bottom: 0px;
border-bottom: 1px solid $border-color;
color: #5c5d5e;
font-size: 16px;
line-height: 42px;
.author {
color: #5c5d5e;
}
.issuable-id {
color: #5c5d5e;
}
}
......@@ -141,11 +141,6 @@ form.edit-issue {
}
}
.issue-closed-by-widget {
padding: 16px 0;
margin: 0px;
}
.issue-form .select2-container {
width: 250px !important;
}
......@@ -191,7 +191,7 @@
.btn-clipboard {
@extend .pull-right;
margin-right: 18px;
margin-right: 20px;
margin-top: 5px;
position: absolute;
right: 0;
......
......@@ -75,17 +75,15 @@
.common-note-form {
margin: 0;
background: #F7F8FA;
background: #fff;
padding: $gl-padding;
margin-left: -$gl-padding;
margin-right: -$gl-padding;
border-right: 1px solid $border-color;
border-top: 1px solid $border-color;
margin-bottom: -$gl-padding;
}
.note-form-actions {
background: #F9F9F9;
background: #fff;
.note-form-option {
margin-top: 8px;
......
......@@ -128,7 +128,7 @@ ul.notes {
}
&:last-child {
border-bottom: none;
border-bottom: 1px solid $border-color;
}
}
}
......
......@@ -335,6 +335,36 @@ ul.nav.nav-projects-tabs {
}
}
.top-area {
border-bottom: 1px solid #EEE;
ul.left-top-menu {
display: inline-block;
width: 50%;
margin-bottom: 0px;
border-bottom: none;
}
.projects-search-form {
width: 50%;
display: inline-block;
float: right;
padding-top: 7px;
text-align: right;
.btn-green {
margin-top: -2px;
margin-left: 10px;
}
}
@media (max-width: $screen-xs-max) {
.projects-search-form {
padding-top: 15px;
}
}
}
.fork-namespaces {
.fork-thumbnail {
text-align: center;
......@@ -412,11 +442,18 @@ pre.light-well {
.projects-search-form {
margin: -$gl-padding;
background-color: #f8fafc;
padding: $gl-padding;
margin-bottom: 0px;
border-top: 1px solid #e7e9ed;
border-bottom: 1px solid #e7e9ed;
input {
display: inline-block;
width: calc(100% - 151px);
}
.btn {
display: inline-block;
width: 135px;
}
}
.git-empty {
......
......@@ -35,3 +35,20 @@
border-color: $gl-warning;
}
}
.ci-status-icon-success {
@extend .cgreen;
}
.ci-status-icon-failed {
@extend .cred;
}
.ci-status-icon-running,
.ci-status-icon-pending {
// These are standard text color
}
.ci-status-icon-canceled,
.ci-status-icon-disabled,
.ci-status-icon-not-found,
.ci-status-icon-skipped {
@extend .cgray;
}
class Admin::IdentitiesController < Admin::ApplicationController
before_action :user
before_action :identity, except: :index
before_action :identity, except: [:index, :new, :create]
def new
@identity = Identity.new
end
def create
@identity = Identity.new(identity_params)
@identity.user_id = user.id
if @identity.save
redirect_to admin_user_identities_path(@user), notice: 'User identity was successfully created.'
else
render :new
end
end
def index
@identities = @user.identities
......
......@@ -10,6 +10,7 @@ class ApplicationController < ActionController::Base
before_action :authenticate_user_from_token!
before_action :authenticate_user!
before_action :validate_user_service_ticket!
before_action :reject_blocked!
before_action :check_password_expiration
before_action :ldap_security_check
......@@ -202,6 +203,20 @@ class ApplicationController < ActionController::Base
end
end
def validate_user_service_ticket!
return unless signed_in? && session[:service_tickets]
valid = session[:service_tickets].all? do |provider, ticket|
Gitlab::OAuth::Session.valid?(provider, ticket)
end
unless valid
session[:service_tickets] = nil
sign_out current_user
redirect_to new_user_session_path
end
end
def check_password_expiration
if current_user && current_user.password_expires_at && current_user.password_expires_at < Time.now && !current_user.ldap_user?
redirect_to new_profile_password_path and return
......
......@@ -19,8 +19,10 @@ module Ci
@error = e.message
@status = false
rescue
@error = "Undefined error"
@error = 'Undefined error'
@status = false
ensure
render :show
end
end
end
class Dashboard::SnippetsController < Dashboard::ApplicationController
def index
@snippets = SnippetsFinder.new.execute(current_user,
@snippets = SnippetsFinder.new.execute(
current_user,
filter: :by_user,
user: current_user,
scope: params[:scope]
......
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
protect_from_forgery except: [:kerberos, :saml]
protect_from_forgery except: [:kerberos, :saml, :cas3]
Gitlab.config.omniauth.providers.each do |provider|
define_method provider['name'] do
......@@ -42,6 +42,14 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
render 'errors/omniauth_error', layout: "errors", status: 422
end
def cas3
ticket = params['ticket']
if ticket
handle_service_ticket oauth['provider'], ticket
end
handle_omniauth
end
private
def handle_omniauth
......@@ -84,6 +92,12 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
redirect_to new_user_session_path
end
def handle_service_ticket provider, ticket
Gitlab::OAuth::Session.create provider, ticket
session[:service_tickets] ||= {}
session[:service_tickets][provider] = ticket
end
def oauth
@oauth ||= request.env['omniauth.auth']
end
......
......@@ -7,7 +7,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
before_action :closes_issues, only: [:edit, :update, :show, :diffs, :commits, :builds]
before_action :validates_merge_request, only: [:show, :diffs, :commits, :builds]
before_action :define_show_vars, only: [:show, :diffs, :commits, :builds]
before_action :define_widget_vars, only: [:merge, :cancel_merge_when_build_succeeds]
before_action :define_widget_vars, only: [:merge, :cancel_merge_when_build_succeeds, :merge_check]
before_action :ensure_ref_fetched, only: [:show, :diffs, :commits, :builds]
# Allow read any merge_request
......@@ -153,11 +153,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
def merge_check
if @merge_request.unchecked?
@merge_request.check_if_can_be_merged
end
closes_issues
@merge_request.check_if_can_be_merged if @merge_request.unchecked?
render partial: "projects/merge_requests/widget/show.html.haml", layout: false
end
......@@ -178,7 +174,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@merge_request.update(merge_error: nil)
if params[:merge_when_build_succeeds] && @merge_request.ci_commit && @merge_request.ci_commit.active?
if params[:merge_when_build_succeeds].present? && @merge_request.ci_commit && @merge_request.ci_commit.active?
MergeRequests::MergeWhenBuildSucceedsService.new(@project, current_user, merge_params)
.execute(@merge_request)
@status = :merge_when_build_succeeds
......@@ -299,6 +295,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
def define_widget_vars
@ci_commit = @merge_request.ci_commit
closes_issues
end
def invalid_mr
......
......@@ -13,7 +13,8 @@ class Projects::NotesController < Projects::ApplicationController
@notes.each do |note|
notes_json[:notes] << {
id: note.id,
html: note_to_html(note)
html: note_to_html(note),
valid: note.valid?
}
end
......@@ -68,7 +69,7 @@ class Projects::NotesController < Projects::ApplicationController
data = {
author: current_user,
is_award: true,
note: note_params[:note].gsub(":", '')
note: note_params[:note].delete(":")
}
note = noteable.notes.find_by(data)
......
......@@ -21,7 +21,7 @@ class Projects::ProtectedBranchesController < Projects::ApplicationController
if protected_branch &&
protected_branch.update_attributes(
developers_can_push: params[:developers_can_push]
developers_can_push: params[:developers_can_push]
)
respond_to do |format|
......
class Projects::ServicesController < Projects::ApplicationController
ALLOWED_PARAMS = [:title, :token, :type, :active, :api_key, :api_version, :subdomain,
ALLOWED_PARAMS = [:title, :token, :type, :active, :api_key, :api_url, :api_version, :subdomain,
:room, :recipients, :project_url, :webhook,
:user_key, :device, :priority, :sound, :bamboo_url, :username, :password,
:build_key, :server, :teamcity_url, :drone_url, :build_type,
......@@ -10,7 +10,8 @@ class Projects::ServicesController < Projects::ApplicationController
:notify_only_broken_builds, :add_pusher,
:send_from_committer_email, :disable_diffs, :external_wiki_url,
:notify, :color,
:server_host, :server_port, :default_irc_uri, :enable_ssl_verification]
:server_host, :server_port, :default_irc_uri, :enable_ssl_verification,
:jira_issue_transition_id]
# Parameters to ignore if no value is specified
FILTER_BLANK_PARAMS = [:password]
......
......@@ -61,7 +61,7 @@ module ApplicationHelper
options[:class] ||= ''
options[:class] << ' identicon'
bg_key = project.id % 7
style = "background-color: ##{ allowed_colors.values[bg_key] }; color: #555"
style = "background-color: ##{allowed_colors.values[bg_key]}; color: #555"
content_tag(:div, class: options[:class], style: style) do
project.name[0, 1].upcase
......@@ -204,12 +204,16 @@ module ApplicationHelper
# Returns an HTML-safe String
def time_ago_with_tooltip(time, placement: 'top', html_class: 'time_ago', skip_js: false)
element = content_tag :time, time.to_s,
class: "#{html_class} js-timeago",
class: "#{html_class} js-timeago js-timeago-pending",
datetime: time.getutc.iso8601,
title: time.in_time_zone.stamp('Aug 21, 2011 9:23pm'),
data: { toggle: 'tooltip', placement: placement, container: 'body' }
element += javascript_tag "$('.js-timeago').last().timeago()" unless skip_js
unless skip_js
element << javascript_tag(
"$('.js-timeago-pending').removeClass('js-timeago-pending').timeago()"
)
end
element
end
......
......@@ -10,8 +10,8 @@ module ButtonHelper
# # => "<button class='...' data-clipboard-text='Foo'>...</button>"
#
# # Define the target element
# clipboard_button(clipboard_target: "#foo")
# # => "<button class='...' data-clipboard-target='#foo'>...</button>"
# clipboard_button(clipboard_target: "div#foo")
# # => "<button class='...' data-clipboard-target='div#foo'>...</button>"
#
# See http://clipboardjs.com/#usage
def clipboard_button(data = {})
......
......@@ -12,19 +12,6 @@ module CiStatusHelper
ci_label_for_status(ci_commit.status)
end
def ci_status_color(ci_commit)
case ci_commit.status
when 'success'
'green'
when 'failed'
'red'
when 'running', 'pending'
'yellow'
else
'gray'
end
end
def ci_status_with_icon(status)
content_tag :span, class: "ci-status ci-#{status}" do
ci_icon_for_status(status) + '&nbsp;'.html_safe + ci_label_for_status(status)
......@@ -56,12 +43,11 @@ module CiStatusHelper
end
def render_ci_status(ci_commit)
link_to ci_status_path(ci_commit),
class: "ci-status-link c#{ci_status_color(ci_commit)}",
link_to ci_status_icon(ci_commit),
ci_status_path(ci_commit),
class: "ci-status-link ci-status-icon-#{ci_commit.status.dasherize}",
title: "Build #{ci_status_label(ci_commit)}",
data: { toggle: 'tooltip', placement: 'left' } do
ci_status_icon(ci_commit)
end
data: { toggle: 'tooltip', placement: 'left' }
end
def no_runners_for_project?(project)
......
module ExternalWikiHelper
def get_project_wiki_path(project)
external_wiki_service = project.services.
select { |service| service.to_param == 'external_wiki' }.first
find { |service| service.to_param == 'external_wiki' }
if external_wiki_service.present? && external_wiki_service.active?
external_wiki_service.properties['external_wiki_url']
else
......
......@@ -20,7 +20,7 @@ module GitlabMarkdownHelper
end
user = current_user if defined?(current_user)
gfm_body = Gitlab::Markdown.render(escaped_body, project: @project, current_user: user, pipeline: :single_line)
gfm_body = Banzai.render(escaped_body, project: @project, current_user: user, pipeline: :single_line)
fragment = Nokogiri::HTML::DocumentFragment.parse(gfm_body)
if fragment.children.size == 1 && fragment.children[0].name == 'a'
......@@ -50,7 +50,7 @@ module GitlabMarkdownHelper
context[:project] ||= @project
html = Gitlab::Markdown.render(text, context)
html = Banzai.render(text, context)
context.merge!(
current_user: (current_user if defined?(current_user)),
......@@ -61,11 +61,12 @@ module GitlabMarkdownHelper
ref: @ref
)
Gitlab::Markdown.post_process(html, context)
Banzai.post_process(html, context)
end
def asciidoc(text)
Gitlab::Asciidoc.render(text,
Gitlab::Asciidoc.render(
text,
project: @project,
current_user: (current_user if defined?(current_user)),
......
......@@ -57,15 +57,15 @@ module IssuesHelper
options_from_collection_for_select(milestones, 'id', 'title', object.milestone_id)
end
def issue_box_class(item)
def status_box_class(item)
if item.respond_to?(:expired?) && item.expired?
'issue-box-expired'
'status-box-expired'
elsif item.respond_to?(:merged?) && item.merged?
'issue-box-merged'
'status-box-merged'
elsif item.closed?
'issue-box-closed'
'status-box-closed'
else
'issue-box-open'
'status-box-open'
end
end
......@@ -94,12 +94,13 @@ module IssuesHelper
end.sort.to_sentence(last_word_connector: ', or ')
end
def emoji_icon(name, unicode = nil)
def emoji_icon(name, unicode = nil, aliases = [])
unicode ||= Emoji.emoji_filename(name)
content_tag :div, "",
class: "icon emoji-icon emoji-#{unicode}",
"data-emoji" => name,
"data-aliases" => aliases.join(" "),
"data-unicode-name" => unicode
end
......@@ -119,6 +120,6 @@ module IssuesHelper
end
end
# Required for Gitlab::Markdown::IssueReferenceFilter
# Required for Banzai::Filter::IssueReferenceFilter
module_function :url_for_issue
end
......@@ -107,6 +107,6 @@ module LabelsHelper
options_from_collection_for_select(grouped_labels, 'name', 'title', params[:label_name])
end
# Required for Gitlab::Markdown::LabelReferenceFilter
# Required for Banzai::Filter::LabelReferenceFilter
module_function :render_colored_label, :text_color_for_bg, :escape_once
end
......@@ -27,7 +27,16 @@ module MergeRequestsHelper
end
def ci_build_details_path(merge_request)
merge_request.source_project.ci_service.build_page(merge_request.last_commit.sha, merge_request.source_branch)
build_url = merge_request.source_project.ci_service.build_page(merge_request.last_commit.sha, merge_request.source_branch)
return nil unless build_url
parsed_url = URI.parse(build_url)
unless parsed_url.userinfo.blank?
parsed_url.userinfo = ''
end
parsed_url.to_s
end
def merge_path_description(merge_request, separator)
......
......@@ -105,6 +105,14 @@ module ProjectsHelper
end
end
def user_max_access_in_project(user_id, project)
level = project.team.max_member_access(user_id)
if level
Gitlab::Access.options_with_owner.key(level)
end
end
private
def get_project_nav_tabs(project, current_user)
......@@ -277,14 +285,6 @@ module ProjectsHelper
end
end
def user_max_access_in_project(user, project)
level = project.team.max_member_access(user)
if level
Gitlab::Access.options_with_owner.key(level)
end
end
def leave_project_message(project)
"Are you sure you want to leave \"#{project.name}\" project?"
end
......@@ -330,10 +330,9 @@ module ProjectsHelper
def filename_path(project, filename)
if project && blob = project.repository.send(filename)
namespace_project_blob_path(
project.namespace,
project,
tree_join(project.default_branch,
blob.name)
project.namespace,
project,
tree_join(project.default_branch, blob.name)
)
end
end
......
......@@ -79,7 +79,7 @@ module TreeHelper
part_path = File.join(part_path, part) unless part_path.empty?
part_path = part if part_path.empty?
next unless parts.last(2).include?(part) if parts.count > max_links
next if parts.count > max_links && !parts.last(2).include?(part)
yield(part, tree_join(@ref, part_path))
end
end
......
......@@ -17,7 +17,7 @@ class Notify < BaseMailer
subject: subject,
body: body.html_safe,
content_type: 'text/html'
)
)
end
# Splits "gitlab.corp.company.com" up into "gitlab.corp.company.com",
......
......@@ -126,12 +126,16 @@ class ApplicationSetting < ActiveRecord::Base
def restricted_signup_domains_raw=(values)
self.restricted_signup_domains = []
self.restricted_signup_domains = values.split(
/\s*[,;]\s* # comma or semicolon, optionally surrounded by whitespace
| # or
\s # any whitespace character
| # or
[\r\n] # any number of newline characters
/x)
/\s*[,;]\s* # comma or semicolon, optionally surrounded by whitespace
| # or
\s # any whitespace character
| # or
[\r\n] # any number of newline characters
/x)
self.restricted_signup_domains.reject! { |d| d.empty? }
end
def runners_registration_token
ensure_runners_registration_token!
end
end
......@@ -135,6 +135,16 @@ module Ci
predefined_variables + yaml_variables + project_variables + trigger_variables
end
def merge_request
merge_requests = MergeRequest.includes(:merge_request_diff)
.where(source_branch: ref, source_project_id: commit.gl_project_id)
.reorder(iid: :asc)
merge_requests.find do |merge_request|
merge_request.commits.any? { |ci| ci.id == commit.sha }
end
end
def project
commit.project
end
......@@ -170,7 +180,8 @@ module Ci
def extract_coverage(text, regex)
begin
matches = text.gsub(Regexp.new(regex)).to_a.last
matches = text.scan(Regexp.new(regex)).last
matches = matches.last if matches.kind_of?(Array)
coverage = matches.gsub(/\d+(\.\d+)?/).first
if coverage.present?
......
......@@ -218,16 +218,6 @@ module Ci
update!(committed_at: DateTime.now)
end
##
# This method checks if build status should be displayed.
#
# Build status should be available only if builds are enabled
# on project level and `.gitlab-ci.yml` file is present.
#
def show_build_status?
project.builds_enabled? && ci_yaml_file
end
private
def save_yaml_error(error)
......
......@@ -23,7 +23,7 @@ module Mentionable
included do
if self < Participable
participant ->(current_user) { mentioned_users(current_user, load_lazy_references: false) }
participant ->(current_user) { mentioned_users(current_user) }
end
end
......@@ -43,15 +43,15 @@ module Mentionable
self
end
def all_references(current_user = self.author, text = nil, load_lazy_references: true)
ext = Gitlab::ReferenceExtractor.new(self.project, current_user, load_lazy_references: load_lazy_references)
def all_references(current_user = self.author, text = nil)
ext = Gitlab::ReferenceExtractor.new(self.project, current_user)
if text
ext.analyze(text)
else
self.class.mentionable_attrs.each do |attr, options|
text = send(attr)
options[:cache_key] = [self, attr] if options.delete(:cache)
options[:cache_key] = [self, attr] if options.delete(:cache) && self.persisted?
ext.analyze(text, options)
end
end
......@@ -59,13 +59,13 @@ module Mentionable
ext
end
def mentioned_users(current_user = nil, load_lazy_references: true)
all_references(current_user, load_lazy_references: load_lazy_references).users
def mentioned_users(current_user = nil)
all_references(current_user).users
end
# Extract GFM references to other Mentionables from this Mentionable. Always excludes its #local_reference.
def referenced_mentionables(current_user = self.author, text = nil, load_lazy_references: true)
refs = all_references(current_user, text, load_lazy_references: load_lazy_references)
def referenced_mentionables(current_user = self.author, text = nil)
refs = all_references(current_user, text)
refs = (refs.issues + refs.merge_requests + refs.commits)
# We're using this method instead of Array diffing because that requires
......
......@@ -37,21 +37,22 @@ module Participable
# Be aware that this method makes a lot of sql queries.
# Save result into variable if you are going to reuse it inside same request
def participants(current_user = self.author, load_lazy_references: true)
participants = self.class.participant_attrs.flat_map do |attr|
value =
if attr.respond_to?(:call)
instance_exec(current_user, &attr)
else
send(attr)
end
def participants(current_user = self.author)
participants =
Gitlab::ReferenceExtractor.lazily do
self.class.participant_attrs.flat_map do |attr|
value =
if attr.respond_to?(:call)
instance_exec(current_user, &attr)
else
send(attr)
end
participants_for(value, current_user)
end.compact.uniq
if load_lazy_references
participants = Gitlab::Markdown::ReferenceFilter::LazyReference.load(participants).uniq
participants_for(value, current_user)
end.compact.uniq
end
unless Gitlab::ReferenceExtractor.lazy?
participants.select! do |user|
user.can?(:read_project, project)
end
......@@ -64,12 +65,12 @@ module Participable
def participants_for(value, current_user = nil)
case value
when User, Gitlab::Markdown::ReferenceFilter::LazyReference
when User, Banzai::LazyReference
[value]
when Enumerable, ActiveRecord::Relation
value.flat_map { |v| participants_for(v, current_user) }
when Participable
value.participants(current_user, load_lazy_references: false)
value.participants(current_user)
end
end
end
......@@ -13,20 +13,21 @@ module TokenAuthenticatable
@token_fields << token_field
define_singleton_method("find_by_#{token_field}") do |token|
where(token_field => token).first if token
find_by(token_field => token) if token
end
define_method("ensure_#{token_field}") do
current_token = read_attribute(token_field)
if current_token.blank?
write_attribute(token_field, generate_token_for(token_field))
else
current_token
end
current_token.blank? ? write_new_token(token_field) : current_token
end
define_method("ensure_#{token_field}!") do
send("reset_#{token_field}!") if read_attribute(token_field).blank?
read_attribute(token_field)
end
define_method("reset_#{token_field}!") do
write_attribute(token_field, generate_token_for(token_field))
write_new_token(token_field)
save!
end
end
......@@ -34,10 +35,15 @@ module TokenAuthenticatable
private
def generate_token_for(token_field)
def write_new_token(token_field)
new_token = generate_token(token_field)
write_attribute(token_field, new_token)
end
def generate_token(token_field)
loop do
token = Devise.friendly_token
break token unless self.class.unscoped.where(token_field => token).first
break token unless self.class.unscoped.find_by(token_field => token)
end
end
end
......@@ -84,11 +84,11 @@ class Issue < ActiveRecord::Base
end
def referenced_merge_requests
references = [self, *notes].flat_map do |note|
note.all_references(load_lazy_references: false).merge_requests
end.uniq
Gitlab::Markdown::ReferenceFilter::LazyReference.load(references).uniq.sort_by(&:iid)
Gitlab::ReferenceExtractor.lazily do
[self, *notes].flat_map do |note|
note.all_references.merge_requests
end
end.sort_by(&:iid)
end
# Reset issue events cache
......
class JiraIssue < ExternalIssue
end
......@@ -194,9 +194,7 @@ class MergeRequest < ActiveRecord::Base
similar_mrs = similar_mrs.where('id not in (?)', self.id) if self.id
if similar_mrs.any?
errors.add :validate_branches,
"Cannot Create: This merge request already exists: #{
similar_mrs.pluck(:title)
}"
"Cannot Create: This merge request already exists: #{similar_mrs.pluck(:title)}"
end
end
end
......@@ -337,7 +335,7 @@ class MergeRequest < ActiveRecord::Base
issues = commits.flat_map { |c| c.closes_issues(current_user) }
issues.push(*Gitlab::ClosingIssueExtractor.new(project, current_user).
closed_by_message(description))
issues.uniq
issues.uniq(&:id)
else
[]
end
......
......@@ -45,7 +45,7 @@ class Namespace < ActiveRecord::Base
class << self
def by_path(path)
where('lower(path) = :value', value: path.downcase).first
find_by('lower(path) = :value', value: path.downcase)
end
# Case insensetive search for namespace by path or name
......@@ -148,6 +148,6 @@ class Namespace < ActiveRecord::Base
end
def find_fork_of(project)
projects.joins(:forked_project_link).where('forked_project_links.forked_from_project_id = ?', project.id).first
projects.joins(:forked_project_link).find_by('forked_project_links.forked_from_project_id = ?', project.id)
end
end
......@@ -373,11 +373,11 @@ class Note < ActiveRecord::Base
end
def contains_emoji_only?
note =~ /\A#{Gitlab::Markdown::EmojiFilter.emoji_pattern}\s?\Z/
note =~ /\A#{Banzai::Filter::EmojiFilter.emoji_pattern}\s?\Z/
end
def award_emoji_name
original_name = note.match(Gitlab::Markdown::EmojiFilter.emoji_pattern)[1]
original_name = note.match(Banzai::Filter::EmojiFilter.emoji_pattern)[1]
AwardEmoji.normilize_emoji_name(original_name)
end
end
......@@ -265,7 +265,7 @@ class Project < ActiveRecord::Base
joins(:namespace).
iwhere('namespaces.path' => namespace_path)
projects.where('projects.path' => project_path).take ||
projects.find_by('projects.path' => project_path) ||
projects.iwhere('projects.path' => project_path).take
end
......@@ -450,7 +450,7 @@ class Project < ActiveRecord::Base
end
def external_issue_tracker
@external_issues_tracker ||= external_issues_trackers.select(&:activated?).first
@external_issues_tracker ||= external_issues_trackers.find(&:activated?)
end
def can_have_issues_tracker_id?
......@@ -496,7 +496,11 @@ class Project < ActiveRecord::Base
end
def ci_service
@ci_service ||= ci_services.select(&:activated?).first
@ci_service ||= ci_services.find(&:activated?)
end
def jira_tracker?
issues_tracker.to_param == 'jira'
end
def avatar_type
......@@ -547,7 +551,7 @@ class Project < ActiveRecord::Base
end
def project_member_by_name_or_email(name = nil, email = nil)
user = users.where('name like ? or email like ?', name, email).first
user = users.find_by('name like ? or email like ?', name, email)
project_members.where(user: user) if user
end
......@@ -722,7 +726,7 @@ class Project < ActiveRecord::Base
end
def project_member(user)
project_members.where(user_id: user).first
project_members.find_by(user_id: user)
end
def default_branch
......@@ -799,6 +803,10 @@ class Project < ActiveRecord::Base
false
end
def jira_tracker_active?
jira_tracker? && jira_service.active
end
def ci_commit(sha)
ci_commits.find_by(sha: sha)
end
......@@ -850,4 +858,8 @@ class Project < ActiveRecord::Base
def build_timeout_in_minutes=(value)
self.build_timeout = value.to_i * 60
end
def open_issues_count
issues.opened.count
end
end
......@@ -27,12 +27,10 @@ class BambooService < CiService
validates :build_key, presence: true, if: :activated?
validates :username,
presence: true,
if: ->(service) { service.password? },
if: :activated?
if: ->(service) { service.activated? && service.password }
validates :password,
presence: true,
if: ->(service) { service.username? },
if: :activated?
if: ->(service) { service.activated? && service.username }
attr_accessor :response
......
......@@ -58,6 +58,6 @@ class FlowdockService < Service
repo_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}",
commit_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/commit/%s",
diff_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/compare/%s...%s",
)
)
end
end
......@@ -57,6 +57,6 @@ class GemnasiumService < Service
token: token,
api_key: api_key,
repo: project.repository.path_to_repo
)
)
end
end
......@@ -18,6 +18,11 @@
# note_events :boolean default(TRUE), not null
#
# TODO(ayufan): The GitLabCiService is deprecated and the type should be removed when the database entries are removed
class GitlabCiService < CiService
# this is no longer used
# We override the active accessor to always make GitLabCiService disabled
# Otherwise the GitLabCiService can be picked, but should never be since it's deprecated
def active
false
end
end
......@@ -19,9 +19,24 @@
#
class JiraService < IssueTrackerService
include HTTParty
include Gitlab::Application.routes.url_helpers
prop_accessor :title, :description, :project_url, :issues_url, :new_issue_url
DEFAULT_API_VERSION = 2
prop_accessor :username, :password, :api_url, :jira_issue_transition_id,
:title, :description, :project_url, :issues_url, :new_issue_url
before_validation :set_api_url, :set_jira_issue_transition_id
before_update :reset_password
def reset_password
# don't reset the password if a new one is provided
if api_url_changed? && !password_touched?
self.password = nil
end
end
def help
line1 = 'Setting `project_url`, `issues_url` and `new_issue_url` will '\
......@@ -54,4 +69,228 @@ class JiraService < IssueTrackerService
def to_param
'jira'
end
def fields
super.push(
{ type: 'text', name: 'api_url', placeholder: 'https://jira.example.com/rest/api/2' },
{ type: 'text', name: 'username', placeholder: '' },
{ type: 'password', name: 'password', placeholder: '' },
{ type: 'text', name: 'jira_issue_transition_id', placeholder: '2' }
)
end
def execute(push, issue = nil)
if issue.nil?
# No specific issue, that means
# we just want to test settings
test_settings
else
close_issue(push, issue)
end
end
def create_cross_reference_note(mentioned, noteable, author)
issue_name = mentioned.id
project = self.project
noteable_name = noteable.class.name.underscore.downcase
noteable_id = if noteable.is_a?(Commit)
noteable.id
else
noteable.iid
end
entity_url = build_entity_url(noteable_name.to_sym, noteable_id)
data = {
user: {
name: author.name,
url: resource_url(user_path(author)),
},
project: {
name: project.path_with_namespace,
url: resource_url(namespace_project_path(project.namespace, project))
},
entity: {
name: noteable_name.humanize.downcase,
url: entity_url
}
}
add_comment(data, issue_name)
end
def test_settings
result = JiraService.get(
jira_api_test_url,
headers: {
'Content-Type' => 'application/json',
'Authorization' => "Basic #{auth}"
}
)
case result.code
when 201, 200
Rails.logger.info("#{self.class.name} SUCCESS #{result.code}: Successfully connected to #{api_url}.")
true
else
Rails.logger.info("#{self.class.name} ERROR #{result.code}: #{result.parsed_response}")
false
end
rescue Errno::ECONNREFUSED => e
Rails.logger.info "#{self.class.name} ERROR: #{e.message}. API URL: #{api_url}."
false
end
private
def build_api_url_from_project_url
server = URI(project_url)
default_ports = [["http",80],["https",443]].include?([server.scheme,server.port])
server_url = "#{server.scheme}://#{server.host}"
server_url.concat(":#{server.port}") unless default_ports
"#{server_url}/rest/api/#{DEFAULT_API_VERSION}"
rescue
"" # looks like project URL was not valid
end
def set_api_url
self.api_url = build_api_url_from_project_url if self.api_url.blank?
end
def set_jira_issue_transition_id
self.jira_issue_transition_id ||= "2"
end
def close_issue(entity, issue)
commit_id = if entity.is_a?(Commit)
entity.id
elsif entity.is_a?(MergeRequest)
entity.last_commit.id
end
commit_url = build_entity_url(:commit, commit_id)
# Depending on the JIRA project's workflow, a comment during transition
# may or may not be allowed. Split the operation in to two calls so the
# comment always works.
transition_issue(issue)
add_issue_solved_comment(issue, commit_id, commit_url)
end
def transition_issue(issue)
message = {
transition: {
id: jira_issue_transition_id
}
}
send_message(close_issue_url(issue.iid), message.to_json)
end
def add_issue_solved_comment(issue, commit_id, commit_url)
comment = {
body: "Issue solved with [#{commit_id}|#{commit_url}]."
}
send_message(comment_url(issue.iid), comment.to_json)
end
def add_comment(data, issue_name)
url = comment_url(issue_name)
user_name = data[:user][:name]
user_url = data[:user][:url]
entity_name = data[:entity][:name]
entity_url = data[:entity][:url]
project_name = data[:project][:name]
message = {
body: "[#{user_name}|#{user_url}] mentioned this issue in [a #{entity_name} of #{project_name}|#{entity_url}]."
}
unless existing_comment?(issue_name, message[:body])
send_message(url, message.to_json)
end
end
def auth
require 'base64'
Base64.urlsafe_encode64("#{self.username}:#{self.password}")
end
def send_message(url, message)
result = JiraService.post(
url,
body: message,
headers: {
'Content-Type' => 'application/json',
'Authorization' => "Basic #{auth}"
}
)
message = case result.code
when 201, 200, 204
"#{self.class.name} SUCCESS #{result.code}: Successfully posted to #{url}."
when 401
"#{self.class.name} ERROR 401: Unauthorized. Check the #{self.username} credentials and JIRA access permissions and try again."
else
"#{self.class.name} ERROR #{result.code}: #{result.parsed_response}"
end
Rails.logger.info(message)
message
rescue URI::InvalidURIError, Errno::ECONNREFUSED => e
Rails.logger.info "#{self.class.name} ERROR: #{e.message}. Hostname: #{url}."
end
def existing_comment?(issue_name, new_comment)
result = JiraService.get(
comment_url(issue_name),
headers: {
'Content-Type' => 'application/json',
'Authorization' => "Basic #{auth}"
}
)
case result.code
when 201, 200
existing_comments = JSON.parse(result.body)['comments']
if existing_comments.present?
return existing_comments.map { |comment| comment['body'].include?(new_comment) }.any?
end
end
false
rescue JSON::ParserError
false
end
def resource_url(resource)
"#{Settings.gitlab['url'].chomp("/")}#{resource}"
end
def build_entity_url(entity_name, entity_id)
resource_url(
polymorphic_url(
[
self.project.namespace.becomes(Namespace),
self.project,
entity_name
],
id: entity_id,
routing_type: :path
)
)
end
def close_issue_url(issue_name)
"#{self.api_url}/issue/#{issue_name}/transitions"
end
def comment_url(issue_name)
"#{self.api_url}/issue/#{issue_name}/comment"
end
def jira_api_test_url
"#{self.api_url}/myself"
end
end
......@@ -27,12 +27,10 @@ class TeamcityService < CiService
validates :build_type, presence: true, if: :activated?
validates :username,
presence: true,
if: ->(service) { service.password? },
if: :activated?
if: ->(service) { service.activated? && service.password }
validates :password,
presence: true,
if: ->(service) { service.username? },
if: :activated?
if: ->(service) { service.activated? && service.username }
attr_accessor :response
......@@ -147,6 +145,6 @@ class TeamcityService < CiService
'</build>',
headers: { 'Content-type' => 'application/xml' },
basic_auth: auth
)
)
end
end
......@@ -26,6 +26,7 @@
# bio :string(255)
# failed_attempts :integer default(0)
# locked_at :datetime
# unlock_token :string(255)
# username :string(255)
# can_create_group :boolean default(TRUE), not null
# can_create_team :boolean default(TRUE), not null
......@@ -220,9 +221,9 @@ class User < ActiveRecord::Base
def find_for_database_authentication(warden_conditions)
conditions = warden_conditions.dup
if login = conditions.delete(:login)
where(conditions).where(["lower(username) = :value OR lower(email) = :value", { value: login.downcase }]).first
where(conditions).find_by("lower(username) = :value OR lower(email) = :value", value: login.downcase)
else
where(conditions).first
find_by(conditions)
end
end
......@@ -285,7 +286,7 @@ class User < ActiveRecord::Base
end
def by_username_or_id(name_or_id)
where('users.username = ? OR users.id = ?', name_or_id.to_s, name_or_id.to_i).first
find_by('users.username = ? OR users.id = ?', name_or_id.to_s, name_or_id.to_i)
end
def build_user(attrs = {})
......
......@@ -16,9 +16,23 @@ class CreateCommitBuildsService
return false
end
tag = Gitlab::Git.tag_ref?(origin_ref)
commit = project.ensure_ci_commit(sha)
commit = project.ci_commit(sha)
unless commit
commit = project.ci_commits.new(sha: sha)
# Skip creating ci_commit when no gitlab-ci.yml is found
unless commit.ci_yaml_file
return false
end
# Create a new ci_commit
commit.save!
end
# Skip creating builds for commits that have [ci skip]
unless commit.skip_ci?
# Create builds for commit
tag = Gitlab::Git.tag_ref?(origin_ref)
commit.update_committed!
commit.create_builds(ref, tag, user)
end
......
module Issues
class CloseService < Issues::BaseService
def execute(issue, commit = nil)
if project.jira_tracker? && project.jira_service.active
project.jira_service.execute(commit, issue)
return issue
end
if project.default_issues_tracker? && issue.close
event_service.close_issue(issue, current_user)
create_note(issue, commit)
......
......@@ -112,7 +112,7 @@ module MergeRequests
merge_requests_for_source_branch.each do |merge_request|
SystemNoteService.change_branch_presence(
merge_request, merge_request.project, @current_user,
merge_request, merge_request.project, @current_user,
:source, @branch_name, presence)
end
end
......
......@@ -241,9 +241,14 @@ class SystemNoteService
note_options.merge!(noteable: noteable)
end
create_note(note_options)
if noteable.is_a?(ExternalIssue)
noteable.project.issues_tracker.create_cross_reference_note(noteable, mentioner, author)
else
create_note(note_options)
end
end
def self.cross_reference?(note_text)
note_text.start_with?(cross_reference_note_prefix)
end
......@@ -259,7 +264,7 @@ class SystemNoteService
#
# Returns Boolean
def self.cross_reference_disallowed?(noteable, mentioner)
return true if noteable.is_a?(ExternalIssue)
return true if noteable.is_a?(ExternalIssue) && !noteable.project.jira_tracker_active?
return false unless mentioner.is_a?(MergeRequest)
return false unless noteable.is_a?(Commit)
......
......@@ -79,6 +79,10 @@
GitLab API
%span.pull-right
= API::API::version
%p
Git
%span.pull-right
= Gitlab::Git.version
%p
Ruby
%span.pull-right
......
- page_title "Identities", @user.name, "Users"
= render 'admin/users/head'
= link_to 'New Identity', new_admin_user_identity_path, class: 'pull-right btn btn-new'
- if @identities.present?
.table-holder
%table.table
......
- page_title "New Identity"
%h3.page-title New identity
%hr
= render 'form'
......@@ -3,7 +3,7 @@
To register a new runner you should enter the following registration token.
With this token the runner will request a unique runner token and use that for future communication.
Registration token is
%code{ id: 'runners-token' } #{current_application_settings.ensure_runners_registration_token}
%code{ id: 'runners-token' } #{current_application_settings.runners_registration_token}
.bs-callout.clearfix
.pull-left
......
......@@ -41,5 +41,3 @@
%i.fa.fa-remove.incorrect-syntax
%b Error:
= @error
:plain
$(".results").html("#{escape_javascript(render "create")}")
\ No newline at end of file
%h2 Check your .gitlab-ci.yml
%hr
= form_tag ci_lint_path, method: :post, remote: true do
.control-group
= label_tag :content, "Content of .gitlab-ci.yml", class: 'control-label'
.controls
= text_area_tag :content, nil, class: 'form-control span1', rows: 7, require: true
.row
= form_tag ci_lint_path, method: :post do
.form-group
= label_tag :content, 'Content of .gitlab-ci.yml', class: 'control-label text-nowrap'
.col-sm-12
= text_area_tag :content, nil, class: 'form-control span1', rows: 7, require: true
.col-sm-12
.pull-left.prepend-top-10
= submit_tag 'Validate', class: 'btn btn-success submit-yml'
.control-group.clearfix
.controls.pull-left.prepend-top-10
= submit_tag "Validate", class: 'btn btn-success submit-yml'
%p.text-center.loading
%i.fa.fa-refresh.fa-spin
.results.prepend-top-20
:javascript
$(".loading").hide();
$('form').bind('ajax:beforeSend', function() {
$(".loading").show();
});
$('form').bind('ajax:complete', function() {
$(".loading").hide();
});
.row.prepend-top-20
.col-sm-12
.results
= render partial: 'create' if defined?(@status)
= content_for :flash_message do
= render 'shared/project_limit'
.top-area
%ul.left-top-menu
= nav_link(page: [dashboard_projects_path, root_path]) do
= link_to dashboard_projects_path, title: 'Home', class: 'shortcuts-activity', data: {placement: 'right'} do
Your Projects
= nav_link(page: starred_dashboard_projects_path) do
= link_to starred_dashboard_projects_path, title: 'Starred Projects', data: {placement: 'right'} do
Starred Projects
= nav_link(page: [explore_root_path, trending_explore_projects_path, starred_explore_projects_path, explore_projects_path], html_options: { class: 'hidden-xs' }) do
= link_to explore_root_path, title: 'Explore', data: {placement: 'right'} do
Explore Projects
%ul.center-top-menu
= nav_link(page: [dashboard_projects_path, root_path]) do
= link_to dashboard_projects_path, title: 'Home', class: 'shortcuts-activity', data: {placement: 'right'} do
Your Projects
= nav_link(page: starred_dashboard_projects_path) do
= link_to starred_dashboard_projects_path, title: 'Starred Projects', data: {placement: 'right'} do
Starred Projects
= nav_link(page: [explore_root_path, trending_explore_projects_path, starred_explore_projects_path, explore_projects_path], html_options: { class: 'hidden-xs' }) do
= link_to explore_root_path, title: 'Explore', data: {placement: 'right'} do
Explore Projects
.projects-search-form
= search_field_tag :filter_projects, nil, placeholder: 'Filter by name...', class: 'projects-list-filter form-control hidden-xs', spellcheck: false
- if current_user.can_create_project?
= link_to new_project_path, class: 'btn btn-green' do
%i.fa.fa-plus
New Project
- page_title @milestone.title, "Milestones"
- header_title "Milestones", dashboard_milestones_path
.issuable-details
.page-title
.issue-box{ class: "issue-box-#{@milestone.closed? ? 'closed' : 'open'}" }
- if @milestone.closed?
Closed
- else
Open
.detail-page-header
.status-box{ class: "status-box-#{@milestone.closed? ? 'closed' : 'open'}" }
- if @milestone.closed?
Closed
- else
Open
%span.identifier
Milestone #{@milestone.title}
.gray-content-block.middle-block
%h2.issue-title
= markdown escape_once(@milestone.title), pipeline: :single_line
.detail-page-description.gray-content-block.second-block
%h2.title
= markdown escape_once(@milestone.title), pipeline: :single_line
- if @milestone.complete? && @milestone.active?
.alert.alert-success.prepend-top-default
......
.projects-list-holder
.projects-search-form
.input-group
= search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'projects-list-filter form-control', spellcheck: false
- if current_user.can_create_project?
%span.input-group-btn
= link_to new_project_path, class: 'btn btn-green' do
%i.fa.fa-plus
New Project
= render 'shared/projects/list', projects: @projects, ci: true
<p>Hello <%= @resource.email %>!</p>
<p>Your account has been locked due to an excessive amount of unsuccessful sign in attempts.</p>
<p>Click the link below to unlock your account:</p>
<p><%= link_to 'Unlock your account', unlock_url(@resource, unlock_token: @token) %></p>
%p
Hello #{@resource.name}!
%p
Your GitLab account has been locked due to an excessive amount of unsuccessful
sign in attempts. Your account will automatically unlock in
= time_ago_in_words(Devise.unlock_in.from_now)
or you may click the link below to unlock now.
%p= link_to 'Unlock your account', unlock_url(@resource, unlock_token: @token)
<h2>Resend unlock instructions</h2>
<%= form_for(resource, as: resource_name, url: unlock_path(resource_name), html: { method: :post }) do |f| %>
<%= devise_error_messages! %>
<div><%= f.label :email %><br />
<%= f.email_field :email %></div>
<div><%= f.submit "Resend unlock instructions" %></div>
<% end %>
<%= render partial: "devise/shared/links" %>
.login-box
.login-heading
%h3 Resend unlock email
.login-body
= form_for(resource, as: resource_name, url: unlock_path(resource_name), html: { method: :post }) do |f|
.devise-errors
= devise_error_messages!
.clearfix.append-bottom-20
= f.email_field :email, class: 'form-control', placeholder: 'Email', autofocus: 'autofocus', autocapitalize: 'off', autocorrect: 'off'
.clearfix
= f.submit 'Resend unlock instructions', class: 'btn btn-success'
.clearfix.prepend-top-20
= render 'devise/shared/sign_in_link'
.panel.panel-default.projects-list-holder
.panel-heading.clearfix
.projects-list-holder
.projects-search-form
.input-group
= search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'projects-list-filter form-control', spellcheck: false
- if can? current_user, :create_projects, @group
......
- page_title @milestone.title, "Milestones"
= render "header_title"
.issuable-details
.page-title
.issue-box{ class: "issue-box-#{@milestone.closed? ? 'closed' : 'open'}" }
- if @milestone.closed?
Closed
- else
Open
.detail-page-header
.status-box{ class: "status-box-#{@milestone.closed? ? 'closed' : 'open'}" }
- if @milestone.closed?
Closed
- else
Open
%span.identifier
Milestone #{@milestone.title}
.pull-right
- if can?(current_user, :admin_milestones, @group)
- if @milestone.active?
= link_to 'Close Milestone', group_milestone_path(@group, @milestone.safe_title, title: @milestone.title, milestone: {state_event: :close }), method: :put, class: "btn btn-grouped btn-close"
- else
= link_to 'Reopen Milestone', group_milestone_path(@group, @milestone.safe_title, title: @milestone.title, milestone: {state_event: :activate }), method: :put, class: "btn btn-grouped btn-reopen"
.pull-right
- if can?(current_user, :admin_milestones, @group)
- if @milestone.active?
= link_to 'Close Milestone', group_milestone_path(@group, @milestone.safe_title, title: @milestone.title, milestone: {state_event: :close }), method: :put, class: "btn btn-grouped btn-close"
- else
= link_to 'Reopen Milestone', group_milestone_path(@group, @milestone.safe_title, title: @milestone.title, milestone: {state_event: :activate }), method: :put, class: "btn btn-grouped btn-reopen"
.gray-content-block.middle-block
%h2.issue-title
= markdown escape_once(@milestone.title), pipeline: :single_line
.detail-page-description.gray-content-block.second-block
%h2.title
= markdown escape_once(@milestone.title), pipeline: :single_line
- if @milestone.complete? && @milestone.active?
.alert.alert-success.prepend-top-default
......
......@@ -5,37 +5,47 @@
- if current_user
= auto_discovery_link_tag(:atom, group_url(@group, format: :atom, private_token: current_user.private_token), title: "#{@group.name} activity")
.dashboard
.header-with-avatar.clearfix
= image_tag group_icon(@group), class: "avatar group-avatar s90"
%h3
= @group.name
.username
@#{@group.path}
- if @group.description.present?
.description
= markdown(@group.description, pipeline: :description)
%hr
= render 'shared/show_aside'
- if can?(current_user, :read_group, @group)
.row
%section.activities.col-md-7
.hidden-xs
- if current_user
= render "events/event_last_push", event: @last_push
.pull-right
= link_to group_path(@group, { format: :atom, private_token: current_user.private_token }), title: "Feed", class: 'btn rss-btn' do
%i.fa.fa-rss
= render 'shared/event_filter'
%hr
.content_list
= spinner
%aside.side.col-md-5
= render "projects", projects: @projects
- else
%p
This group does not have public projects
.cover-block
.avatar-holder
= link_to group_icon(@group), target: '_blank' do
= image_tag group_icon(@group), class: "avatar group-avatar s90"
.cover-title
= @group.name
.cover-desc.username
@#{@group.path}
- if @group.description.present?
.cover-desc.description
= markdown(@group.description, pipeline: :description)
- if can?(current_user, :read_group, @group)
%ul.center-top-menu.no-top
%li.active
= link_to "#activity", 'data-toggle' => 'tab' do
Activity
- if @projects.present?
%li
= link_to "#projects", 'data-toggle' => 'tab' do
Projects
.tab-content
.tab-pane.active#activity
.gray-content-block.activity-filter-block
- if current_user
= render "events/event_last_push", event: @last_push
.pull-right
= link_to group_path(@group, { format: :atom, private_token: current_user.private_token }), title: "Feed", class: 'btn rss-btn' do
%i.fa.fa-rss
= render 'shared/event_filter'
.content_list
= spinner
.tab-pane#projects
= render "projects", projects: @projects
- else
%p
This group does not have public projects
%div
"#{link_to @note.author_name, user_url(@note.author)} wrote:"
%div
= markdown(@note.note, pipeline: :email)
......@@ -7,6 +7,10 @@
%strong.monospace= link_to @build.commit.short_sha, ci_status_path(@build.commit)
from
= link_to @build.ref, namespace_project_commits_path(@project.namespace, @project, @build.ref)
- merge_request = @build.merge_request
- if merge_request
via
= link_to "merge request ##{merge_request.iid}", merge_request_path(merge_request)
#up-build-trace
- if @commit.matrix_for_ref?(@build.ref)
......
......@@ -20,8 +20,8 @@
%p
%span.light Commit
= link_to @commit.id, namespace_project_commit_path(@project.namespace, @project, @commit), class: "monospace", data: { clipboard_text: @commit.id }
= clipboard_button
= link_to @commit.id, namespace_project_commit_path(@project.namespace, @project, @commit), class: "monospace"
= clipboard_button(clipboard_text: @commit.id)
.commit-info-row
%span.light Authored by
%strong
......@@ -40,7 +40,7 @@
- @commit.parents.each do |parent|
= link_to parent.short_id, namespace_project_commit_path(@project.namespace, @project, parent), class: "monospace"
- if @ci_commit && @ci_commit.show_build_status?
- if @ci_commit
.pull-right
= link_to ci_status_path(@ci_commit), class: "ci-status ci-#{@ci_commit.status}" do
= ci_status_icon(@ci_commit)
......
......@@ -19,11 +19,11 @@
- if defined?(commit_sha) && commit_sha
%td
= link_to commit_status.short_sha, namespace_project_commit_path(@project.namespace, @project, commit_status.sha), class: "monospace"
= link_to commit_status.short_sha, namespace_project_commit_path(commit_status.project.namespace, commit_status.project, commit_status.sha), class: "monospace"
%td
- if commit_status.ref
= link_to commit_status.ref, namespace_project_commits_path(@project.namespace, @project, commit_status.ref)
= link_to commit_status.ref, namespace_project_commits_path(commit_status.project.namespace, commit_status.project, commit_status.ref)
- else
.light none
......@@ -66,7 +66,7 @@
%td
.pull-right
- if current_user && can?(current_user, :download_build_artifacts, @project) && commit_status.download_url
- if current_user && can?(current_user, :download_build_artifacts, commit_status.project) && commit_status.download_url
= link_to commit_status.download_url, title: 'Download artifacts' do
%i.fa.fa-download
- if current_user && can?(current_user, :manage_builds, commit_status.project)
......
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.
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