Commit 2bfd4f44 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch 'master' of dev.gitlab.org:gitlab/gitlabhq

Conflicts:
	VERSION
	config/gitlab.yml.example
	config/initializers/1_settings.rb
	lib/api/entities.rb
	lib/api/groups.rb
parents 42f5c5bd ae1be437
user: git user: git
group: git group: git
services:
- postgres
before_precompile: ./bin/pkgr_before_precompile.sh before_precompile: ./bin/pkgr_before_precompile.sh
targets: targets:
debian-7: &wheezy debian-7: &wheezy
build_dependencies: build_dependencies:
- libkrb5-dev
- libicu-dev - libicu-dev
- cmake - cmake
- pkg-config - pkg-config
...@@ -14,6 +17,7 @@ targets: ...@@ -14,6 +17,7 @@ targets:
ubuntu-12.04: *wheezy ubuntu-12.04: *wheezy
ubuntu-14.04: ubuntu-14.04:
build_dependencies: build_dependencies:
- libkrb5-dev
- libicu-dev - libicu-dev
- cmake - cmake
- pkg-config - pkg-config
...@@ -23,6 +27,7 @@ targets: ...@@ -23,6 +27,7 @@ targets:
- git - git
centos-6: centos-6:
build_dependencies: build_dependencies:
- krb5-devel
- libicu-devel - libicu-devel
- cmake - cmake
- pkgconfig - pkgconfig
......
Note: The upcoming release contains empty lines to reduce the number of merge conflicts, scroll down to see past releases. Note: The upcoming release contains empty lines to reduce the number of merge conflicts, scroll down to see past releases.
v 7.8.0
- Replace highlight.js with rouge-fork rugments (Stefan Tatschner)
- Make project search case insensitive (Hannes Rosenögger)
-
- Expose description in groups API
-
-
- Add diff syntax highlighting in email-on-push service notifications (Hannes Rosenögger)
-
-
-
- Allow more variations for commit messages closing issues (Julien Bianchi and Hannes Rosenögger)
-
-
- Show tags in commit view (Hannes Rosenögger)
-
-
-
-
-
-
-
-
- Fix commits pagination
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Add action property to merge request hook (Julien Bianchi)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
v 7.7.0 v 7.7.0
- Import from GitHub.com feature - Import from GitHub.com feature
- Add Jetbrains Teamcity CI service (Jason Lippert) - Add Jetbrains Teamcity CI service (Jason Lippert)
...@@ -24,6 +82,10 @@ v 7.7.0 ...@@ -24,6 +82,10 @@ v 7.7.0
- Trigger GitLab CI when push tags - Trigger GitLab CI when push tags
- When accept merge request - do merge using sidaekiq job - When accept merge request - do merge using sidaekiq job
- Enable web signups by default - Enable web signups by default
- Fixes for diff comments: drag-n-drop images, selecting images
- Fixes for edit comments: drag-n-drop images, preview mode, selecting images, save & update
- Remove password strength indicator
v 7.6.0 v 7.6.0
......
...@@ -47,7 +47,7 @@ gem 'gitlab_omniauth-ldap', '1.2.0', require: "omniauth-ldap" ...@@ -47,7 +47,7 @@ gem 'gitlab_omniauth-ldap', '1.2.0', require: "omniauth-ldap"
gem 'net-ldap' gem 'net-ldap'
# Git Wiki # Git Wiki
gem 'gollum-lib', '~> 3.0.0' gem 'gollum-lib', '~> 4.0.0'
# Language detection # Language detection
gem "gitlab-linguist", "~> 3.0.0", require: "linguist" gem "gitlab-linguist", "~> 3.0.0", require: "linguist"
...@@ -267,3 +267,4 @@ end ...@@ -267,3 +267,4 @@ end
gem "newrelic_rpm" gem "newrelic_rpm"
gem 'octokit', '3.7.0' gem 'octokit', '3.7.0'
gem "rugments"
...@@ -166,13 +166,14 @@ GEM ...@@ -166,13 +166,14 @@ GEM
rugged (~> 0.19) rugged (~> 0.19)
gherkin-ruby (0.3.1) gherkin-ruby (0.3.1)
racc racc
github-markup (1.1.0) github-markup (1.3.1)
posix-spawn (~> 0.3.8)
gitlab-flowdock-git-hook (0.4.2.2) gitlab-flowdock-git-hook (0.4.2.2)
gitlab-grit (>= 2.4.1) gitlab-grit (>= 2.4.1)
multi_json multi_json
gitlab-grack (2.0.0.pre) gitlab-grack (2.0.0.pre)
rack (~> 1.5.1) rack (~> 1.5.1)
gitlab-grit (2.6.12) gitlab-grit (2.7.2)
charlock_holmes (~> 0.6) charlock_holmes (~> 0.6)
diff-lcs (~> 1.1) diff-lcs (~> 1.1)
mime-types (~> 1.15) mime-types (~> 1.15)
...@@ -194,11 +195,13 @@ GEM ...@@ -194,11 +195,13 @@ GEM
omniauth (~> 1.0) omniauth (~> 1.0)
pyu-ruby-sasl (~> 0.0.3.1) pyu-ruby-sasl (~> 0.0.3.1)
rubyntlm (~> 0.3) rubyntlm (~> 0.3)
gollum-lib (3.0.0) gollum-grit_adapter (0.1.0)
github-markup (~> 1.1.0) gitlab-grit (~> 2.7.1)
gitlab-grit (~> 2.6.5) gollum-lib (4.0.0)
nokogiri (~> 1.6.1) github-markup (~> 1.3.1)
rouge (~> 1.3.3) gollum-grit_adapter (~> 0.1.0)
nokogiri (~> 1.6.4)
rouge (~> 1.7.4)
sanitize (~> 2.1.0) sanitize (~> 2.1.0)
stringex (~> 2.5.1) stringex (~> 2.5.1)
gon (5.0.1) gon (5.0.1)
...@@ -297,7 +300,7 @@ GEM ...@@ -297,7 +300,7 @@ GEM
treetop (~> 1.4.8) treetop (~> 1.4.8)
method_source (0.8.2) method_source (0.8.2)
mime-types (1.25.1) mime-types (1.25.1)
mini_portile (0.6.0) mini_portile (0.6.1)
minitest (5.3.5) minitest (5.3.5)
mousetrap-rails (1.4.6) mousetrap-rails (1.4.6)
multi_json (1.10.1) multi_json (1.10.1)
...@@ -309,8 +312,8 @@ GEM ...@@ -309,8 +312,8 @@ GEM
net-ssh (>= 2.6.5) net-ssh (>= 2.6.5)
net-ssh (2.8.0) net-ssh (2.8.0)
newrelic_rpm (3.9.4.245) newrelic_rpm (3.9.4.245)
nokogiri (1.6.2.1) nokogiri (1.6.5)
mini_portile (= 0.6.0) mini_portile (~> 0.6.0)
nprogress-rails (0.1.2.3) nprogress-rails (0.1.2.3)
oauth (0.4.7) oauth (0.4.7)
oauth2 (0.8.1) oauth2 (0.8.1)
...@@ -446,7 +449,7 @@ GEM ...@@ -446,7 +449,7 @@ GEM
rest-client (1.6.7) rest-client (1.6.7)
mime-types (>= 1.16) mime-types (>= 1.16)
rinku (1.7.3) rinku (1.7.3)
rouge (1.3.3) rouge (1.7.4)
rspec (2.14.1) rspec (2.14.1)
rspec-core (~> 2.14.0) rspec-core (~> 2.14.0)
rspec-expectations (~> 2.14.0) rspec-expectations (~> 2.14.0)
...@@ -466,6 +469,7 @@ GEM ...@@ -466,6 +469,7 @@ GEM
rubyntlm (0.4.0) rubyntlm (0.4.0)
rubypants (0.2.0) rubypants (0.2.0)
rugged (0.21.2) rugged (0.21.2)
rugments (1.0.0.beta3)
safe_yaml (0.9.7) safe_yaml (0.9.7)
sanitize (2.1.0) sanitize (2.1.0)
nokogiri (>= 1.4.4) nokogiri (>= 1.4.4)
...@@ -541,7 +545,7 @@ GEM ...@@ -541,7 +545,7 @@ GEM
sprockets (~> 2.8) sprockets (~> 2.8)
stamp (0.5.0) stamp (0.5.0)
state_machine (1.2.0) state_machine (1.2.0)
stringex (2.5.1) stringex (2.5.2)
temple (0.6.7) temple (0.6.7)
term-ansicolor (1.2.2) term-ansicolor (1.2.2)
tins (~> 0.8) tins (~> 0.8)
...@@ -656,7 +660,7 @@ DEPENDENCIES ...@@ -656,7 +660,7 @@ DEPENDENCIES
gitlab_git (= 7.0.0.rc14) gitlab_git (= 7.0.0.rc14)
gitlab_meta (= 7.0) gitlab_meta (= 7.0)
gitlab_omniauth-ldap (= 1.2.0) gitlab_omniauth-ldap (= 1.2.0)
gollum-lib (~> 3.0.0) gollum-lib (~> 4.0.0)
gon (~> 5.0.0) gon (~> 5.0.0)
grape (~> 0.6.1) grape (~> 0.6.1)
grape-entity (~> 0.4.2) grape-entity (~> 0.4.2)
...@@ -709,6 +713,7 @@ DEPENDENCIES ...@@ -709,6 +713,7 @@ DEPENDENCIES
redis-rails redis-rails
request_store request_store
rspec-rails rspec-rails
rugments
sanitize (~> 2.0) sanitize (~> 2.0)
sass-rails (~> 4.0.2) sass-rails (~> 4.0.2)
sdoc sdoc
......
...@@ -73,7 +73,7 @@ On [about.gitlab.com](https://about.gitlab.com/) you can find more information a ...@@ -73,7 +73,7 @@ On [about.gitlab.com](https://about.gitlab.com/) you can find more information a
## Requirements ## Requirements
- Ubuntu/Debian/CentOS/RHEL** - Ubuntu/Debian/CentOS/RHEL**
- ruby 2.0+ - Ruby (MRI) 2.0 or 2.1
- git 1.7.10+ - git 1.7.10+
- redis 2.0+ - redis 2.0+
- MySQL or PostgreSQL - MySQL or PostgreSQL
......
7.7.0.pre-ee 7.8.0.pre-ee
...@@ -18,14 +18,12 @@ ...@@ -18,14 +18,12 @@
#= require jquery.turbolinks #= require jquery.turbolinks
#= require turbolinks #= require turbolinks
#= require bootstrap #= require bootstrap
#= require password_strength
#= require select2 #= require select2
#= require raphael #= require raphael
#= require g.raphael-min #= require g.raphael-min
#= require g.bar-min #= require g.bar-min
#= require chart-lib.min #= require chart-lib.min
#= require branch-graph #= require branch-graph
#= require highlight.pack
#= require ace/ace #= require ace/ace
#= require ace/ext-searchbox #= require ace/ext-searchbox
#= require d3 #= require d3
...@@ -109,9 +107,19 @@ window.unbindEvents = -> ...@@ -109,9 +107,19 @@ window.unbindEvents = ->
$(document).unbind('scroll') $(document).unbind('scroll')
$(document).off('scroll') $(document).off('scroll')
window.shiftWindow = ->
scrollBy 0, -50
document.addEventListener("page:fetch", unbindEvents) document.addEventListener("page:fetch", unbindEvents)
# Scroll the window to avoid the topnav bar
# https://github.com/twitter/bootstrap/issues/1768
if location.hash
setTimeout shiftWindow, 1
window.addEventListener "hashchange", shiftWindow
$ -> $ ->
# Click a .one_click_select field, select the contents # Click a .one_click_select field, select the contents
$(".one_click_select").on 'click', -> $(@).select() $(".one_click_select").on 'click', -> $(@).select()
......
...@@ -4,7 +4,6 @@ $ -> ...@@ -4,7 +4,6 @@ $ ->
class Dispatcher class Dispatcher
constructor: () -> constructor: () ->
@initSearch() @initSearch()
@initHighlight()
@initPageScripts() @initPageScripts()
initPageScripts: -> initPageScripts: ->
...@@ -33,17 +32,20 @@ class Dispatcher ...@@ -33,17 +32,20 @@ class Dispatcher
GitLab.GfmAutoComplete.setup() GitLab.GfmAutoComplete.setup()
shortcut_handler = new ShortcutsNavigation() shortcut_handler = new ShortcutsNavigation()
new ZenMode() new ZenMode()
new DropzoneInput($('.issue-form'))
when 'projects:merge_requests:new', 'projects:merge_requests:edit' when 'projects:merge_requests:new', 'projects:merge_requests:edit'
GitLab.GfmAutoComplete.setup() GitLab.GfmAutoComplete.setup()
new Diff() new Diff()
shortcut_handler = new ShortcutsNavigation() shortcut_handler = new ShortcutsNavigation()
new ZenMode() new ZenMode()
new DropzoneInput($('.merge-request-form'))
when 'projects:merge_requests:show' when 'projects:merge_requests:show'
new Diff() new Diff()
shortcut_handler = new ShortcutsIssueable() shortcut_handler = new ShortcutsIssueable()
new ZenMode() new ZenMode()
when "projects:merge_requests:diffs" when "projects:merge_requests:diffs"
new Diff() new Diff()
new ZenMode()
when 'projects:merge_requests:index' when 'projects:merge_requests:index'
shortcut_handler = new ShortcutsNavigation() shortcut_handler = new ShortcutsNavigation()
when 'dashboard:show' when 'dashboard:show'
...@@ -112,6 +114,7 @@ class Dispatcher ...@@ -112,6 +114,7 @@ class Dispatcher
new Wikis() new Wikis()
shortcut_handler = new ShortcutsNavigation() shortcut_handler = new ShortcutsNavigation()
new ZenMode() new ZenMode()
new DropzoneInput($('.wiki-form'))
when 'snippets', 'labels', 'graphs' when 'snippets', 'labels', 'graphs'
shortcut_handler = new ShortcutsNavigation() shortcut_handler = new ShortcutsNavigation()
when 'team_members', 'deploy_keys', 'hooks', 'services', 'protected_branches' when 'team_members', 'deploy_keys', 'hooks', 'services', 'protected_branches'
...@@ -130,10 +133,3 @@ class Dispatcher ...@@ -130,10 +133,3 @@ class Dispatcher
project_ref = opts.data('autocomplete-project-ref') project_ref = opts.data('autocomplete-project-ref')
new SearchAutocomplete(path, project_id, project_ref) new SearchAutocomplete(path, project_id, project_ref)
initHighlight: ->
$('.highlight pre code').each (i, e) ->
$(e).html($.map($(e).html().split("\n"), (line, i) ->
"<span class='line' id='LC" + (i + 1) + "'>" + line + "</span>"
).join("\n"))
hljs.highlightBlock(e)
class @DropzoneInput
constructor: (form) ->
Dropzone.autoDiscover = false
alertClass = "alert alert-danger alert-dismissable div-dropzone-alert"
alertAttr = "class=\"close\" data-dismiss=\"alert\"" + "aria-hidden=\"true\""
divHover = "<div class=\"div-dropzone-hover\"></div>"
divSpinner = "<div class=\"div-dropzone-spinner\"></div>"
divAlert = "<div class=\"" + alertClass + "\"></div>"
iconPicture = "<i class=\"fa fa-picture-o div-dropzone-icon\"></i>"
iconSpinner = "<i class=\"fa fa-spinner fa-spin div-dropzone-icon\"></i>"
btnAlert = "<button type=\"button\"" + alertAttr + ">&times;</button>"
project_image_path_upload = window.project_image_path_upload or null
form_textarea = $(form).find("textarea.markdown-area")
form_textarea.wrap "<div class=\"div-dropzone\"></div>"
form_dropzone = $(form).find('.div-dropzone')
form_dropzone.parent().addClass "div-dropzone-wrapper"
form_dropzone.append divHover
$(".div-dropzone-hover").append iconPicture
form_dropzone.append divSpinner
$(".div-dropzone-spinner").append iconSpinner
$(".div-dropzone-spinner").css
"opacity": 0
"display": "none"
# Preview button
$(document).off "click", ".js-md-preview-button"
$(document).on "click", ".js-md-preview-button", (e) ->
###
Shows the Markdown preview.
Lets the server render GFM into Html and displays it.
###
e.preventDefault()
form = $(this).closest("form")
# toggle tabs
form.find(".js-md-write-button").parent().removeClass "active"
form.find(".js-md-preview-button").parent().addClass "active"
# toggle content
form.find(".md-write-holder").hide()
form.find(".md-preview-holder").show()
preview = form.find(".js-md-preview")
mdText = form.find(".markdown-area").val()
if mdText.trim().length is 0
preview.text "Nothing to preview."
else
preview.text "Loading..."
$.get($(this).data("url"),
md_text: mdText
).success (previewData) ->
preview.html previewData
# Write button
$(document).off "click", ".js-md-write-button"
$(document).on "click", ".js-md-write-button", (e) ->
###
Shows the Markdown textarea.
###
e.preventDefault()
form = $(this).closest("form")
# toggle tabs
form.find(".js-md-write-button").parent().addClass "active"
form.find(".js-md-preview-button").parent().removeClass "active"
# toggle content
form.find(".md-write-holder").show()
form.find(".md-preview-holder").hide()
dropzone = form_dropzone.dropzone(
url: project_image_path_upload
dictDefaultMessage: ""
clickable: true
paramName: "markdown_img"
maxFilesize: 10
uploadMultiple: false
acceptedFiles: "image/jpg,image/jpeg,image/gif,image/png"
headers:
"X-CSRF-Token": $("meta[name=\"csrf-token\"]").attr("content")
previewContainer: false
processing: ->
$(".div-dropzone-alert").alert "close"
dragover: ->
form_textarea.addClass "div-dropzone-focus"
form.find(".div-dropzone-hover").css "opacity", 0.7
return
dragleave: ->
form_textarea.removeClass "div-dropzone-focus"
form.find(".div-dropzone-hover").css "opacity", 0
return
drop: ->
form_textarea.removeClass "div-dropzone-focus"
form.find(".div-dropzone-hover").css "opacity", 0
form_textarea.focus()
return
success: (header, response) ->
child = $(dropzone[0]).children("textarea")
$(child).val $(child).val() + formatLink(response.link) + "\n"
return
error: (temp, errorMessage) ->
checkIfMsgExists = $(".error-alert").children().length
if checkIfMsgExists is 0
$(".error-alert").append divAlert
$(".div-dropzone-alert").append btnAlert + errorMessage
return
sending: ->
form_dropzone.find(".div-dropzone-spinner").css
"opacity": 0.7
"display": "inherit"
return
complete: ->
$(".dz-preview").remove()
$(".markdown-area").trigger "input"
$(".div-dropzone-spinner").css
"opacity": 0
"display": "none"
return
)
child = $(dropzone[0]).children("textarea")
formatLink = (str) ->
"![" + str.alt + "](" + str.url + ")"
handlePaste = (e) ->
e.preventDefault()
my_event = e.originalEvent
if my_event.clipboardData and my_event.clipboardData.items
processItem(my_event)
processItem = (e) ->
image = isImage(e)
if image
filename = getFilename(e) or "image.png"
text = "{{" + filename + "}}"
pasteText(text)
uploadFile image.getAsFile(), filename
else
text = e.clipboardData.getData("text/plain")
pasteText(text)
isImage = (data) ->
i = 0
while i < data.clipboardData.items.length
item = data.clipboardData.items[i]
if item.type.indexOf("image") isnt -1
return item
i++
return false
pasteText = (text) ->
caretStart = $(child)[0].selectionStart
caretEnd = $(child)[0].selectionEnd
textEnd = $(child).val().length
beforeSelection = $(child).val().substring 0, caretStart
afterSelection = $(child).val().substring caretEnd, textEnd
$(child).val beforeSelection + text + afterSelection
form_textarea.trigger "input"
getFilename = (e) ->
if window.clipboardData and window.clipboardData.getData
value = window.clipboardData.getData("Text")
else if e.clipboardData and e.clipboardData.getData
value = e.clipboardData.getData("text/plain")
value = value.split("\r")
value.first()
uploadFile = (item, filename) ->
formData = new FormData()
formData.append "markdown_img", item, filename
$.ajax
url: project_image_path_upload
type: "POST"
data: formData
dataType: "json"
processData: false
contentType: false
headers:
"X-CSRF-Token": $("meta[name=\"csrf-token\"]").attr("content")
beforeSend: ->
showSpinner()
closeAlertMessage()
success: (e, textStatus, response) ->
insertToTextArea(filename, formatLink(response.responseJSON.link))
error: (response) ->
showError(response.responseJSON.message)
complete: ->
closeSpinner()
insertToTextArea = (filename, url) ->
$(child).val (index, val) ->
val.replace("{{" + filename + "}}", url + "\n")
appendToTextArea = (url) ->
$(child).val (index, val) ->
val + url + "\n"
showSpinner = (e) ->
form.find(".div-dropzone-spinner").css
"opacity": 0.7
"display": "inherit"
closeSpinner = ->
form.find(".div-dropzone-spinner").css
"opacity": 0
"display": "none"
showError = (message) ->
checkIfMsgExists = $(".error-alert").children().length
if checkIfMsgExists is 0
$(".error-alert").append divAlert
$(".div-dropzone-alert").append btnAlert + message
closeAlertMessage = ->
form.find(".div-dropzone-alert").alert "close"
form.find(".markdown-selector").click (e) ->
e.preventDefault()
$(@).closest('.gfm-form').find('.div-dropzone').click()
return
formatLink: (str) ->
"![" + str.alt + "](" + str.url + ")"
formatLink = (str) ->
"![" + str.alt + "](" + str.url + ")"
$(document).ready ->
alertClass = "alert alert-danger alert-dismissable div-dropzone-alert"
alertAttr = "class=\"close\" data-dismiss=\"alert\"" + "aria-hidden=\"true\""
divHover = "<div class=\"div-dropzone-hover\"></div>"
divSpinner = "<div class=\"div-dropzone-spinner\"></div>"
divAlert = "<div class=\"" + alertClass + "\"></div>"
iconPicture = "<i class=\"fa fa-picture-o div-dropzone-icon\"></i>"
iconSpinner = "<i class=\"fa fa-spinner fa-spin div-dropzone-icon\"></i>"
btnAlert = "<button type=\"button\"" + alertAttr + ">&times;</button>"
project_image_path_upload = window.project_image_path_upload or null
$("textarea.markdown-area").wrap "<div class=\"div-dropzone\"></div>"
$(".div-dropzone").parent().addClass "div-dropzone-wrapper"
$(".div-dropzone").append divHover
$(".div-dropzone-hover").append iconPicture
$(".div-dropzone").append divSpinner
$(".div-dropzone-spinner").append iconSpinner
$(".div-dropzone-spinner").css
"opacity": 0
"display": "none"
# Preview button
$(document).off "click", ".js-md-preview-button"
$(document).on "click", ".js-md-preview-button", (e) ->
###
Shows the Markdown preview.
Lets the server render GFM into Html and displays it.
###
e.preventDefault()
form = $(this).closest("form")
# toggle tabs
form.find(".js-md-write-button").parent().removeClass "active"
form.find(".js-md-preview-button").parent().addClass "active"
# toggle content
form.find(".md-write-holder").hide()
form.find(".md-preview-holder").show()
preview = form.find(".js-md-preview")
mdText = form.find(".markdown-area").val()
if mdText.trim().length is 0
preview.text "Nothing to preview."
else
preview.text "Loading..."
$.get($(this).data("url"),
md_text: mdText
).success (previewData) ->
preview.html previewData
# Write button
$(document).off "click", ".js-md-write-button"
$(document).on "click", ".js-md-write-button", (e) ->
###
Shows the Markdown textarea.
###
e.preventDefault()
form = $(this).closest("form")
# toggle tabs
form.find(".js-md-write-button").parent().addClass "active"
form.find(".js-md-preview-button").parent().removeClass "active"
# toggle content
form.find(".md-write-holder").show()
form.find(".md-preview-holder").hide()
dropzone = $(".div-dropzone").dropzone(
url: project_image_path_upload
dictDefaultMessage: ""
clickable: true
paramName: "markdown_img"
maxFilesize: 10
uploadMultiple: false
acceptedFiles: "image/jpg,image/jpeg,image/gif,image/png"
headers:
"X-CSRF-Token": $("meta[name=\"csrf-token\"]").attr("content")
previewContainer: false
processing: ->
$(".div-dropzone-alert").alert "close"
dragover: ->
$(".div-dropzone > textarea").addClass "div-dropzone-focus"
$(".div-dropzone-hover").css "opacity", 0.7
return
dragleave: ->
$(".div-dropzone > textarea").removeClass "div-dropzone-focus"
$(".div-dropzone-hover").css "opacity", 0
return
drop: ->
$(".div-dropzone > textarea").removeClass "div-dropzone-focus"
$(".div-dropzone-hover").css "opacity", 0
$(".div-dropzone > textarea").focus()
return
success: (header, response) ->
child = $(dropzone[0]).children("textarea")
$(child).val $(child).val() + formatLink(response.link) + "\n"
return
error: (temp, errorMessage) ->
checkIfMsgExists = $(".error-alert").children().length
if checkIfMsgExists is 0
$(".error-alert").append divAlert
$(".div-dropzone-alert").append btnAlert + errorMessage
return
sending: ->
$(".div-dropzone-spinner").css
"opacity": 0.7
"display": "inherit"
return
complete: ->
$(".dz-preview").remove()
$(".markdown-area").trigger "input"
$(".div-dropzone-spinner").css
"opacity": 0
"display": "none"
return
)
child = $(dropzone[0]).children("textarea")
formatLink = (str) ->
"![" + str.alt + "](" + str.url + ")"
handlePaste = (e) ->
e.preventDefault()
my_event = e.originalEvent
if my_event.clipboardData and my_event.clipboardData.items
processItem(my_event)
processItem = (e) ->
image = isImage(e)
if image
filename = getFilename(e) or "image.png"
text = "{{" + filename + "}}"
pasteText(text)
uploadFile image.getAsFile(), filename
else
text = e.clipboardData.getData("text/plain")
pasteText(text)
isImage = (data) ->
i = 0
while i < data.clipboardData.items.length
item = data.clipboardData.items[i]
if item.type.indexOf("image") isnt -1
return item
i++
return false
pasteText = (text) ->
caretStart = $(child)[0].selectionStart
caretEnd = $(child)[0].selectionEnd
textEnd = $(child).val().length
beforeSelection = $(child).val().substring 0, caretStart
afterSelection = $(child).val().substring caretEnd, textEnd
$(child).val beforeSelection + text + afterSelection
$(".markdown-area").trigger "input"
getFilename = (e) ->
if window.clipboardData and window.clipboardData.getData
value = window.clipboardData.getData("Text")
else if e.clipboardData and e.clipboardData.getData
value = e.clipboardData.getData("text/plain")
value = value.split("\r")
value.first()
uploadFile = (item, filename) ->
formData = new FormData()
formData.append "markdown_img", item, filename
$.ajax
url: project_image_path_upload
type: "POST"
data: formData
dataType: "json"
processData: false
contentType: false
headers:
"X-CSRF-Token": $("meta[name=\"csrf-token\"]").attr("content")
beforeSend: ->
showSpinner()
closeAlertMessage()
success: (e, textStatus, response) ->
insertToTextArea(filename, formatLink(response.responseJSON.link))
error: (response) ->
showError(response.responseJSON.message)
complete: ->
closeSpinner()
insertToTextArea = (filename, url) ->
$(child).val (index, val) ->
val.replace("{{" + filename + "}}", url + "\n")
appendToTextArea = (url) ->
$(child).val (index, val) ->
val + url + "\n"
showSpinner = (e) ->
$(".div-dropzone-spinner").css
"opacity": 0.7
"display": "inherit"
closeSpinner = ->
$(".div-dropzone-spinner").css
"opacity": 0
"display": "none"
showError = (message) ->
checkIfMsgExists = $(".error-alert").children().length
if checkIfMsgExists is 0
$(".error-alert").append divAlert
$(".div-dropzone-alert").append btnAlert + message
closeAlertMessage = ->
$(".div-dropzone-alert").alert "close"
$(".markdown-selector").click (e) ->
e.preventDefault()
$(@).closest('.gfm-form').find('.div-dropzone').click()
return
return
...@@ -114,10 +114,6 @@ class @Notes ...@@ -114,10 +114,6 @@ class @Notes
if @isNewNote(note) if @isNewNote(note)
@note_ids.push(note.id) @note_ids.push(note.id)
$('ul.main-notes-list').append(note.html) $('ul.main-notes-list').append(note.html)
code = "#note_" + note.id + " .highlight pre code"
$(code).each (i, e) ->
hljs.highlightBlock(e)
### ###
Check if note does not exists on page Check if note does not exists on page
...@@ -219,6 +215,7 @@ class @Notes ...@@ -219,6 +215,7 @@ class @Notes
setupNoteForm: (form) -> setupNoteForm: (form) ->
disableButtonIfEmptyField form.find(".js-note-text"), form.find(".js-comment-button") disableButtonIfEmptyField form.find(".js-note-text"), form.find(".js-comment-button")
form.removeClass "js-new-note-form" form.removeClass "js-new-note-form"
form.find('.div-dropzone').remove()
# setup preview buttons # setup preview buttons
form.find(".js-md-write-button, .js-md-preview-button").tooltip placement: "left" form.find(".js-md-write-button, .js-md-preview-button").tooltip placement: "left"
...@@ -233,6 +230,7 @@ class @Notes ...@@ -233,6 +230,7 @@ class @Notes
# remove notify commit author checkbox for non-commit notes # remove notify commit author checkbox for non-commit notes
form.find(".js-notify-commit-author").remove() if form.find("#note_noteable_type").val() isnt "Commit" form.find(".js-notify-commit-author").remove() if form.find("#note_noteable_type").val() isnt "Commit"
GitLab.GfmAutoComplete.setup() GitLab.GfmAutoComplete.setup()
new DropzoneInput(form)
form.show() form.show()
...@@ -259,11 +257,10 @@ class @Notes ...@@ -259,11 +257,10 @@ class @Notes
Updates the current note field. Updates the current note field.
### ###
updateNote: (xhr, note, status) => updateNote: (xhr, note, status) =>
note_li = $("#note_" + note.id) note_li = $(".note-row-" + note.id)
note_li.replaceWith(note.html) note_li.replaceWith(note.html)
code = "#note_" + note.id + " .highlight pre code" note_li.find('.note-edit-form').hide()
$(code).each (i, e) -> note_li.find('.note-text').show()
hljs.highlightBlock(e)
### ###
Called in response to clicking the edit note link Called in response to clicking the edit note link
...@@ -276,11 +273,19 @@ class @Notes ...@@ -276,11 +273,19 @@ class @Notes
e.preventDefault() e.preventDefault()
note = $(this).closest(".note") note = $(this).closest(".note")
note.find(".note-text").hide() note.find(".note-text").hide()
note.find(".note-header").hide()
base_form = note.find(".note-edit-form")
form = base_form.clone().insertAfter(base_form)
form.addClass('current-note-edit-form')
form.find('.div-dropzone').remove()
# Show the attachment delete link # Show the attachment delete link
note.find(".js-note-attachment-delete").show() note.find(".js-note-attachment-delete").show()
# Setup markdown form
GitLab.GfmAutoComplete.setup() GitLab.GfmAutoComplete.setup()
form = note.find(".note-edit-form") new DropzoneInput(form)
form.show() form.show()
textarea = form.find("textarea") textarea = form.find("textarea")
textarea.focus() textarea.focus()
...@@ -295,8 +300,8 @@ class @Notes ...@@ -295,8 +300,8 @@ class @Notes
e.preventDefault() e.preventDefault()
note = $(this).closest(".note") note = $(this).closest(".note")
note.find(".note-text").show() note.find(".note-text").show()
note.find(".js-note-attachment-delete").hide() note.find(".note-header").show()
note.find(".note-edit-form").hide() note.find(".current-note-edit-form").remove()
### ###
Called in response to deleting a note of any kind. Called in response to deleting a note of any kind.
......
#= require pwstrength-bootstrap-1.2.2
overwritten_messages =
wordSimilarToUsername: "Your password should not contain your username"
overwritten_rules =
wordSequences: false
options =
showProgressBar: false
showVerdicts: false
showPopover: true
showErrors: true
showStatus: true
errorMessages: overwritten_messages
$(document).ready ->
profileOptions = {}
profileOptions.ui = options
profileOptions.rules =
activated: overwritten_rules
deviseOptions = {}
deviseOptions.common =
usernameField: "#user_username"
deviseOptions.ui = options
deviseOptions.rules =
activated: overwritten_rules
$("#user_password_profile").pwstrength profileOptions
$("#user_password_sign_up").pwstrength deviseOptions
$("#user_password_recover").pwstrength deviseOptions
...@@ -10,7 +10,15 @@ class @ZenMode ...@@ -10,7 +10,15 @@ class @ZenMode
if not @active_checkbox if not @active_checkbox
@scroll_position = window.pageYOffset @scroll_position = window.pageYOffset
$('body').on 'change', '.zennable input[type=checkbox]', (e) => $('body').on 'click', '.zen-enter-link', (e) =>
e.preventDefault()
$(e.currentTarget).closest('.zennable').find('.zen-toggle-comment').prop('checked', true)
$('body').on 'click', '.zen-leave-link', (e) =>
e.preventDefault()
$(e.currentTarget).closest('.zennable').find('.zen-toggle-comment').prop('checked', false)
$('body').on 'change', '.zen-toggle-comment', (e) =>
checkbox = e.currentTarget checkbox = e.currentTarget
if checkbox.checked if checkbox.checked
# Disable other keyboard shortcuts in ZEN mode # Disable other keyboard shortcuts in ZEN mode
...@@ -32,8 +40,6 @@ class @ZenMode ...@@ -32,8 +40,6 @@ class @ZenMode
@active_zen_area = @active_checkbox.parent().find('textarea') @active_zen_area = @active_checkbox.parent().find('textarea')
@active_zen_area.focus() @active_zen_area.focus()
window.location.hash = ZenMode.fullscreen_prefix + @active_checkbox.prop('id') window.location.hash = ZenMode.fullscreen_prefix + @active_checkbox.prop('id')
# Disable dropzone in ZEN mode
Dropzone.forElement('.div-dropzone').disable()
exitZenMode: => exitZenMode: =>
if @active_zen_area isnt null if @active_zen_area isnt null
......
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
*= require jquery.ui.autocomplete *= require jquery.ui.autocomplete
*= require jquery.atwho *= require jquery.atwho
*= require select2 *= require select2
*= require highlightjs.min
*= require_self *= require_self
*= require dropzone/basic *= require dropzone/basic
*/ */
......
...@@ -54,6 +54,11 @@ pre { ...@@ -54,6 +54,11 @@ pre {
text-shadow: none; text-shadow: none;
} }
.dropdown-menu-align-right {
left: auto;
right: 0px;
}
.dropdown-menu > li > a:hover, .dropdown-menu > li > a:hover,
.dropdown-menu > li > a:focus { .dropdown-menu > li > a:focus {
background: $bg_primary; background: $bg_primary;
...@@ -273,10 +278,6 @@ img.emoji { ...@@ -273,10 +278,6 @@ img.emoji {
height: 220px; height: 220px;
} }
.navless-container {
margin-top: 68px;
}
.description-block { .description-block {
@extend .light-well; @extend .light-well;
@extend .light; @extend .light;
......
...@@ -97,136 +97,3 @@ label { ...@@ -97,136 +97,3 @@ label {
.wiki-content { .wiki-content {
margin-top: 35px; margin-top: 35px;
} }
.zennable {
position: relative;
input {
display: none;
}
.collapse {
display: none;
opacity: 0.5;
&:before {
content: '\f066';
font-family: FontAwesome;
color: #000;
font-size: 28px;
position: relative;
padding: 30px 40px 0 0;
}
&:hover {
opacity: 0.8;
}
}
.expand {
opacity: 0.5;
&:before {
content: '\f065';
font-family: FontAwesome;
color: #000;
font-size: 14px;
line-height: 14px;
padding-right: 20px;
position: relative;
vertical-align: middle;
}
&:hover {
opacity: 0.8;
}
}
input:checked ~ .zen-backdrop .expand {
display: none;
}
input:checked ~ .zen-backdrop .collapse {
display: block;
position: absolute;
top: 0;
}
label {
position: absolute;
top: -26px;
right: 0;
font-variant: small-caps;
text-transform: uppercase;
font-size: 10px;
padding: 4px;
font-weight: 500;
letter-spacing: 1px;
&:before {
display: inline-block;
width: 10px;
height: 14px;
}
}
input:checked ~ .zen-backdrop {
background-color: white;
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
z-index: 1031;
textarea {
border: none;
box-shadow: none;
border-radius: 0;
color: #000;
font-size: 20px;
line-height: 26px;
padding: 30px;
display: block;
outline: none;
resize: none;
height: 100vh;
max-width: 900px;
margin: 0 auto;
}
}
.zen-backdrop textarea::-webkit-input-placeholder {
color: white;
}
.zen-backdrop textarea:-moz-placeholder {
color: white;
}
.zen-backdrop textarea::-moz-placeholder {
color: white;
}
.zen-backdrop textarea:-ms-input-placeholder {
color: white;
}
input:checked ~ .zen-backdrop textarea::-webkit-input-placeholder {
color: #999;
}
input:checked ~ .zen-backdrop textarea:-moz-placeholder {
color: #999;
opacity: 1;
}
input:checked ~ .zen-backdrop textarea::-moz-placeholder {
color: #999;
opacity: 1;
}
input:checked ~ .zen-backdrop textarea:-ms-input-placeholder {
color: #999;
}
}
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
.issue-form, .merge-request-form, .wiki-form { .issue-form, .merge-request-form, .wiki-form {
.description { .description {
height: 20em; height: 20em;
border-top-left-radius: 0;
} }
} }
...@@ -17,4 +18,4 @@ ...@@ -17,4 +18,4 @@
.description { .description {
height: 14em; height: 14em;
} }
} }
\ No newline at end of file
.highlighted-data { .file-content.code {
border: none; border: none;
box-shadow: none; box-shadow: none;
margin: 0px; margin: 0px;
...@@ -13,8 +13,13 @@ ...@@ -13,8 +13,13 @@
font-size: 12px !important; font-size: 12px !important;
line-height: 16px !important; line-height: 16px !important;
margin: 0; margin: 0;
overflow: auto;
overflow-y: hidden;
white-space: pre;
word-wrap: normal;
code { code {
font-family: $monospace_font;
white-space: pre; white-space: pre;
word-wrap: normal; word-wrap: normal;
padding: 0; padding: 0;
...@@ -25,10 +30,6 @@ ...@@ -25,10 +30,6 @@
} }
} }
.hljs {
padding: 0;
}
.line-numbers { .line-numbers {
padding: 10px; padding: 10px;
text-align: right; text-align: right;
...@@ -51,18 +52,18 @@ ...@@ -51,18 +52,18 @@
} }
} }
} }
}
.highlight { .note-text .code {
overflow: auto; border: none;
overflow-y: hidden; box-shadow: none;
background: $box_bg;
pre { padding: 1em;
white-space: pre;
word-wrap: normal;
code { code {
font-family: $monospace_font; font-family: $monospace_font;
} white-space: pre;
} word-wrap: normal;
padding: 0;
} }
} }
...@@ -69,12 +69,11 @@ ...@@ -69,12 +69,11 @@
} }
.well-title { .well-title {
font-size: 14px; font-size: $list-font-size;
line-height: 18px; line-height: 18px;
} }
.row_title { .row_title {
font-weight: 500;
color: #444; color: #444;
&:hover { &:hover {
color: #444; color: #444;
......
/** Common mobile (screen XS) styles **/ /** Common mobile (screen XS, SM) styles **/
@media (max-width: $screen-xs-max) { @media (max-width: $screen-xs-max) {
.container .content { .container .content {
margin-top: 20px; margin-top: 20px;
...@@ -13,5 +13,41 @@ ...@@ -13,5 +13,41 @@
display: none; display: none;
} }
} }
.issues-filters,
.dash-projects-filters,
.check-all-holder {
display: none;
}
.rss-btn {
display: none !important;
}
.project-home-panel {
.star-fork-buttons {
padding-top: 10px;
padding-right: 15px;
}
}
.project-home-links {
display: none;
}
} }
@media (max-width: $screen-sm-max) {
.issues-filters {
.milestone-filter, .labels-filter {
display: none;
}
}
.page-title .new-issue-link {
display: none;
}
.issue_edited_ago, .note_edited_ago {
display: none;
}
}
.zennable {
position: relative;
input {
display: none;
}
.zen-enter-link {
color: #888;
position: absolute;
top: -26px;
right: 4px;
}
.zen-leave-link {
display: none;
color: #888;
position: absolute;
top: 10px;
right: 10px;
padding: 5px;
font-size: 36px;
&:hover {
color: #111;
}
}
input:checked ~ .zen-backdrop .zen-enter-link {
display: none;
}
input:checked ~ .zen-backdrop .zen-leave-link {
display: block;
position: absolute;
top: 0;
}
input:checked ~ .zen-backdrop {
background-color: white;
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
z-index: 1031;
textarea {
border: none;
box-shadow: none;
border-radius: 0;
color: #000;
font-size: 20px;
line-height: 26px;
padding: 30px;
display: block;
outline: none;
resize: none;
height: 100vh;
max-width: 900px;
margin: 0 auto;
}
}
.zen-backdrop textarea::-webkit-input-placeholder {
color: white;
}
.zen-backdrop textarea:-moz-placeholder {
color: white;
}
.zen-backdrop textarea::-moz-placeholder {
color: white;
}
.zen-backdrop textarea:-ms-input-placeholder {
color: white;
}
input:checked ~ .zen-backdrop textarea::-webkit-input-placeholder {
color: #999;
}
input:checked ~ .zen-backdrop textarea:-moz-placeholder {
color: #999;
opacity: 1;
}
input:checked ~ .zen-backdrop textarea::-moz-placeholder {
color: #999;
opacity: 1;
}
input:checked ~ .zen-backdrop textarea:-ms-input-placeholder {
color: #999;
}
}
.dark { /* https://github.com/MozMorris/tomorrow-pygments */
background-color: #232323; .code.dark {
.line.hll {
background: #558;
}
.highlight{
border-left: 1px solid #444;
}
.no-highlight {
color: #DDD;
}
pre.code,
.line-numbers,
.line-numbers a { .line-numbers a {
color: #666; background-color: #1d1f21 !important;
} color: #c5c8c6 !important;
}
pre {
background-color: #232323; pre.code {
} border-left: 1px solid #666;
}
.hljs {
display: block; pre.hll {
background: #232323; background-color: #fff !important;
color: #E6E1DC; }
}
.hll { background-color: #373b41 }
.hljs-comment, .c { color: #969896 } /* Comment */
.hljs-template_comment, .err { color: #cc6666 } /* Error */
.hljs-javadoc, .k { color: #b294bb } /* Keyword */
.hljs-shebang { .l { color: #de935f } /* Literal */
color: #BC9458; .n { color: #c5c8c6 } /* Name */
font-style: italic; .o { color: #8abeb7 } /* Operator */
} .p { color: #c5c8c6 } /* Punctuation */
.cm { color: #969896 } /* Comment.Multiline */
.hljs-keyword, .cp { color: #969896 } /* Comment.Preproc */
.ruby .hljs-function .hljs-keyword, .c1 { color: #969896 } /* Comment.Single */
.hljs-request, .cs { color: #969896 } /* Comment.Special */
.hljs-status, .gd { color: #cc6666 } /* Generic.Deleted */
.nginx .hljs-title, .ge { font-style: italic } /* Generic.Emph */
.method, .gh { color: #c5c8c6; font-weight: bold } /* Generic.Heading */
.hljs-list .hljs-title { .gi { color: #b5bd68 } /* Generic.Inserted */
color: #C26230; .gp { color: #969896; font-weight: bold } /* Generic.Prompt */
} .gs { font-weight: bold } /* Generic.Strong */
.gu { color: #8abeb7; font-weight: bold } /* Generic.Subheading */
.hljs-string, .kc { color: #b294bb } /* Keyword.Constant */
.hljs-number, .kd { color: #b294bb } /* Keyword.Declaration */
.hljs-regexp, .kn { color: #8abeb7 } /* Keyword.Namespace */
.hljs-tag .hljs-value, .kp { color: #b294bb } /* Keyword.Pseudo */
.hljs-cdata, .kr { color: #b294bb } /* Keyword.Reserved */
.hljs-filter .hljs-argument, .kt { color: #f0c674 } /* Keyword.Type */
.hljs-attr_selector, .ld { color: #b5bd68 } /* Literal.Date */
.apache .hljs-cbracket, .m { color: #de935f } /* Literal.Number */
.hljs-date, .s { color: #b5bd68 } /* Literal.String */
.tex .hljs-command, .na { color: #81a2be } /* Name.Attribute */
.markdown .hljs-link_label { .nb { color: #c5c8c6 } /* Name.Builtin */
color: #A5C261; .nc { color: #f0c674 } /* Name.Class */
} .no { color: #cc6666 } /* Name.Constant */
.nd { color: #8abeb7 } /* Name.Decorator */
.hljs-subst { .ni { color: #c5c8c6 } /* Name.Entity */
color: #519F50; .ne { color: #cc6666 } /* Name.Exception */
} .nf { color: #81a2be } /* Name.Function */
.nl { color: #c5c8c6 } /* Name.Label */
.hljs-tag, .nn { color: #f0c674 } /* Name.Namespace */
.hljs-tag .hljs-keyword, .nx { color: #81a2be } /* Name.Other */
.hljs-tag .hljs-title, .py { color: #c5c8c6 } /* Name.Property */
.hljs-doctype, .nt { color: #8abeb7 } /* Name.Tag */
.hljs-sub .hljs-identifier, .nv { color: #cc6666 } /* Name.Variable */
.hljs-pi, .ow { color: #8abeb7 } /* Operator.Word */
.input_number { .w { color: #c5c8c6 } /* Text.Whitespace */
color: #E8BF6A; .mf { color: #de935f } /* Literal.Number.Float */
} .mh { color: #de935f } /* Literal.Number.Hex */
.mi { color: #de935f } /* Literal.Number.Integer */
.hljs-identifier { .mo { color: #de935f } /* Literal.Number.Oct */
color: #D0D0FF; .sb { color: #b5bd68 } /* Literal.String.Backtick */
} .sc { color: #c5c8c6 } /* Literal.String.Char */
.sd { color: #969896 } /* Literal.String.Doc */
.hljs-class .hljs-title, .s2 { color: #b5bd68 } /* Literal.String.Double */
.haskell .hljs-type, .se { color: #de935f } /* Literal.String.Escape */
.smalltalk .hljs-class, .sh { color: #b5bd68 } /* Literal.String.Heredoc */
.hljs-javadoctag, .si { color: #de935f } /* Literal.String.Interpol */
.hljs-yardoctag, .sx { color: #b5bd68 } /* Literal.String.Other */
.hljs-phpdoc { .sr { color: #b5bd68 } /* Literal.String.Regex */
text-decoration: none; .s1 { color: #b5bd68 } /* Literal.String.Single */
} .ss { color: #b5bd68 } /* Literal.String.Symbol */
.bp { color: #c5c8c6 } /* Name.Builtin.Pseudo */
.hljs-constant { .vc { color: #cc6666 } /* Name.Variable.Class */
color: #DA4939; .vg { color: #cc6666 } /* Name.Variable.Global */
} .vi { color: #cc6666 } /* Name.Variable.Instance */
.il { color: #de935f } /* Literal.Number.Integer.Long */
.hljs-symbol,
.hljs-built_in,
.ruby .hljs-symbol .hljs-string,
.ruby .hljs-symbol .hljs-identifier,
.markdown .hljs-link_url,
.hljs-attribute {
color: #6D9CBE;
}
.markdown .hljs-link_url {
text-decoration: underline;
}
.hljs-params,
.hljs-variable,
.clojure .hljs-attribute {
color: #D0D0FF;
}
.css .hljs-tag,
.hljs-rules .hljs-property,
.hljs-pseudo,
.tex .hljs-special {
color: #CDA869;
}
.css .hljs-class {
color: #9B703F;
}
.hljs-rules .hljs-keyword {
color: #C5AF75;
}
.hljs-rules .hljs-value {
color: #CF6A4C;
}
.css .hljs-id {
color: #8B98AB;
}
.hljs-annotation,
.apache .hljs-sqbracket,
.nginx .hljs-built_in {
color: #9B859D;
}
.hljs-preprocessor,
.hljs-preprocessor *,
.hljs-pragma {
color: #8996A8 !important;
}
.hljs-hexcolor,
.css .hljs-value .hljs-number {
color: #A5C261;
}
.hljs-title,
.hljs-decorator,
.css .hljs-function {
color: #FFC66D;
}
.diff .hljs-header,
.hljs-chunk {
background-color: #2F33AB;
color: #E6E1DC;
display: inline-block;
width: 100%;
}
.diff .hljs-change {
background-color: #4A410D;
color: #F8F8F8;
display: inline-block;
width: 100%;
}
.hljs-addition {
background-color: #144212;
color: #E6E1DC;
display: inline-block;
width: 100%;
}
.hljs-deletion {
background-color: #600;
color: #E6E1DC;
display: inline-block;
width: 100%;
}
.coffeescript .javascript,
.javascript .xml,
.tex .hljs-formula,
.xml .javascript,
.xml .vbscript,
.xml .css,
.xml .hljs-cdata {
opacity: 0.7;
}
} }
.monokai { /* https://github.com/richleland/pygments-css/blob/master/monokai.css */
background-color: #272822; .code.monokai {
.highlight{
border-left: 1px solid #444;
}
.line.hll {
background: #558;
}
.no-highlight {
color: #DDD;
}
pre.highlight,
.line-numbers,
.line-numbers a { .line-numbers a {
color: #666; background:#272822 !important;
} color:#f8f8f2 !important;
}
pre {
background-color: #272822; pre.code {
color: #f8f8f2; border-left: 1px solid #555;
} }
.hljs { .hll { background-color: #49483e }
display: block; .c { color: #75715e } /* Comment */
background: #272822; .err { color: #960050; background-color: #1e0010 } /* Error */
} .k { color: #66d9ef } /* Keyword */
.l { color: #ae81ff } /* Literal */
.hljs-tag, .n { color: #f8f8f2 } /* Name */
.hljs-tag .hljs-title, .o { color: #f92672 } /* Operator */
.hljs-strong, .p { color: #f8f8f2 } /* Punctuation */
.hljs-change, .cm { color: #75715e } /* Comment.Multiline */
.hljs-winutils, .cp { color: #75715e } /* Comment.Preproc */
.hljs-flow, .c1 { color: #75715e } /* Comment.Single */
.lisp .hljs-title, .cs { color: #75715e } /* Comment.Special */
.clojure .hljs-built_in, .ge { font-style: italic } /* Generic.Emph */
.hljs-keyword, .gs { font-weight: bold } /* Generic.Strong */
.nginx .hljs-title, .kc { color: #66d9ef } /* Keyword.Constant */
.tex .hljs-special { .kd { color: #66d9ef } /* Keyword.Declaration */
color: #F92672; .kn { color: #f92672 } /* Keyword.Namespace */
} .kp { color: #66d9ef } /* Keyword.Pseudo */
.kr { color: #66d9ef } /* Keyword.Reserved */
.hljs { .kt { color: #66d9ef } /* Keyword.Type */
color: #F8F8F2; .ld { color: #e6db74 } /* Literal.Date */
} .m { color: #ae81ff } /* Literal.Number */
.s { color: #e6db74 } /* Literal.String */
.asciidoc .hljs-code, .na { color: #a6e22e } /* Name.Attribute */
.markdown .hljs-code, .nb { color: #f8f8f2 } /* Name.Builtin */
.hljs-literal, .nc { color: #a6e22e } /* Name.Class */
.hljs-function .hljs-keyword { .no { color: #66d9ef } /* Name.Constant */
color: #66D9EF; .nd { color: #a6e22e } /* Name.Decorator */
} .ni { color: #f8f8f2 } /* Name.Entity */
.ne { color: #a6e22e } /* Name.Exception */
.nf { color: #a6e22e } /* Name.Function */
.hljs-code, .nl { color: #f8f8f2 } /* Name.Label */
.hljs-class .hljs-title, .nn { color: #f8f8f2 } /* Name.Namespace */
.hljs-header { .nx { color: #a6e22e } /* Name.Other */
color: white; .py { color: #f8f8f2 } /* Name.Property */
} .nt { color: #f92672 } /* Name.Tag */
.nv { color: #f8f8f2 } /* Name.Variable */
.hljs-link_label, .ow { color: #f92672 } /* Operator.Word */
.hljs-attribute, .w { color: #f8f8f2 } /* Text.Whitespace */
.hljs-symbol, .mf { color: #ae81ff } /* Literal.Number.Float */
.hljs-symbol .hljs-string, .mh { color: #ae81ff } /* Literal.Number.Hex */
.hljs-value, .mi { color: #ae81ff } /* Literal.Number.Integer */
.hljs-constant, .mo { color: #ae81ff } /* Literal.Number.Oct */
.hljs-number, .sb { color: #e6db74 } /* Literal.String.Backtick */
.hljs-regexp { .sc { color: #e6db74 } /* Literal.String.Char */
color: #AE81FF; .sd { color: #e6db74 } /* Literal.String.Doc */
} .s2 { color: #e6db74 } /* Literal.String.Double */
.se { color: #ae81ff } /* Literal.String.Escape */
.hljs-string { .sh { color: #e6db74 } /* Literal.String.Heredoc */
color: #E6DB74; .si { color: #e6db74 } /* Literal.String.Interpol */
} .sx { color: #e6db74 } /* Literal.String.Other */
.sr { color: #e6db74 } /* Literal.String.Regex */
.hljs-params { .s1 { color: #e6db74 } /* Literal.String.Single */
color: #fd971f; .ss { color: #e6db74 } /* Literal.String.Symbol */
} .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */
.vc { color: #f8f8f2 } /* Name.Variable.Class */
.hljs-link_url, .vg { color: #f8f8f2 } /* Name.Variable.Global */
.hljs-tag .hljs-value, .vi { color: #f8f8f2 } /* Name.Variable.Instance */
.hljs-bullet, .il { color: #ae81ff } /* Literal.Number.Integer.Long */
.hljs-subst,
.hljs-title, .gh { } /* Generic Heading & Diff Header */
.hljs-emphasis, .gu { color: #75715e; } /* Generic.Subheading & Diff Unified/Comment? */
.hljs-type, .gd { color: #f92672; } /* Generic.Deleted & Diff Deleted */
.hljs-preprocessor, .gi { color: #a6e22e; } /* Generic.Inserted & Diff Inserted */
.hljs-pragma,
.ruby .hljs-class .hljs-parent,
.hljs-built_in,
.sql .hljs-aggregate,
.django .hljs-template_tag,
.django .hljs-variable,
.smalltalk .hljs-class,
.hljs-javadoc,
.django .hljs-filter .hljs-argument,
.smalltalk .hljs-localvars,
.smalltalk .hljs-array,
.hljs-attr_selector,
.hljs-pseudo,
.hljs-addition,
.hljs-stream,
.hljs-envvar,
.apache .hljs-tag,
.apache .hljs-cbracket,
.tex .hljs-command,
.hljs-prompt {
color: #A6E22E;
}
.hljs-comment,
.hljs-annotation,
.smartquote,
.hljs-blockquote,
.hljs-horizontal_rule,
.hljs-template_comment,
.hljs-decorator,
.hljs-pi,
.hljs-doctype,
.hljs-deletion,
.hljs-shebang,
.apache .hljs-sqbracket,
.tex .hljs-formula {
color: #75715E;
}
.hljs-keyword,
.hljs-literal,
.css .hljs-id,
.hljs-phpdoc,
.hljs-title,
.hljs-header,
.haskell .hljs-type,
.vbscript .hljs-built_in,
.sql .hljs-aggregate,
.rsl .hljs-built_in,
.smalltalk .hljs-class,
.diff .hljs-header,
.hljs-chunk,
.hljs-winutils,
.bash .hljs-variable,
.apache .hljs-tag,
.tex .hljs-special,
.hljs-request,
.hljs-status {
font-weight: bold;
}
.coffeescript .javascript,
.javascript .xml,
.tex .hljs-formula,
.xml .javascript,
.xml .vbscript,
.xml .css,
.xml .hljs-cdata {
opacity: 0.5;
}
} }
.solarized-dark { /* https://gist.github.com/qguv/7936275 */
background-color: #002B36; .code.solarized-dark {
.highlight{
border-left: 1px solid #113b46;
}
.line.hll {
background: #000;
}
.no-highlight {
color: #DDD;
}
pre {
background-color: #002B36;
color: #eee;
}
pre.code,
.line-numbers,
.line-numbers a { .line-numbers a {
color: #666; background-color: #002b36 !important;
color: #93a1a1 !important;
} }
.hljs { pre.code {
display: block; border-left: 1px solid #113b46;
background: #002b36;
color: #839496;
}
.hljs-comment,
.hljs-template_comment,
.diff .hljs-header,
.hljs-doctype,
.hljs-pi,
.lisp .hljs-string,
.hljs-javadoc {
color: #586e75;
}
/* Solarized Green */
.hljs-keyword,
.hljs-winutils,
.method,
.hljs-addition,
.css .hljs-tag,
.hljs-request,
.hljs-status,
.nginx .hljs-title {
color: #859900;
} }
/* Solarized Cyan */ /* Solarized Dark
.hljs-number,
.hljs-command,
.hljs-string,
.hljs-tag .hljs-value,
.hljs-rules .hljs-value,
.hljs-phpdoc,
.tex .hljs-formula,
.hljs-regexp,
.hljs-hexcolor,
.hljs-link_url {
color: #2aa198;
}
/* Solarized Blue */ For use with Jekyll and Pygments
.hljs-title,
.hljs-localvars,
.hljs-chunk,
.hljs-decorator,
.hljs-built_in,
.hljs-identifier,
.vhdl .hljs-literal,
.hljs-id,
.css .hljs-function {
color: #268bd2;
}
/* Solarized Yellow */ http://ethanschoonover.com/solarized
.hljs-attribute,
.hljs-variable,
.lisp .hljs-body,
.smalltalk .hljs-number,
.hljs-constant,
.hljs-class .hljs-title,
.hljs-parent,
.haskell .hljs-type,
.hljs-link_reference {
color: #b58900;
}
/* Solarized Orange */ SOLARIZED HEX ROLE
.hljs-preprocessor, --------- -------- ------------------------------------------
.hljs-preprocessor .hljs-keyword, base03 #002b36 background
.hljs-pragma, base01 #586e75 comments / secondary content
.hljs-shebang, base1 #93a1a1 body text / default code / primary content
.hljs-symbol, orange #cb4b16 constants
.hljs-symbol .hljs-string, red #dc322f regex, special keywords
.diff .hljs-change, blue #268bd2 reserved keywords
.hljs-special, cyan #2aa198 strings, numbers
.hljs-attr_selector, green #859900 operators, other keywords
.hljs-subst, */
.hljs-cdata,
.clojure .hljs-title,
.css .hljs-pseudo,
.hljs-header {
color: #cb4b16;
}
/* Solarized Red */ .c { color: #586e75 } /* Comment */
.hljs-deletion, .err { color: #93a1a1 } /* Error */
.hljs-important { .g { color: #93a1a1 } /* Generic */
color: #dc322f; .k { color: #859900 } /* Keyword */
} .l { color: #93a1a1 } /* Literal */
.n { color: #93a1a1 } /* Name */
/* Solarized Violet */ .o { color: #859900 } /* Operator */
.hljs-link_label { .x { color: #cb4b16 } /* Other */
color: #6c71c4; .p { color: #93a1a1 } /* Punctuation */
} .cm { color: #586e75 } /* Comment.Multiline */
.cp { color: #859900 } /* Comment.Preproc */
.tex .hljs-formula { .c1 { color: #586e75 } /* Comment.Single */
background: #073642; .cs { color: #859900 } /* Comment.Special */
} .gd { color: #2aa198 } /* Generic.Deleted */
.ge { color: #93a1a1; font-style: italic } /* Generic.Emph */
.gr { color: #dc322f } /* Generic.Error */
.gh { color: #cb4b16 } /* Generic.Heading */
.gi { color: #859900 } /* Generic.Inserted */
.go { color: #93a1a1 } /* Generic.Output */
.gp { color: #93a1a1 } /* Generic.Prompt */
.gs { color: #93a1a1; font-weight: bold } /* Generic.Strong */
.gu { color: #cb4b16 } /* Generic.Subheading */
.gt { color: #93a1a1 } /* Generic.Traceback */
.kc { color: #cb4b16 } /* Keyword.Constant */
.kd { color: #268bd2 } /* Keyword.Declaration */
.kn { color: #859900 } /* Keyword.Namespace */
.kp { color: #859900 } /* Keyword.Pseudo */
.kr { color: #268bd2 } /* Keyword.Reserved */
.kt { color: #dc322f } /* Keyword.Type */
.ld { color: #93a1a1 } /* Literal.Date */
.m { color: #2aa198 } /* Literal.Number */
.s { color: #2aa198 } /* Literal.String */
.na { color: #93a1a1 } /* Name.Attribute */
.nb { color: #B58900 } /* Name.Builtin */
.nc { color: #268bd2 } /* Name.Class */
.no { color: #cb4b16 } /* Name.Constant */
.nd { color: #268bd2 } /* Name.Decorator */
.ni { color: #cb4b16 } /* Name.Entity */
.ne { color: #cb4b16 } /* Name.Exception */
.nf { color: #268bd2 } /* Name.Function */
.nl { color: #93a1a1 } /* Name.Label */
.nn { color: #93a1a1 } /* Name.Namespace */
.nx { color: #93a1a1 } /* Name.Other */
.py { color: #93a1a1 } /* Name.Property */
.nt { color: #268bd2 } /* Name.Tag */
.nv { color: #268bd2 } /* Name.Variable */
.ow { color: #859900 } /* Operator.Word */
.w { color: #93a1a1 } /* Text.Whitespace */
.mf { color: #2aa198 } /* Literal.Number.Float */
.mh { color: #2aa198 } /* Literal.Number.Hex */
.mi { color: #2aa198 } /* Literal.Number.Integer */
.mo { color: #2aa198 } /* Literal.Number.Oct */
.sb { color: #586e75 } /* Literal.String.Backtick */
.sc { color: #2aa198 } /* Literal.String.Char */
.sd { color: #93a1a1 } /* Literal.String.Doc */
.s2 { color: #2aa198 } /* Literal.String.Double */
.se { color: #cb4b16 } /* Literal.String.Escape */
.sh { color: #93a1a1 } /* Literal.String.Heredoc */
.si { color: #2aa198 } /* Literal.String.Interpol */
.sx { color: #2aa198 } /* Literal.String.Other */
.sr { color: #dc322f } /* Literal.String.Regex */
.s1 { color: #2aa198 } /* Literal.String.Single */
.ss { color: #2aa198 } /* Literal.String.Symbol */
.bp { color: #268bd2 } /* Name.Builtin.Pseudo */
.vc { color: #268bd2 } /* Name.Variable.Class */
.vg { color: #268bd2 } /* Name.Variable.Global */
.vi { color: #268bd2 } /* Name.Variable.Instance */
.il { color: #2aa198 } /* Literal.Number.Integer.Long */
} }
/* https://gist.github.com/qguv/7936275 */
.code.solarized-light {
pre.code,
.line-numbers,
.line-numbers a {
background-color: #fdf6e3 !important;
color: #586e75 !important;
}
pre.code {
border-left: 1px solid #c5d0d4;
}
/* Solarized Light
For use with Jekyll and Pygments
http://ethanschoonover.com/solarized
SOLARIZED HEX ROLE
--------- -------- ------------------------------------------
base01 #586e75 body text / default code / primary content
base1 #93a1a1 comments / secondary content
base3 #fdf6e3 background
orange #cb4b16 constants
red #dc322f regex, special keywords
blue #268bd2 reserved keywords
cyan #2aa198 strings, numbers
green #859900 operators, other keywords
*/
.c { color: #93a1a1 } /* Comment */
.err { color: #586e75 } /* Error */
.g { color: #586e75 } /* Generic */
.k { color: #859900 } /* Keyword */
.l { color: #586e75 } /* Literal */
.n { color: #586e75 } /* Name */
.o { color: #859900 } /* Operator */
.x { color: #cb4b16 } /* Other */
.p { color: #586e75 } /* Punctuation */
.cm { color: #93a1a1 } /* Comment.Multiline */
.cp { color: #859900 } /* Comment.Preproc */
.c1 { color: #93a1a1 } /* Comment.Single */
.cs { color: #859900 } /* Comment.Special */
.gd { color: #2aa198 } /* Generic.Deleted */
.ge { color: #586e75; font-style: italic } /* Generic.Emph */
.gr { color: #dc322f } /* Generic.Error */
.gh { color: #cb4b16 } /* Generic.Heading */
.gi { color: #859900 } /* Generic.Inserted */
.go { color: #586e75 } /* Generic.Output */
.gp { color: #586e75 } /* Generic.Prompt */
.gs { color: #586e75; font-weight: bold } /* Generic.Strong */
.gu { color: #cb4b16 } /* Generic.Subheading */
.gt { color: #586e75 } /* Generic.Traceback */
.kc { color: #cb4b16 } /* Keyword.Constant */
.kd { color: #268bd2 } /* Keyword.Declaration */
.kn { color: #859900 } /* Keyword.Namespace */
.kp { color: #859900 } /* Keyword.Pseudo */
.kr { color: #268bd2 } /* Keyword.Reserved */
.kt { color: #dc322f } /* Keyword.Type */
.ld { color: #586e75 } /* Literal.Date */
.m { color: #2aa198 } /* Literal.Number */
.s { color: #2aa198 } /* Literal.String */
.na { color: #586e75 } /* Name.Attribute */
.nb { color: #B58900 } /* Name.Builtin */
.nc { color: #268bd2 } /* Name.Class */
.no { color: #cb4b16 } /* Name.Constant */
.nd { color: #268bd2 } /* Name.Decorator */
.ni { color: #cb4b16 } /* Name.Entity */
.ne { color: #cb4b16 } /* Name.Exception */
.nf { color: #268bd2 } /* Name.Function */
.nl { color: #586e75 } /* Name.Label */
.nn { color: #586e75 } /* Name.Namespace */
.nx { color: #586e75 } /* Name.Other */
.py { color: #586e75 } /* Name.Property */
.nt { color: #268bd2 } /* Name.Tag */
.nv { color: #268bd2 } /* Name.Variable */
.ow { color: #859900 } /* Operator.Word */
.w { color: #586e75 } /* Text.Whitespace */
.mf { color: #2aa198 } /* Literal.Number.Float */
.mh { color: #2aa198 } /* Literal.Number.Hex */
.mi { color: #2aa198 } /* Literal.Number.Integer */
.mo { color: #2aa198 } /* Literal.Number.Oct */
.sb { color: #93a1a1 } /* Literal.String.Backtick */
.sc { color: #2aa198 } /* Literal.String.Char */
.sd { color: #586e75 } /* Literal.String.Doc */
.s2 { color: #2aa198 } /* Literal.String.Double */
.se { color: #cb4b16 } /* Literal.String.Escape */
.sh { color: #586e75 } /* Literal.String.Heredoc */
.si { color: #2aa198 } /* Literal.String.Interpol */
.sx { color: #2aa198 } /* Literal.String.Other */
.sr { color: #dc322f } /* Literal.String.Regex */
.s1 { color: #2aa198 } /* Literal.String.Single */
.ss { color: #2aa198 } /* Literal.String.Symbol */
.bp { color: #268bd2 } /* Name.Builtin.Pseudo */
.vc { color: #268bd2 } /* Name.Variable.Class */
.vg { color: #268bd2 } /* Name.Variable.Global */
.vi { color: #268bd2 } /* Name.Variable.Instance */
.il { color: #2aa198 } /* Literal.Number.Integer.Long */
}
.white { /* https://github.com/aahan/pygments-github-style */
.line.hll { .code.white {
background: #FFA;
}
pre {
background-color: #fff;
color: #333;
}
.hljs {
background: #FFF;
}
pre.highlight,
.line-numbers,
.line-numbers a { .line-numbers a {
color: #999; background-color: #fff !important;
} color: #333 !important;
}
.hljs {
display: block; pre.code {
background: #fff; color: black; border-left: 1px solid #bbb;
} }
.hljs-comment, .hll { background-color: #f8f8f8 }
.hljs-template_comment, .c { color: #999988; font-style: italic; }
.hljs-javadoc, .err { color: #a61717; background-color: #e3d2d2; }
.hljs-comment * { .k { font-weight: bold; }
color: #006a00; .o { font-weight: bold; }
} .cm { color: #999988; font-style: italic; }
.cp { color: #999999; font-weight: bold; }
.hljs-keyword, .c1 { color: #999988; font-style: italic; }
.hljs-literal, .cs { color: #999999; font-weight: bold; font-style: italic; }
.nginx .hljs-title { .gd { color: #000000; background-color: #ffdddd; }
color: #aa0d91; .gd .x { color: #000000; background-color: #ffaaaa; }
} .ge { font-style: italic; }
.method, .gr { color: #aa0000; }
.hljs-list .hljs-title, .gh { color: #999999; }
.hljs-tag .hljs-title, .gi { color: #000000; background-color: #ddffdd; }
.setting .hljs-value, .gi .x { color: #000000; background-color: #aaffaa; }
.hljs-winutils, .go { color: #888888; }
.tex .hljs-command, .gp { color: #555555; }
.http .hljs-title, .gs { font-weight: bold; }
.hljs-request, .gu { color: #800080; font-weight: bold; }
.hljs-status { .gt { color: #aa0000; }
color: #008; .kc { font-weight: bold; }
} .kd { font-weight: bold; }
.kn { font-weight: bold; }
.hljs-envvar, .kp { font-weight: bold; }
.tex .hljs-special { .kr { font-weight: bold; }
color: #660; .kt { color: #445588; font-weight: bold; }
} .m { color: #009999; }
.s { color: #dd1144; }
.hljs-string { .n { color: #333333; }
color: #c41a16; .na { color: teal; }
} .nb { color: #0086b3; }
.hljs-tag .hljs-value, .nc { color: #445588; font-weight: bold; }
.hljs-cdata, .no { color: teal; }
.hljs-filter .hljs-argument, .ni { color: purple; }
.hljs-attr_selector, .ne { color: #990000; font-weight: bold; }
.apache .hljs-cbracket, .nf { color: #990000; font-weight: bold; }
.hljs-date, .nn { color: #555555; }
.hljs-regexp { .nt { color: navy; }
color: #080; .nv { color: teal; }
} .ow { font-weight: bold; }
.w { color: #bbbbbb; }
.hljs-sub .hljs-identifier, .mf { color: #009999; }
.hljs-pi, .mh { color: #009999; }
.hljs-tag, .mi { color: #009999; }
.hljs-tag .hljs-keyword, .mo { color: #009999; }
.hljs-decorator, .sb { color: #dd1144; }
.ini .hljs-title, .sc { color: #dd1144; }
.hljs-shebang, .sd { color: #dd1144; }
.hljs-prompt, .s2 { color: #dd1144; }
.hljs-hexcolor, .se { color: #dd1144; }
.hljs-rules .hljs-value, .sh { color: #dd1144; }
.hljs-symbol, .si { color: #dd1144; }
.hljs-symbol .hljs-string, .sx { color: #dd1144; }
.hljs-number, .sr { color: #009926; }
.css .hljs-function, .s1 { color: #dd1144; }
.clojure .hljs-title, .ss { color: #990073; }
.clojure .hljs-built_in, .bp { color: #999999; }
.hljs-function .hljs-title, .vc { color: teal; }
.coffeescript .hljs-attribute { .vg { color: teal; }
color: #1c00cf; .vi { color: teal; }
} .il { color: #009999; }
.gc { color: #999; background-color: #EAF2F5; }
.hljs-class .hljs-title,
.haskell .hljs-type,
.smalltalk .hljs-class,
.hljs-javadoctag,
.hljs-yardoctag,
.hljs-phpdoc,
.hljs-typename,
.hljs-tag .hljs-attribute,
.hljs-doctype,
.hljs-class .hljs-id,
.hljs-built_in,
.setting,
.hljs-params,
.clojure .hljs-attribute {
color: #5c2699;
}
.hljs-variable {
color: #3f6e74;
}
.css .hljs-tag,
.hljs-rules .hljs-property,
.hljs-pseudo,
.hljs-subst {
color: #000;
}
.css .hljs-class,
.css .hljs-id {
color: #9B703F;
}
.hljs-value .hljs-important {
color: #ff7700;
font-weight: bold;
}
.hljs-rules .hljs-keyword {
color: #C5AF75;
}
.hljs-annotation,
.apache .hljs-sqbracket,
.nginx .hljs-built_in {
color: #9B859D;
}
.hljs-preprocessor,
.hljs-preprocessor *,
.hljs-pragma {
color: #643820;
}
.tex .hljs-formula {
background-color: #EEE;
font-style: italic;
}
.diff .hljs-header,
.hljs-chunk {
color: #808080;
font-weight: bold;
}
.diff .hljs-change {
background-color: #BCCFF9;
}
.hljs-addition {
background-color: #BAEEBA;
}
.hljs-deletion {
background-color: #FFC8BD;
}
.hljs-comment .hljs-yardoctag {
font-weight: bold;
}
.method .hljs-id {
color: #000;
}
}
.shadow {
@include box-shadow(0 5px 15px #000);
}
.file-content {
&.code .white {
.highlight {
border-left: 1px solid #eee;
}
}
&.wiki .white {
.highlight, pre, .hljs {
background: #F9F9F9;
}
}
}
.readme-holder .wiki, .note-body, .wiki-holder {
.white {
.highlight, pre, .hljs {
background: #F9F9F9;
}
}
} }
...@@ -2,6 +2,10 @@ html { ...@@ -2,6 +2,10 @@ html {
overflow-y: scroll; overflow-y: scroll;
&.touch .tooltip { display: none !important; } &.touch .tooltip { display: none !important; }
body {
padding-top: 47px;
}
} }
.container { .container {
...@@ -13,3 +17,6 @@ html { ...@@ -13,3 +17,6 @@ html {
margin: 0 0; margin: 0 0;
} }
.navless-container {
margin-top: 30px;
}
...@@ -69,7 +69,12 @@ ...@@ -69,7 +69,12 @@
margin-top: 0; margin-top: 0;
} }
code { padding: 0 4px; } code {
font-family: $monospace_font;
white-space: pre;
word-wrap: normal;
padding: 0;
}
h1 { h1 {
margin-top: 45px; margin-top: 45px;
......
...@@ -47,3 +47,13 @@ $deleted: #f77; ...@@ -47,3 +47,13 @@ $deleted: #f77;
* NProgress customize * NProgress customize
*/ */
$nprogress-color: #c0392b; $nprogress-color: #c0392b;
/**
* Font sizes
*/
$list-font-size: 15px;
/**
* Sidebar navigation width
*/
$sidebar_width: 230px;
...@@ -139,7 +139,7 @@ ...@@ -139,7 +139,7 @@
*/ */
li.commit { li.commit {
.commit-row-title { .commit-row-title {
font-size: 14px; font-size: $list-font-size;
margin-bottom: 2px; margin-bottom: 2px;
.notes_count { .notes_count {
...@@ -158,7 +158,6 @@ li.commit { ...@@ -158,7 +158,6 @@ li.commit {
.commit-row-message { .commit-row-message {
color: #333; color: #333;
font-weight: 500;
&:hover { &:hover {
color: #444; color: #444;
text-decoration: underline; text-decoration: underline;
......
...@@ -55,11 +55,12 @@ ...@@ -55,11 +55,12 @@
} }
.event-body { .event-body {
margin-left: 35px; margin-left: 35px;
margin-right: 100px; margin-right: 80px;
color: #777; color: #777;
.event-note { .event-note {
margin-top: 5px; margin-top: 5px;
word-wrap: break-word;
.md { .md {
font-size: 13px; font-size: 13px;
...@@ -71,6 +72,7 @@ ...@@ -71,6 +72,7 @@
border-radius: 0; border-radius: 0;
color: #777; color: #777;
margin: 0 20px; margin: 0 20px;
overflow: hidden;
} }
.note-image-attach { .note-image-attach {
......
...@@ -8,8 +8,6 @@ header { ...@@ -8,8 +8,6 @@ header {
margin-bottom: 0; margin-bottom: 0;
min-height: 40px; min-height: 40px;
border: none; border: none;
position: fixed;
top: 0;
width: 100%; width: 100%;
.navbar-inner { .navbar-inner {
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
.issue-title { .issue-title {
margin-bottom: 5px; margin-bottom: 5px;
font-size: 14px; font-size: $list-font-size;
} }
.issue-info { .issue-info {
...@@ -166,3 +166,7 @@ form.edit-issue { ...@@ -166,3 +166,7 @@ form.edit-issue {
.issue-title { .issue-title {
margin-top: 0; margin-top: 0;
} }
.context .select2-container {
width: 100% !important;
}
.markdown-area {
background: #FFF;
border: 1px solid #ddd;
min-height: 100px;
padding: 5px;
font-size: 14px;
box-shadow: none;
width: 100%;
}
...@@ -88,7 +88,7 @@ ...@@ -88,7 +88,7 @@
.merge-request-title { .merge-request-title {
margin-bottom: 5px; margin-bottom: 5px;
font-size: 14px; font-size: $list-font-size;
} }
.merge-request-info { .merge-request-info {
......
.page-with-sidebar { .page-with-sidebar {
background: #F5F5F5; background: #F5F5F5;
.sidebar-wrapper {
position: fixed;
top: 0;
left: 0;
height: 100%;
border-right: 1px solid #EAEAEA;
}
} }
.sidebar-wrapper { .sidebar-wrapper {
...@@ -12,7 +22,6 @@ ...@@ -12,7 +22,6 @@
width: 100%; width: 100%;
padding: 15px; padding: 15px;
background: #FFF; background: #FFF;
margin-top: 48px;
} }
.nav-sidebar { .nav-sidebar {
...@@ -93,22 +102,17 @@ ...@@ -93,22 +102,17 @@
@mixin expanded-sidebar { @mixin expanded-sidebar {
.page-with-sidebar { .page-with-sidebar {
padding-left: 250px; padding-left: $sidebar_width;
} }
.sidebar-wrapper { .sidebar-wrapper {
width: 250px; width: $sidebar_width;
position: fixed;
left: 250px;
height: 100%;
margin-left: -250px;
border-right: 1px solid #EAEAEA;
.nav-sidebar { .nav-sidebar {
margin-top: 20px; margin-top: 20px;
position: fixed; position: fixed;
top: 45px; top: 45px;
width: 250px; width: $sidebar_width;
} }
} }
...@@ -124,11 +128,6 @@ ...@@ -124,11 +128,6 @@
.sidebar-wrapper { .sidebar-wrapper {
width: 52px; width: 52px;
position: fixed;
top: 0;
left: 0;
height: 100%;
border-right: 1px solid #EAEAEA;
overflow-x: hidden; overflow-x: hidden;
.nav-sidebar { .nav-sidebar {
...@@ -151,11 +150,10 @@ ...@@ -151,11 +150,10 @@
} }
} }
@media (max-width: $screen-sm-max) { @media (max-width: $screen-md-max) {
@include folded-sidebar; @include folded-sidebar;
} }
@media(min-width: $screen-sm-max) { @media(min-width: $screen-md-max) {
@include expanded-sidebar; @include expanded-sidebar;
} }
/**
* Note Form
*/
.comment-btn {
@extend .btn-create;
}
.reply-btn {
@extend .btn-primary;
}
.diff-file .diff-content {
tr.line_holder:hover {
&> td.line_content {
background: $hover !important;
border-color: darken($hover, 10%) !important;
}
&> td.new_line,
&> td.old_line {
background: darken($hover, 4%) !important;
border-color: darken($hover, 10%) !important;
}
}
tr.line_holder:hover > td .line_note_link {
opacity: 1.0;
filter: alpha(opacity=100);
}
}
.diff-file,
.discussion {
.new_note {
margin: 0;
border: none;
}
}
.new_note {
display: none;
}
.new_note, .edit_note {
.buttons {
float: left;
margin-top: 8px;
}
.clearfix {
margin-bottom: 0;
}
.note-preview-holder {
> p {
overflow-x: auto;
}
}
.note_text {
width: 100%;
}
}
/* loading indicator */
.notes-busy {
margin: 18px;
}
.note-image-attach {
@extend .col-md-4;
@extend .thumbnail;
margin-left: 45px;
float: none;
}
.common-note-form {
margin: 0;
background: #F9F9F9;
padding: 5px;
border: 1px solid #DDD;
}
.note-form-actions {
background: #F9F9F9;
height: 45px;
.note-form-option {
margin-top: 8px;
margin-left: 30px;
@extend .pull-left;
}
.js-notify-commit-author {
float: left;
}
.write-preview-btn {
// makes the "absolute" position for links relative to this
position: relative;
// preview/edit buttons
> a {
position: absolute;
right: 5px;
top: 8px;
}
}
}
.note-edit-form {
display: none;
font-size: 13px;
.form-actions {
padding-left: 20px;
.btn-save {
float: left;
}
.note-form-option {
float: left;
padding: 2px 0 0 25px;
}
}
}
.js-note-attachment-delete {
display: none;
}
.parallel-comment {
padding: 6px;
}
.error-alert > .alert {
margin-top: 5px;
margin-bottom: 5px;
}
.discussion-body,
.diff-file {
.notes .note {
border-color: #ddd;
padding: 10px 15px;
}
.discussion-reply-holder {
background: #f9f9f9;
padding: 10px 15px;
border-top: 1px solid #DDD;
}
}
.discussion-notes-count {
font-size: 16px;
}
.edit_note {
.markdown-area {
min-height: 140px;
}
.note-form-actions {
background: transparent;
}
}
.comment-hints {
color: #999;
background: #FFF;
padding: 5px;
margin-top: -7px;
border: 1px solid #DDD;
font-size: 13px;
}
...@@ -61,8 +61,12 @@ ul.notes { ...@@ -61,8 +61,12 @@ ul.notes {
font-size: 14px; font-size: 14px;
} }
.note-body { .note-body {
@include md-typography;
overflow: auto; overflow: auto;
.note-text {
overflow: auto;
word-wrap: break-word;
@include md-typography;
}
} }
.note-header { .note-header {
padding-bottom: 3px; padding-bottom: 3px;
...@@ -190,169 +194,3 @@ ul.notes { ...@@ -190,169 +194,3 @@ ul.notes {
} }
} }
/**
* Note Form
*/
.comment-btn {
@extend .btn-create;
}
.reply-btn {
@extend .btn-primary;
}
.diff-file .diff-content {
tr.line_holder:hover {
&> td.line_content {
background: $hover !important;
border-color: darken($hover, 10%) !important;
}
&> td.new_line,
&> td.old_line {
background: darken($hover, 4%) !important;
border-color: darken($hover, 10%) !important;
}
}
tr.line_holder:hover > td .line_note_link {
opacity: 1.0;
filter: alpha(opacity=100);
}
}
.diff-file,
.discussion {
.new_note {
margin: 0;
border: none;
}
}
.new_note {
display: none;
.buttons {
float: left;
margin-top: 8px;
}
.clearfix {
margin-bottom: 0;
}
.note_text {
background: #FFF;
border: 1px solid #ddd;
min-height: 100px;
padding: 5px;
font-size: 14px;
box-shadow: none;
}
.note-preview-holder {
> p {
overflow-x: auto;
}
}
.note_text {
width: 100%;
}
}
/* loading indicator */
.notes-busy {
margin: 18px;
}
.note-image-attach {
@extend .col-md-4;
@extend .thumbnail;
margin-left: 45px;
float: none;
}
.common-note-form {
margin: 0;
background: #F9F9F9;
padding: 5px;
border: 1px solid #DDD;
}
.note-form-actions {
background: #F9F9F9;
height: 45px;
.note-form-option {
margin-top: 8px;
margin-left: 30px;
@extend .pull-left;
}
.js-notify-commit-author {
float: left;
}
.write-preview-btn {
// makes the "absolute" position for links relative to this
position: relative;
// preview/edit buttons
> a {
position: absolute;
right: 5px;
top: 8px;
}
}
}
.note-edit-form {
display: none;
.note_text {
border: 1px solid #DDD;
box-shadow: none;
font-size: 14px;
height: 80px;
width: 100%;
}
.form-actions {
padding-left: 20px;
.btn-save {
float: left;
}
.note-form-option {
float: left;
padding: 2px 0 0 25px;
}
}
}
.js-note-attachment-delete {
display: none;
}
.parallel-comment {
padding: 6px;
}
.error-alert > .alert {
margin-top: 5px;
margin-bottom: 5px;
}
.discussion-body,
.diff-file {
.notes .note {
border-color: #ddd;
padding: 10px 15px;
}
.discussion-reply-holder {
background: #f9f9f9;
padding: 10px 15px;
border-top: 1px solid #DDD;
}
}
.discussion-notes-count {
font-size: 16px;
}
...@@ -111,20 +111,3 @@ ...@@ -111,20 +111,3 @@
height: 50px; height: 50px;
} }
} }
//CSS for password-strength indicator
#password-strength {
margin-bottom: 0;
}
.has-success input {
background-color: #D6F1D7 !important;
}
.has-error input {
background-color: #F3CECE !important;
}
.has-warning input {
background-color: #FFE9A4 !important;
}
...@@ -296,20 +296,6 @@ ul.nav.nav-projects-tabs { ...@@ -296,20 +296,6 @@ ul.nav.nav-projects-tabs {
} }
} }
@media (max-width: $screen-xs-max) {
.project-home-panel {
.star-fork-buttons {
padding-top: 10px;
padding-right: 15px;
}
}
.project-home-links {
display: none;
}
}
table.table.protected-branches-list tr.no-border { table.table.protected-branches-list tr.no-border {
th, td { th, td {
border: 0; border: 0;
......
...@@ -98,6 +98,11 @@ ...@@ -98,6 +98,11 @@
background: #f1f1f1; background: #f1f1f1;
border-left: 1px solid #DDD; border-left: 1px solid #DDD;
} }
td.lines {
code {
font-family: $monospace_font;
}
}
} }
} }
......
...@@ -26,6 +26,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController ...@@ -26,6 +26,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
:signin_enabled, :signin_enabled,
:gravatar_enabled, :gravatar_enabled,
:sign_in_text, :sign_in_text,
:home_page_url
) )
end end
end end
class Admin::ApplicationsController < Admin::ApplicationController
before_action :set_application, only: [:show, :edit, :update, :destroy]
def index
@applications = Doorkeeper::Application.where("owner_id IS NULL")
end
def show
end
def new
@application = Doorkeeper::Application.new
end
def edit
end
def create
@application = Doorkeeper::Application.new(application_params)
if @application.save
flash[:notice] = I18n.t(:notice, scope: [:doorkeeper, :flash, :applications, :create])
redirect_to admin_application_url(@application)
else
render :new
end
end
def update
if @application.update(application_params)
redirect_to admin_application_path(@application), notice: 'Application was successfully updated.'
else
render :edit
end
end
def destroy
@application.destroy
redirect_to admin_applications_url, notice: 'Application was successfully destroyed.'
end
private
def set_application
@application = Doorkeeper::Application.where("owner_id IS NULL").find(params[:id])
end
# Only allow a trusted parameter "white list" through.
def application_params
params[:doorkeeper_application].permit(:name, :redirect_uri)
end
end
...@@ -48,6 +48,17 @@ class ApplicationController < ActionController::Base ...@@ -48,6 +48,17 @@ class ApplicationController < ActionController::Base
end end
end end
def authenticate_user!(*args)
# If user is not signe-in and tries to access root_path - redirect him to landing page
if current_application_settings.home_page_url.present?
if current_user.nil? && controller_name == 'dashboard' && action_name == 'show'
redirect_to current_application_settings.home_page_url and return
end
end
super(*args)
end
def log_exception(exception) def log_exception(exception)
application_trace = ActionDispatch::ExceptionWrapper.new(env, exception).application_trace application_trace = ActionDispatch::ExceptionWrapper.new(env, exception).application_trace
application_trace.map!{ |t| " #{t}\n" } application_trace.map!{ |t| " #{t}\n" }
......
...@@ -22,6 +22,11 @@ class GithubImportsController < ApplicationController ...@@ -22,6 +22,11 @@ class GithubImportsController < ApplicationController
@repos.reject!{|repo| already_added_projects_names.include? repo.full_name} @repos.reject!{|repo| already_added_projects_names.include? repo.full_name}
end end
def jobs
jobs = current_user.created_projects.where(import_type: "github").to_json(:only => [:id, :import_status])
render json: jobs
end
def create def create
@repo_id = params[:repo_id].to_i @repo_id = params[:repo_id].to_i
repo = octo_client.repo(@repo_id) repo = octo_client.repo(@repo_id)
...@@ -42,7 +47,7 @@ class GithubImportsController < ApplicationController ...@@ -42,7 +47,7 @@ class GithubImportsController < ApplicationController
namespace.add_owner(current_user) namespace.add_owner(current_user)
end end
Gitlab::Github::ProjectCreator.new(repo, namespace, current_user).execute @project = Gitlab::Github::ProjectCreator.new(repo, namespace, current_user).execute
end end
private private
......
...@@ -9,10 +9,8 @@ class Oauth::ApplicationsController < Doorkeeper::ApplicationsController ...@@ -9,10 +9,8 @@ class Oauth::ApplicationsController < Doorkeeper::ApplicationsController
def create def create
@application = Doorkeeper::Application.new(application_params) @application = Doorkeeper::Application.new(application_params)
if Doorkeeper.configuration.confirm_application_owner? @application.owner = current_user
@application.owner = current_user
end
if @application.save if @application.save
flash[:notice] = I18n.t(:notice, scope: [:doorkeeper, :flash, :applications, :create]) flash[:notice] = I18n.t(:notice, scope: [:doorkeeper, :flash, :applications, :create])
redirect_to oauth_application_url(@application) redirect_to oauth_application_url(@application)
......
...@@ -12,6 +12,7 @@ class Projects::CommitController < Projects::ApplicationController ...@@ -12,6 +12,7 @@ class Projects::CommitController < Projects::ApplicationController
@line_notes = @project.notes.for_commit_id(commit.id).inline @line_notes = @project.notes.for_commit_id(commit.id).inline
@branches = @project.repository.branch_names_contains(commit.id) @branches = @project.repository.branch_names_contains(commit.id)
@tags = @project.repository.tag_names_contains(commit.id)
@diffs = @commit.diffs @diffs = @commit.diffs
@note = @project.build_commit_note(commit) @note = @project.build_commit_note(commit)
@notes_count = @project.notes.for_commit_id(commit.id).count @notes_count = @project.notes.for_commit_id(commit.id).count
......
...@@ -233,13 +233,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -233,13 +233,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end end
def allowed_to_push_code?(project, branch) def allowed_to_push_code?(project, branch)
action = if project.protected_branch?(branch) ::Gitlab::GitAccess.can_push_to_branch?(current_user, project, branch)
:push_code_to_protected_branches
else
:push_code
end
can?(current_user, action, project)
end end
def merge_request_params def merge_request_params
......
...@@ -15,11 +15,11 @@ class RegistrationsController < Devise::RegistrationsController ...@@ -15,11 +15,11 @@ class RegistrationsController < Devise::RegistrationsController
super super
end end
def after_sign_up_path_for(resource) def after_sign_up_path_for(_resource)
new_user_session_path new_user_session_path
end end
def after_inactive_sign_up_path_for(resource) def after_inactive_sign_up_path_for(_resource)
new_user_session_path new_user_session_path
end end
......
...@@ -5,8 +5,9 @@ module ApplicationHelper ...@@ -5,8 +5,9 @@ module ApplicationHelper
COLOR_SCHEMES = { COLOR_SCHEMES = {
1 => 'white', 1 => 'white',
2 => 'dark', 2 => 'dark',
3 => 'solarized-dark', 3 => 'solarized-light',
4 => 'monokai', 4 => 'solarized-dark',
5 => 'monokai',
} }
COLOR_SCHEMES.default = 'white' COLOR_SCHEMES.default = 'white'
...@@ -189,20 +190,6 @@ module ApplicationHelper ...@@ -189,20 +190,6 @@ module ApplicationHelper
BroadcastMessage.current BroadcastMessage.current
end end
def highlight_js(&block)
string = capture(&block)
content_tag :div, class: "highlighted-data #{user_color_scheme_class}" do
content_tag :div, class: 'highlight' do
content_tag :pre do
content_tag :code do
string.html_safe
end
end
end
end
end
def time_ago_with_tooltip(date, placement = 'top', html_class = 'time_ago') def time_ago_with_tooltip(date, placement = 'top', html_class = 'time_ago')
capture_haml do capture_haml do
haml_tag :time, date.to_s, haml_tag :time, date.to_s,
...@@ -305,9 +292,4 @@ module ApplicationHelper ...@@ -305,9 +292,4 @@ module ApplicationHelper
profile_key_path(key) profile_key_path(key)
end end
end end
def redirect_from_root?
request.env['rack.session']['user_return_to'] ==
'/'
end
end end
module BlobHelper module BlobHelper
def highlightjs_class(blob_name) def highlight(blob_name, blob_content, nowrap = false)
if no_highlight_files.include?(blob_name.downcase) formatter = Rugments::Formatters::HTML.new(
'no-highlight' nowrap: nowrap,
else cssclass: 'code highlight',
blob_name.downcase lineanchors: true,
lineanchorsid: 'LC'
)
begin
lexer = Rugments::Lexer.guess(filename: blob_name, source: blob_content)
rescue Rugments::Lexer::AmbiguousGuess
lexer = Rugments::Lexers::PlainText
end end
formatter.format(lexer.lex(blob_content)).html_safe
end end
def no_highlight_files def no_highlight_files
......
...@@ -11,13 +11,8 @@ module BranchesHelper ...@@ -11,13 +11,8 @@ module BranchesHelper
def can_push_branch?(project, branch_name) def can_push_branch?(project, branch_name)
return false unless project.repository.branch_names.include?(branch_name) return false unless project.repository.branch_names.include?(branch_name)
action = if project.protected_branch?(branch_name)
:push_code_to_protected_branches ::Gitlab::GitAccess.can_push_to_branch?(current_user, project, branch_name)
else
:push_code
end
current_user.can?(action, project)
end end
def can_rebase?(project, branch_name) def can_rebase?(project, branch_name)
......
...@@ -65,6 +65,12 @@ module CommitsHelper ...@@ -65,6 +65,12 @@ module CommitsHelper
branches.sort.map { |branch| link_to(branch, project_tree_path(project, branch)) }.join(", ").html_safe branches.sort.map { |branch| link_to(branch, project_tree_path(project, branch)) }.join(", ").html_safe
end end
# Returns the sorted links to tags, separated by a comma
def commit_tags_links(project, tags)
sorted = VersionSorter.rsort(tags)
sorted.map { |tag| link_to(tag, project_commits_path(project, project.repository.find_tag(tag).name)) }.join(", ").html_safe
end
def link_to_browse_code(project, commit) def link_to_browse_code(project, commit)
if current_controller?(:projects, :commits) if current_controller?(:projects, :commits)
if @repo.blob_at(commit.id, @path) if @repo.blob_at(commit.id, @path)
......
...@@ -135,4 +135,19 @@ module DiffHelper ...@@ -135,4 +135,19 @@ module DiffHelper
'Side-by-side' 'Side-by-side'
end end
end end
def submodule_link(blob, ref)
tree, commit = submodule_links(blob, ref)
commit_id = if commit.nil?
blob.id[0..10]
else
link_to "#{blob.id[0..10]}", commit
end
[
content_tag(:span, link_to(truncate(blob.name, length: 40), tree)),
'@',
content_tag(:span, commit_id, class: 'monospace'),
].join(' ').html_safe
end
end end
...@@ -29,4 +29,14 @@ module EmailsHelper ...@@ -29,4 +29,14 @@ module EmailsHelper
end end
end end
end end
def add_email_highlight_css
Rugments::Themes::Github.render(:scope => '.highlight')
end
def color_email_diff(diffcontent)
formatter = Rugments::Formatters::HTML.new(cssclass: 'highlight')
lexer = Rugments::Lexers::Diff.new
raw formatter.format(lexer.lex(diffcontent))
end
end end
...@@ -67,8 +67,10 @@ module IssuesHelper ...@@ -67,8 +67,10 @@ module IssuesHelper
ts = "#{time_ago_with_tooltip(issue.created_at, 'bottom', 'note_created_ago')}" ts = "#{time_ago_with_tooltip(issue.created_at, 'bottom', 'note_created_ago')}"
if issue.updated_at != issue.created_at if issue.updated_at != issue.created_at
ts << capture_haml do ts << capture_haml do
haml_tag :small do haml_tag :span do
haml_concat " (Edited #{time_ago_with_tooltip(issue.updated_at, 'bottom', 'issue_edited_ago')})" haml_concat '&middot;'
haml_concat '<i class="fa fa-edit" title="edited"></i> '
haml_concat time_ago_with_tooltip(issue.updated_at, 'bottom', 'issue_edited_ago')
end end
end end
end end
......
...@@ -20,8 +20,10 @@ module NotesHelper ...@@ -20,8 +20,10 @@ module NotesHelper
ts = "#{time_ago_with_tooltip(note.created_at, 'bottom', 'note_created_ago')}" ts = "#{time_ago_with_tooltip(note.created_at, 'bottom', 'note_created_ago')}"
if note.updated_at != note.created_at if note.updated_at != note.created_at
ts << capture_haml do ts << capture_haml do
haml_tag :small do haml_tag :span do
haml_concat " (Edited #{time_ago_with_tooltip(note.updated_at, 'bottom', 'note_edited_ago')})" haml_concat '&middot;'
haml_concat '<i class="fa fa-edit" title="edited"></i> '
haml_concat time_ago_with_tooltip(note.updated_at, 'bottom', 'note_edited_ago')
end end
end end
end end
......
...@@ -234,8 +234,10 @@ module ProjectsHelper ...@@ -234,8 +234,10 @@ module ProjectsHelper
def hidden_pass_url(original_url) def hidden_pass_url(original_url)
result = URI(original_url) result = URI(original_url)
result.password = '*****' if result.password.present? result.password = '*****' unless result.password.nil?
result result
rescue
original_url
end end
def project_wiki_path_with_version(proj, page, version, is_newest) def project_wiki_path_with_version(proj, page, version, is_newest)
......
...@@ -2,8 +2,8 @@ module SubmoduleHelper ...@@ -2,8 +2,8 @@ module SubmoduleHelper
include Gitlab::ShellAdapter include Gitlab::ShellAdapter
# links to files listing for submodule if submodule is a project on this server # links to files listing for submodule if submodule is a project on this server
def submodule_links(submodule_item) def submodule_links(submodule_item, ref = nil)
url = @repository.submodule_url_for(@ref, submodule_item.path) url = @repository.submodule_url_for(ref, submodule_item.path)
return url, nil unless url =~ /([^\/:]+\/[^\/]+\.git)\Z/ return url, nil unless url =~ /([^\/:]+\/[^\/]+\.git)\Z/
......
...@@ -58,11 +58,7 @@ module TreeHelper ...@@ -58,11 +58,7 @@ module TreeHelper
ref ||= @ref ref ||= @ref
return false unless project.repository.branch_names.include?(ref) return false unless project.repository.branch_names.include?(ref)
if project.protected_branch? ref ::Gitlab::GitAccess.can_push_to_branch?(current_user, project, ref)
can?(current_user, :push_code_to_protected_branches, project)
else
can?(current_user, :push_code, project)
end
end end
def edit_blob_link(project, ref, path, options = {}) def edit_blob_link(project, ref, path, options = {})
...@@ -108,7 +104,7 @@ module TreeHelper ...@@ -108,7 +104,7 @@ module TreeHelper
end end
end end
def up_dir_path(tree) def up_dir_path
file = File.join(@path, "..") file = File.join(@path, "..")
tree_join(@ref, file) tree_join(@ref, file)
end end
......
class ApplicationSetting < ActiveRecord::Base class ApplicationSetting < ActiveRecord::Base
validates :home_page_url, allow_blank: true,
format: { with: URI::regexp(%w(http https)), message: "should be a valid url" },
if: :home_page_url_column_exist
def self.current def self.current
ApplicationSetting.last ApplicationSetting.last
end end
...@@ -12,4 +16,8 @@ class ApplicationSetting < ActiveRecord::Base ...@@ -12,4 +16,8 @@ class ApplicationSetting < ActiveRecord::Base
sign_in_text: Settings.extra['sign_in_text'], sign_in_text: Settings.extra['sign_in_text'],
) )
end end
def home_page_url_column_exist
ActiveRecord::Base.connection.column_exists?(:application_settings, :home_page_url)
end
end end
...@@ -75,11 +75,11 @@ class Commit ...@@ -75,11 +75,11 @@ class Commit
return no_commit_message if title.blank? return no_commit_message if title.blank?
title_end = title.index(/\n/) title_end = title.index("\n")
if (!title_end && title.length > 100) || (title_end && title_end > 100) if (!title_end && title.length > 100) || (title_end && title_end > 100)
title[0..79] << "&hellip;".html_safe title[0..79] << "&hellip;".html_safe
else else
title.split(/\n/, 2).first title.split("\n", 2).first
end end
end end
...@@ -87,11 +87,11 @@ class Commit ...@@ -87,11 +87,11 @@ class Commit
# #
# cut off, ellipses (`&hellp;`) are prepended to the commit message. # cut off, ellipses (`&hellp;`) are prepended to the commit message.
def description def description
title_end = safe_message.index(/\n/) title_end = safe_message.index("\n")
@description ||= if (!title_end && safe_message.length > 100) || (title_end && title_end > 100) @description ||= if (!title_end && safe_message.length > 100) || (title_end && title_end > 100)
"&hellip;".html_safe << safe_message[80..-1] "&hellip;".html_safe << safe_message[80..-1]
else else
safe_message.split(/\n/, 2)[1].try(:chomp) safe_message.split("\n", 2)[1].try(:chomp)
end end
end end
......
...@@ -91,7 +91,7 @@ class Key < ActiveRecord::Base ...@@ -91,7 +91,7 @@ class Key < ActiveRecord::Base
end end
if cmd_status.zero? if cmd_status.zero?
cmd_output.gsub /([\d\h]{2}:)+[\d\h]{2}/ do |match| cmd_output.gsub /(\h{2}:)+\h{2}/ do |match|
self.fingerprint = match self.fingerprint = match
end end
end end
......
...@@ -190,7 +190,12 @@ class Project < ActiveRecord::Base ...@@ -190,7 +190,12 @@ class Project < ActiveRecord::Base
end end
def search(query) def search(query)
joins(:namespace).where("projects.archived = ?", false).where("projects.name LIKE :query OR projects.path LIKE :query OR namespaces.name LIKE :query OR projects.description LIKE :query", query: "%#{query}%") joins(:namespace).where("projects.archived = ?", false).
where("LOWER(projects.name) LIKE :query OR
LOWER(projects.path) LIKE :query OR
LOWER(namespaces.name) LIKE :query OR
LOWER(projects.description) LIKE :query",
query: "%#{query.try(:downcase)}%")
end end
def search_by_title(query) def search_by_title(query)
......
...@@ -60,9 +60,9 @@ class CampfireService < Service ...@@ -60,9 +60,9 @@ class CampfireService < Service
message << "[#{project.name_with_namespace}] " message << "[#{project.name_with_namespace}] "
message << "#{push[:user_name]} " message << "#{push[:user_name]} "
if before =~ /000000/ if before.include?('000000')
message << "pushed new branch #{ref} \n" message << "pushed new branch #{ref} \n"
elsif after =~ /000000/ elsif after.include?('000000')
message << "removed branch #{ref} \n" message << "removed branch #{ref} \n"
else else
message << "pushed #{push[:total_commits_count]} commits to #{ref}. " message << "pushed #{push[:total_commits_count]} commits to #{ref}. "
......
...@@ -32,8 +32,8 @@ class HipchatService < Service ...@@ -32,8 +32,8 @@ class HipchatService < Service
def fields def fields
[ [
{ type: 'text', name: 'token', placeholder: '' }, { type: 'text', name: 'token', placeholder: 'Room token' },
{ type: 'text', name: 'room', placeholder: '' }, { type: 'text', name: 'room', placeholder: 'Room name or ID' },
{ type: 'text', name: 'server', { type: 'text', name: 'server',
placeholder: 'Leave blank for default. https://hipchat.example.com' } placeholder: 'Leave blank for default. https://hipchat.example.com' }
] ]
...@@ -58,12 +58,12 @@ class HipchatService < Service ...@@ -58,12 +58,12 @@ class HipchatService < Service
message = "" message = ""
message << "#{push[:user_name]} " message << "#{push[:user_name]} "
if before =~ /000000/ if before.include?('000000')
message << "pushed new branch <a href=\""\ message << "pushed new branch <a href=\""\
"#{project.web_url}/commits/#{URI.escape(ref)}\">#{ref}</a>"\ "#{project.web_url}/commits/#{URI.escape(ref)}\">#{ref}</a>"\
" to <a href=\"#{project.web_url}\">"\ " to <a href=\"#{project.web_url}\">"\
"#{project.name_with_namespace.gsub!(/\s/, "")}</a>\n" "#{project.name_with_namespace.gsub!(/\s/, "")}</a>\n"
elsif after =~ /000000/ elsif after.include?('000000')
message << "removed branch #{ref} from <a href=\"#{project.web_url}\">#{project.name_with_namespace.gsub!(/\s/,'')}</a> \n" message << "removed branch #{ref} from <a href=\"#{project.web_url}\">#{project.name_with_namespace.gsub!(/\s/,'')}</a> \n"
else else
message << "pushed to branch <a href=\""\ message << "pushed to branch <a href=\""\
......
...@@ -80,9 +80,9 @@ class PushoverService < Service ...@@ -80,9 +80,9 @@ class PushoverService < Service
before = push_data[:before] before = push_data[:before]
after = push_data[:after] after = push_data[:after]
if before =~ /000000/ if before.include?('000000')
message = "#{push_data[:user_name]} pushed new branch \"#{ref}\"." message = "#{push_data[:user_name]} pushed new branch \"#{ref}\"."
elsif after =~ /000000/ elsif after.include?('000000')
message = "#{push_data[:user_name]} deleted branch \"#{ref}\"." message = "#{push_data[:user_name]} deleted branch \"#{ref}\"."
else else
message = "#{push_data[:user_name]} push to branch \"#{ref}\"." message = "#{push_data[:user_name]} push to branch \"#{ref}\"."
......
...@@ -77,11 +77,11 @@ class SlackMessage ...@@ -77,11 +77,11 @@ class SlackMessage
end end
def new_branch? def new_branch?
before =~ /000000/ before.include?('000000')
end end
def removed_branch? def removed_branch?
after =~ /000000/ after.include?('000000')
end end
def branch_url def branch_url
......
...@@ -312,4 +312,21 @@ class Repository ...@@ -312,4 +312,21 @@ class Repository
[] []
end end
end end
def tag_names_contains(sha)
args = %W(git tag --contains #{sha})
names = Gitlab::Popen.popen(args, path_to_repo).first
if names.respond_to?(:split)
names = names.split("\n").map(&:strip)
names.each do |name|
name.slice! '* '
end
names
else
[]
end
end
end end
...@@ -495,7 +495,7 @@ class User < ActiveRecord::Base ...@@ -495,7 +495,7 @@ class User < ActiveRecord::Base
end end
def temp_oauth_email? def temp_oauth_email?
email =~ /\Atemp-email-for-oauth/ email.start_with?('temp-email-for-oauth')
end end
def public_profile? def public_profile?
...@@ -504,7 +504,7 @@ class User < ActiveRecord::Base ...@@ -504,7 +504,7 @@ class User < ActiveRecord::Base
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
else else
GravatarService.new.execute(email, size) GravatarService.new.execute(email, size)
end end
......
...@@ -3,11 +3,7 @@ require_relative "base_service" ...@@ -3,11 +3,7 @@ require_relative "base_service"
module Files module Files
class CreateService < BaseService class CreateService < BaseService
def execute def execute
allowed = if project.protected_branch?(ref) allowed = Gitlab::GitAccess.can_push_to_branch?(current_user, project, ref)
can?(current_user, :push_code_to_protected_branches, project)
else
can?(current_user, :push_code, project)
end
unless allowed unless allowed
return error("You are not allowed to create file in this branch") return error("You are not allowed to create file in this branch")
......
...@@ -3,11 +3,7 @@ require_relative "base_service" ...@@ -3,11 +3,7 @@ require_relative "base_service"
module Files module Files
class DeleteService < BaseService class DeleteService < BaseService
def execute def execute
allowed = if project.protected_branch?(ref) allowed = ::Gitlab::GitAccess.can_push_to_branch?(current_user, project, ref)
can?(current_user, :push_code_to_protected_branches, project)
else
can?(current_user, :push_code, project)
end
unless allowed unless allowed
return error("You are not allowed to push into this branch") return error("You are not allowed to push into this branch")
......
...@@ -3,11 +3,7 @@ require_relative "base_service" ...@@ -3,11 +3,7 @@ require_relative "base_service"
module Files module Files
class UpdateService < BaseService class UpdateService < BaseService
def execute def execute
allowed = if project.protected_branch?(ref) allowed = ::Gitlab::GitAccess.can_push_to_branch?(current_user, project, ref)
can?(current_user, :push_code_to_protected_branches, project)
else
can?(current_user, :push_code, project)
end
unless allowed unless allowed
return error("You are not allowed to push into this branch") return error("You are not allowed to push into this branch")
......
...@@ -115,23 +115,23 @@ class GitPushService ...@@ -115,23 +115,23 @@ class GitPushService
ref_parts = ref.split('/') ref_parts = ref.split('/')
# Return if this is not a push to a branch (e.g. new commits) # Return if this is not a push to a branch (e.g. new commits)
ref_parts[1] =~ /heads/ && oldrev != Gitlab::Git::BLANK_SHA ref_parts[1].include?('heads') && oldrev != Gitlab::Git::BLANK_SHA
end end
def push_to_new_branch?(ref, oldrev) def push_to_new_branch?(ref, oldrev)
ref_parts = ref.split('/') ref_parts = ref.split('/')
ref_parts[1] =~ /heads/ && oldrev == Gitlab::Git::BLANK_SHA ref_parts[1].include?('heads') && oldrev == Gitlab::Git::BLANK_SHA
end end
def push_remove_branch?(ref, newrev) def push_remove_branch?(ref, newrev)
ref_parts = ref.split('/') ref_parts = ref.split('/')
ref_parts[1] =~ /heads/ && newrev == Gitlab::Git::BLANK_SHA ref_parts[1].include?('heads') && newrev == Gitlab::Git::BLANK_SHA
end end
def push_to_branch?(ref) def push_to_branch?(ref)
ref =~ /refs\/heads/ ref.include?('refs/heads')
end end
def is_default_branch?(ref) def is_default_branch?(ref)
......
...@@ -5,9 +5,12 @@ module MergeRequests ...@@ -5,9 +5,12 @@ module MergeRequests
Note.create_status_change_note(merge_request, merge_request.target_project, current_user, merge_request.state, nil) Note.create_status_change_note(merge_request, merge_request.target_project, current_user, merge_request.state, nil)
end end
def execute_hooks(merge_request) def execute_hooks(merge_request, action = 'open')
if merge_request.project if merge_request.project
hook_data = merge_request.to_hook_data(current_user) hook_data = merge_request.to_hook_data(current_user)
merge_request_url = Gitlab::UrlBuilder.new(:merge_request).build(merge_request.id)
hook_data[:object_attributes][:url] = merge_request_url
hook_data[:object_attributes][:action] = action
merge_request.project.execute_hooks(hook_data, :merge_request_hooks) merge_request.project.execute_hooks(hook_data, :merge_request_hooks)
end end
end end
......
...@@ -9,7 +9,7 @@ module MergeRequests ...@@ -9,7 +9,7 @@ module MergeRequests
event_service.close_mr(merge_request, current_user) event_service.close_mr(merge_request, current_user)
notification_service.close_mr(merge_request, current_user) notification_service.close_mr(merge_request, current_user)
create_note(merge_request) create_note(merge_request)
execute_hooks(merge_request) execute_hooks(merge_request, 'close')
end end
merge_request merge_request
......
...@@ -12,7 +12,7 @@ module MergeRequests ...@@ -12,7 +12,7 @@ module MergeRequests
notification_service.merge_mr(merge_request, current_user) notification_service.merge_mr(merge_request, current_user)
create_merge_event(merge_request, current_user) create_merge_event(merge_request, current_user)
create_note(merge_request) create_note(merge_request)
execute_hooks(merge_request) execute_hooks(merge_request, 'merge')
true true
rescue rescue
......
...@@ -5,7 +5,7 @@ module MergeRequests ...@@ -5,7 +5,7 @@ module MergeRequests
event_service.reopen_mr(merge_request, current_user) event_service.reopen_mr(merge_request, current_user)
notification_service.reopen_mr(merge_request, current_user) notification_service.reopen_mr(merge_request, current_user)
create_note(merge_request) create_note(merge_request)
execute_hooks(merge_request) execute_hooks(merge_request, 'reopen')
merge_request.reload_code merge_request.reload_code
merge_request.mark_as_unchecked merge_request.mark_as_unchecked
end end
......
...@@ -38,7 +38,7 @@ module MergeRequests ...@@ -38,7 +38,7 @@ module MergeRequests
end end
merge_request.notice_added_references(merge_request.project, current_user) merge_request.notice_added_references(merge_request.project, current_user)
execute_hooks(merge_request) execute_hooks(merge_request, 'update')
end end
merge_request merge_request
......
...@@ -118,7 +118,7 @@ class NotificationService ...@@ -118,7 +118,7 @@ class NotificationService
return true unless note.noteable_type.present? return true unless note.noteable_type.present?
# ignore gitlab service messages # ignore gitlab service messages
return true if note.note =~ /\A_Status changed to closed_/ return true if note.note.start_with?('_Status changed to closed_')
return true if note.cross_reference? && note.system == true return true if note.cross_reference? && note.system == true
opts = { noteable_type: note.noteable_type, project_id: note.project_id } opts = { noteable_type: note.noteable_type, project_id: note.project_id }
......
...@@ -25,6 +25,11 @@ ...@@ -25,6 +25,11 @@
= f.label :default_projects_limit, class: 'control-label' = f.label :default_projects_limit, class: 'control-label'
.col-sm-10 .col-sm-10
= f.number_field :default_projects_limit, class: 'form-control' = f.number_field :default_projects_limit, class: 'form-control'
.form-group
= f.label :home_page_url, class: 'control-label'
.col-sm-10
= f.text_field :home_page_url, class: 'form-control', placeholder: 'http://company.example.com'
%span.help-block We will redirect non-logged in users to this page
.form-group .form-group
= f.label :sign_in_text, class: 'control-label' = f.label :sign_in_text, class: 'control-label'
.col-sm-10 .col-sm-10
......
- submit_btn_css ||= 'btn btn-link btn-remove btn-small'
= form_tag admin_application_path(application) do
%input{:name => "_method", :type => "hidden", :value => "delete"}/
= submit_tag 'Destroy', onclick: "return confirm('Are you sure?')", class: submit_btn_css
\ No newline at end of file
= form_for [:admin, @application], url: @url, html: {class: 'form-horizontal', role: 'form'} do |f|
- if application.errors.any?
.alert.alert-danger{"data-alert" => ""}
%p Whoops! Check your form for possible errors
= content_tag :div, class: "form-group#{' has-error' if application.errors[:name].present?}" do
= f.label :name, class: 'col-sm-2 control-label'
.col-sm-10
= f.text_field :name, class: 'form-control'
= doorkeeper_errors_for application, :name
= content_tag :div, class: "form-group#{' has-error' if application.errors[:redirect_uri].present?}" do
= f.label :redirect_uri, class: 'col-sm-2 control-label'
.col-sm-10
= f.text_area :redirect_uri, class: 'form-control'
= doorkeeper_errors_for application, :redirect_uri
%span.help-block
Use one line per URI
- if Doorkeeper.configuration.native_redirect_uri
%span.help-block
Use
%code= Doorkeeper.configuration.native_redirect_uri
for local tests
.form-actions
= f.submit 'Submit', class: "btn btn-primary wide"
= link_to "Cancel", admin_applications_path, class: "btn btn-default"
%h3.page-title Edit application
- @url = admin_application_path(@application)
= render 'form', application: @application
\ No newline at end of file
%h3.page-title
System OAuth applications
%p.light
System OAuth application does not belong to certain user and can be managed only by admins
%hr
%p= link_to 'New Application', new_admin_application_path, class: 'btn btn-success'
%table.table.table-striped
%thead
%tr
%th Name
%th Callback URL
%th Clients
%th
%th
%tbody.oauth-applications
- @applications.each do |application|
%tr{:id => "application_#{application.id}"}
%td= link_to application.name, admin_application_path(application)
%td= application.redirect_uri
%td= application.access_tokens.count
%td= link_to 'Edit', edit_admin_application_path(application), class: 'btn btn-link'
%td= render 'delete_form', application: application
%h3.page-title New application
- @url = admin_applications_path
= render 'form', application: @application
\ No newline at end of file
%h3.page-title
Application: #{@application.name}
%table.table
%tr
%td
Application Id
%td
%code#application_id= @application.uid
%tr
%td
Secret:
%td
%code#secret= @application.secret
%tr
%td
Callback url
%td
- @application.redirect_uri.split.each do |uri|
%div
%span.monospace= uri
.form-actions
= link_to 'Edit', edit_admin_application_path(@application), class: 'btn btn-primary wide pull-left'
= render 'delete_form', application: @application, submit_btn_css: 'btn btn-danger prepend-left-10'
%h3.page-title
Admin area
%p.light
You can manage projects, users and other GitLab data from here.
%hr
.admin-dashboard .admin-dashboard
.row
.col-sm-4
.light-well
%h4 Projects
.data
= link_to admin_projects_path do
%h1= Project.count
%hr
= link_to 'New Project', new_project_path, class: "btn btn-new"
.col-sm-4
.light-well
%h4 Users
.data
= link_to admin_users_path do
%h1= User.count
%hr
= link_to 'New User', new_admin_user_path, class: "btn btn-new"
.col-sm-4
.light-well
%h4 Groups
.data
= link_to admin_groups_path do
%h1= Group.count
%hr
= link_to 'New Group', new_admin_group_path, class: "btn btn-new"
.row.prepend-top-10
.col-md-4
%h4 Latest projects
%hr
- @projects.each do |project|
%p
= link_to project.name_with_namespace, [:admin, project], class: 'str-truncated'
%span.light.pull-right
#{time_ago_with_tooltip(project.created_at)}
.col-md-4
%h4 Latest users
%hr
- @users.each do |user|
%p
= link_to [:admin, user], class: 'str-truncated' do
= user.name
%span.light.pull-right
#{time_ago_with_tooltip(user.created_at)}
.col-md-4
%h4 Latest groups
%hr
- @groups.each do |group|
%p
= link_to [:admin, group], class: 'str-truncated' do
= group.name
%span.light.pull-right
#{time_ago_with_tooltip(group.created_at)}
%br
.row .row
.col-md-4 .col-md-4
%h4 Stats %h4 Statistics
%hr %hr
%p %p
Forks Forks
...@@ -141,3 +79,59 @@ ...@@ -141,3 +79,59 @@
Rails Rails
%span.pull-right %span.pull-right
#{Rails::VERSION::STRING} #{Rails::VERSION::STRING}
%hr
.row
.col-sm-4
.light-well
%h4 Projects
.data
= link_to admin_projects_path do
%h1= Project.count
%hr
= link_to 'New Project', new_project_path, class: "btn btn-new"
.col-sm-4
.light-well
%h4 Users
.data
= link_to admin_users_path do
%h1= User.count
%hr
= link_to 'New User', new_admin_user_path, class: "btn btn-new"
.col-sm-4
.light-well
%h4 Groups
.data
= link_to admin_groups_path do
%h1= Group.count
%hr
= link_to 'New Group', new_admin_group_path, class: "btn btn-new"
.row.prepend-top-10
.col-md-4
%h4 Latest projects
%hr
- @projects.each do |project|
%p
= link_to project.name_with_namespace, [:admin, project], class: 'str-truncated'
%span.light.pull-right
#{time_ago_with_tooltip(project.created_at)}
.col-md-4
%h4 Latest users
%hr
- @users.each do |user|
%p
= link_to [:admin, user], class: 'str-truncated' do
= user.name
%span.light.pull-right
#{time_ago_with_tooltip(user.created_at)}
.col-md-4
%h4 Latest groups
%hr
- @groups.each do |group|
%p
= link_to [:admin, group], class: 'str-truncated' do
= group.name
%span.light.pull-right
#{time_ago_with_tooltip(group.created_at)}
...@@ -6,8 +6,8 @@ ...@@ -6,8 +6,8 @@
.devise-errors .devise-errors
= devise_error_messages! = devise_error_messages!
= f.hidden_field :reset_password_token = f.hidden_field :reset_password_token
.form-group#password-strength %div
= f.password_field :password, class: "form-control top", id: "user_password_recover", placeholder: "New password", required: true = f.password_field :password, class: "form-control top", placeholder: "New password", required: true
%div %div
= f.password_field :password_confirmation, class: "form-control bottom", placeholder: "Confirm new password", required: true = f.password_field :password_confirmation, class: "form-control bottom", placeholder: "Confirm new password", required: true
.clearfix.append-bottom-10 .clearfix.append-bottom-10
......
...@@ -11,8 +11,8 @@ ...@@ -11,8 +11,8 @@
= f.text_field :username, class: "form-control middle", placeholder: "Username", required: true = f.text_field :username, class: "form-control middle", placeholder: "Username", required: true
%div %div
= f.email_field :email, class: "form-control middle", placeholder: "Email", required: true = f.email_field :email, class: "form-control middle", placeholder: "Email", required: true
.form-group#password-strength %div
= f.password_field :password, class: "form-control middle", id: "user_password_sign_up", placeholder: "Password", required: true = f.password_field :password, class: "form-control middle", placeholder: "Password", required: true
%div %div
= f.password_field :password_confirmation, class: "form-control bottom", placeholder: "Confirm password", required: true = f.password_field :password_confirmation, class: "form-control bottom", placeholder: "Confirm password", required: true
%div %div
......
...@@ -12,5 +12,7 @@ ...@@ -12,5 +12,7 @@
target_field.find('input').prop("value", origin_namespace) target_field.find('input').prop("value", origin_namespace)
- else - else
:plain :plain
$("table.import-jobs tbody").prepend($("tr#repo_#{@repo_id}")) job = $("tr#repo_#{@repo_id}")
$("tr#repo_#{@repo_id}").addClass("active").find(".import-actions").html("<i class='fa fa-spinner fa-spin'></i> started") job.attr("id", "project_#{@project.id}")
$("table.import-jobs tbody").prepend(job)
job.addClass("active").find(".import-actions").html("<i class='fa fa-spinner fa-spin'></i> started")
...@@ -3,9 +3,7 @@ ...@@ -3,9 +3,7 @@
Import repositories from GitHub.com Import repositories from GitHub.com
%p.light %p.light
Select projects you want to import. Select projects you want to import.
%span.pull-right
Reload to see the progress.
%hr %hr
%table.table.import-jobs %table.table.import-jobs
...@@ -16,11 +14,11 @@ ...@@ -16,11 +14,11 @@
%th Status %th Status
%tbody %tbody
- @already_added_projects.each do |project| - @already_added_projects.each do |project|
%tr{id: "repo_#{project.id}", class: "#{project_status_css_class(project.import_status)}"} %tr{id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}"}
%td= project.import_source %td= project.import_source
%td %td
%strong= link_to project.name_with_namespace, project %strong= link_to project.name_with_namespace, project
%td %td.job-status
- if project.import_status == 'finished' - if project.import_status == 'finished'
%span.cgreen %span.cgreen
%i.fa.fa-check %i.fa.fa-check
...@@ -33,7 +31,7 @@ ...@@ -33,7 +31,7 @@
%td= repo.full_name %td= repo.full_name
%td.import-target %td.import-target
= repo.full_name = repo.full_name
%td.import-actions %td.import-actions.job-status
= button_tag "Add", class: "btn btn-add-to-import" = button_tag "Add", class: "btn btn-add-to-import"
...@@ -46,3 +44,20 @@ ...@@ -46,3 +44,20 @@
new_namespace = tr.find(".import-target input").prop("value") new_namespace = tr.find(".import-target input").prop("value")
tr.find(".import-target").empty().append(new_namespace + "/" + tr.find(".import-target").data("project_name")) tr.find(".import-target").empty().append(new_namespace + "/" + tr.find(".import-target").data("project_name"))
$.post "#{github_import_url}", {repo_id: id, new_namespace: new_namespace}, dataType: 'script' $.post "#{github_import_url}", {repo_id: id, new_namespace: new_namespace}, dataType: 'script'
setInterval (->
$.get "#{jobs_github_import_path}", (data)->
$.each data, (i, job) ->
job_item = $("#project_" + job.id)
status_field = job_item.find(".job-status")
if job.import_status == 'finished'
job_item.removeClass("active").addClass("success")
status_field.html('<span class="cgreen"><i class="fa fa-check"></i> done</span>')
else if job.import_status == 'started'
status_field.html("<i class='fa fa-spinner fa-spin'></i> started")
else
status_field.html(job.import_status)
), 4000
.documentation.wiki .documentation.wiki
= markdown File.read(Rails.root.join('doc', @category, @file + '.md')) = markdown File.read(Rails.root.join('doc', @category, @file + '.md')).gsub("$your_email", current_user.email)
...@@ -2,7 +2,3 @@ ...@@ -2,7 +2,3 @@
.broadcast-message{ style: broadcast_styling(broadcast_message) } .broadcast-message{ style: broadcast_styling(broadcast_message) }
%i.fa.fa-bullhorn %i.fa.fa-bullhorn
= broadcast_message.message = broadcast_message.message
:css
.sidebar-wrapper .nav-sidebar {
margin-top: 58px;
}
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
= csrf_meta_tags = csrf_meta_tags
= include_gon = include_gon
%meta{name: 'viewport', content: 'width=device-width, initial-scale=1.0'} %meta{name: 'viewport', content: 'width=device-width, initial-scale=1.0'}
%meta{name: 'theme-color', content: '#474D57'}
= render 'layouts/google_analytics' if extra_config.has_key?('google_analytics_id') = render 'layouts/google_analytics' if extra_config.has_key?('google_analytics_id')
= render 'layouts/piwik' if extra_config.has_key?('piwik_url') && extra_config.has_key?('piwik_site_id') = render 'layouts/piwik' if extra_config.has_key?('piwik_url') && extra_config.has_key?('piwik_site_id')
......
%header.navbar.navbar-static-top.navbar-gitlab %header.navbar.navbar-fixed-top.navbar-gitlab
.navbar-inner .navbar-inner
.container .container
%div.app_logo %div.app_logo
......
%header.navbar.navbar-static-top.navbar-gitlab %header.navbar.navbar-fixed-top.navbar-gitlab
.navbar-inner .navbar-inner
.container .container
%div.app_logo %div.app_logo
......
...@@ -6,8 +6,7 @@ ...@@ -6,8 +6,7 @@
= render "layouts/public_head_panel", title: '' = render "layouts/public_head_panel", title: ''
.container.navless-container .container.navless-container
.content .content
- unless redirect_from_root? = render "layouts/flash"
= render "layouts/flash"
.row.prepend-top-20 .row.prepend-top-20
.col-sm-5.pull-right .col-sm-5.pull-right
= yield = yield
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
Projects Projects
= nav_link(controller: :users) do = nav_link(controller: :users) do
= link_to admin_users_path do = link_to admin_users_path do
%i.fa.fa-users %i.fa.fa-user
%span %span
Users Users
= nav_link(controller: :groups) do = nav_link(controller: :groups) do
...@@ -49,3 +49,9 @@ ...@@ -49,3 +49,9 @@
%i.fa.fa-cogs %i.fa.fa-cogs
%span %span
Settings Settings
= nav_link(controller: :applications) do
= link_to admin_applications_path do
%i.fa.fa-cloud
%span
Applications
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
font-size:small; font-size:small;
color:#777 color:#777
} }
#{add_email_highlight_css}
%body %body
%div.content %div.content
= yield = yield
...@@ -24,8 +24,8 @@ ...@@ -24,8 +24,8 @@
%p %p
\— \—
%br %br
- if @project
You're receiving this notification because you are a member of the #{link_to_unless @target_url, @project.name_with_namespace, project_url(@project)} project team.
- if @target_url - if @target_url
#{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
You're receiving this notification because you are a member of the #{link_to_unless @target_url, @project.name_with_namespace, project_url(@project)} project team.
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
= diff.new_path || diff.old_path = diff.new_path || diff.old_path
%hr %hr
%pre %pre
= diff.diff = color_email_diff(diff.diff)
%br %br
- if @compare.timeout - if @compare.timeout
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
= radio_button_tag :notification_level, Notification::N_MENTION, @notification.mention?, class: 'trigger-submit' = radio_button_tag :notification_level, Notification::N_MENTION, @notification.mention?, class: 'trigger-submit'
.level-title .level-title
Mention Mention
%p You will receive notifications only for comments where you was @mentioned %p You will receive notifications only for comments in which you were @mentioned
.radio .radio
= label_tag nil, class: '' do = label_tag nil, class: '' do
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
.form-group .form-group
= f.label :password, 'New password', class: 'control-label' = f.label :password, 'New password', class: 'control-label'
.col-sm-10 .col-sm-10
= f.password_field :password, required: true, class: 'form-control', id: 'user_password_profile' = f.password_field :password, required: true, class: 'form-control'
.form-group .form-group
= f.label :password_confirmation, class: 'control-label' = f.label :password_confirmation, class: 'control-label'
.col-sm-10 .col-sm-10
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
.col-sm-10= f.password_field :current_password, required: true, class: 'form-control' .col-sm-10= f.password_field :current_password, required: true, class: 'form-control'
.form-group .form-group
= f.label :password, class: 'control-label' = f.label :password, class: 'control-label'
.col-sm-10= f.password_field :password, required: true, class: 'form-control', id: 'user_password_profile' .col-sm-10= f.password_field :password, required: true, class: 'form-control'
.form-group .form-group
= f.label :password_confirmation, class: 'control-label' = f.label :password_confirmation, class: 'control-label'
.col-sm-10 .col-sm-10
......
.file-holder.file
.file-title
%i.icon-file
%span.file_name
%span.monospace.light #{ref}
- if local_assigns[:path]
= ': ' + local_assigns[:path]
.file-content.code
%pre.js-edit-mode-pane#editor
= params[:content] || local_assigns[:blob_data]
- if local_assigns[:path]
.js-edit-mode-pane#preview.hide
.center
%h2
%i.icon-spinner.icon-spin
...@@ -19,11 +19,6 @@ ...@@ -19,11 +19,6 @@
Labels Labels
- if current_controller?(:milestones)
%li.pull-right
%button.btn.btn-default.sidebar-expand-button
%i.icon.fa.fa-list
- if current_controller?(:issues) - if current_controller?(:issues)
- if current_user - if current_user
%li.hidden-xs %li.hidden-xs
...@@ -32,9 +27,6 @@ ...@@ -32,9 +27,6 @@
%li.pull-right %li.pull-right
.pull-right .pull-right
%button.btn.btn-default.sidebar-expand-button
%i.icon.fa.fa-list
.pull-left .pull-left
= form_tag project_issues_path(@project), method: :get, id: "issue_search_form", class: 'pull-left issue-search-form' do = form_tag project_issues_path(@project), method: :get, id: "issue_search_form", class: 'pull-left issue-search-form' do
.append-right-10.hidden-xs.hidden-sm .append-right-10.hidden-xs.hidden-sm
...@@ -53,9 +45,6 @@ ...@@ -53,9 +45,6 @@
- if current_controller?(:merge_requests) - if current_controller?(:merge_requests)
%li.pull-right %li.pull-right
.pull-right .pull-right
%button.btn.btn-default.sidebar-expand-button
%i.icon.fa.fa-list
- if can? current_user, :write_merge_request, @project - if can? current_user, :write_merge_request, @project
= link_to new_project_merge_request_path(@project), class: "btn btn-new pull-left", title: "New Merge Request" do = link_to new_project_merge_request_path(@project), class: "btn btn-new pull-left", title: "New Merge Request" do
%i.fa.fa-plus %i.fa.fa-plus
......
.zennable .zennable
%input#zen-toggle-comment{ tabindex: '-1', type: 'checkbox' } %input#zen-toggle-comment.zen-toggle-comment{ tabindex: '-1', type: 'checkbox' }
.zen-backdrop .zen-backdrop
- classes << ' js-gfm-input markdown-area' - classes << ' js-gfm-input markdown-area'
= f.text_area attr, class: classes, placeholder: 'Leave a comment' = f.text_area attr, class: classes, placeholder: 'Leave a comment'
%label{ for: 'zen-toggle-comment', class: 'expand' } Edit in fullscreen = link_to nil, class: 'zen-enter-link', tabindex: '-1' do
%label{ for: 'zen-toggle-comment', class: 'collapse' } %i.fa.fa-expand
Edit in fullscreen
= link_to nil, class: 'zen-leave-link' do
%i.fa.fa-compress
...@@ -26,9 +26,9 @@ ...@@ -26,9 +26,9 @@
= i = i
\ \
%td.lines %td.lines
%pre %pre{class: 'code highlight white'}
%code{ class: highlightjs_class(@blob.name) } %code
:erb :erb
<% lines.each do |line| %> <% lines.each do |line| %>
<%= line %> <%= highlight(@blob.name, line, true).html_safe %>
<% end %> <% end %>
...@@ -8,6 +8,6 @@ ...@@ -8,6 +8,6 @@
- else - else
.file-content.code .file-content.code
- unless blob.empty? - unless blob.empty?
= render 'shared/file_hljs', blob: blob = render 'shared/file_highlight', blob: blob
- else - else
.nothing-here-block Empty file .nothing-here-block Empty file
...@@ -50,6 +50,13 @@ ...@@ -50,6 +50,13 @@
%span.js-details-content.hide %span.js-details-content.hide
= commit_branches_links(@project, @branches) = commit_branches_links(@project, @branches)
- if @tags.any?
.commit-info-row
%span.cgray
Tags:
%span
= commit_tags_links(@project, @tags)
.commit-box .commit-box
%h3.commit-title %h3.commit-title
= gfm escape_once(@commit.title) = gfm escape_once(@commit.title)
......
- unless defined?(project)
- project = @project
- @commits.group_by { |c| c.committed_date.to_date }.sort.reverse.each do |day, commits| - @commits.group_by { |c| c.committed_date.to_date }.sort.reverse.each do |day, commits|
.row.commits-row .row.commits-row
.col-md-2 .col-md-2
......
...@@ -9,6 +9,9 @@ ...@@ -9,6 +9,9 @@
.diff-btn-group .diff-btn-group
- if @commit.parent_ids.present? - if @commit.parent_ids.present?
= view_file_btn(@commit.parent_id, diff_file, project) = view_file_btn(@commit.parent_id, diff_file, project)
- elsif diff_file.diff.submodule?
- submodule_item = project.repository.blob_at(@commit.id, diff_file.file_path)
= submodule_link(submodule_item, @commit.id)
- else - else
- if diff_file.renamed_file - if diff_file.renamed_file
%span= "#{diff_file.old_path} renamed to #{diff_file.new_path}" %span= "#{diff_file.old_path} renamed to #{diff_file.new_path}"
...@@ -26,7 +29,7 @@ ...@@ -26,7 +29,7 @@
&nbsp; &nbsp;
= link_to '#', class: 'js-toggle-diff-comments btn btn-small' do = link_to '#', class: 'js-toggle-diff-comments btn btn-small' do
%i.fa.fa-chevron-down %i.fa.fa-chevron-down
Diff comments Show/Hide comments
&nbsp; &nbsp;
- if @merge_request && @merge_request.source_project - if @merge_request && @merge_request.source_project
......
...@@ -6,21 +6,7 @@ ...@@ -6,21 +6,7 @@
= link_to editing_preview_title(@blob.name), '#preview', 'data-preview-url' => preview_project_edit_tree_path(@project, @id) = link_to editing_preview_title(@blob.name), '#preview', 'data-preview-url' => preview_project_edit_tree_path(@project, @id)
= form_tag(project_edit_tree_path(@project, @id), method: :put, class: "form-horizontal") do = form_tag(project_edit_tree_path(@project, @id), method: :put, class: "form-horizontal") do
.file-holder.file = render 'projects/blob_editor', ref: @ref, path: @path, blob_data: @blob.data
.file-title
%i.fa.fa-file
%span.file_name
%span.monospace.light #{@ref}:
= @path
%span.options
.btn-group.tree-btn-group
= link_to "Cancel", @after_edit_path, class: "btn btn-tiny btn-cancel", data: { confirm: leave_edit_message }
.file-content.code
%pre.js-edit-mode-pane#editor
.js-edit-mode-pane#preview.hide
.center
%h2
%i.fa.fa-spinner.fa-spin
= render 'shared/commit_message_container', params: params, = render 'shared/commit_message_container', params: params,
placeholder: "Update #{@blob.name}" placeholder: "Update #{@blob.name}"
= hidden_field_tag 'last_commit', @last_commit = hidden_field_tag 'last_commit', @last_commit
...@@ -34,7 +20,6 @@ ...@@ -34,7 +20,6 @@
ace.config.loadModule("ace/ext/searchbox"); ace.config.loadModule("ace/ext/searchbox");
var ace_mode = "#{@blob.language.try(:ace_mode)}"; var ace_mode = "#{@blob.language.try(:ace_mode)}";
var editor = ace.edit("editor"); var editor = ace.edit("editor");
editor.setValue("#{escape_javascript(@blob.data)}");
if (ace_mode) { if (ace_mode) {
editor.getSession().setMode('ace/mode/' + ace_mode); editor.getSession().setMode('ace/mode/' + ace_mode);
} }
......
...@@ -19,14 +19,14 @@ ...@@ -19,14 +19,14 @@
%span.slead.has_tooltip{:"data-original-title" => 'Cross-project reference'} %span.slead.has_tooltip{:"data-original-title" => 'Cross-project reference'}
= cross_project_reference(@project, @issue) = cross_project_reference(@project, @issue)
%hr %hr
.context
%cite.cgray
= render partial: 'issue_context', locals: { issue: @issue }
%hr
.clearfix .clearfix
.votes-holder .votes-holder
%h6 Votes %h6 Votes
#votes= render 'votes/votes_block', votable: @issue #votes= render 'votes/votes_block', votable: @issue
%hr
.context
%cite.cgray
= render partial: 'issue_context', locals: { issue: @issue }
- if @issue.labels.any? - if @issue.labels.any?
%hr %hr
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
.pull-right .pull-right
- if can?(current_user, :write_issue, @project) - if can?(current_user, :write_issue, @project)
= link_to new_project_issue_path(@project), class: "btn btn-grouped", title: "New Issue", id: "new_issue_link" do = link_to new_project_issue_path(@project), class: "btn btn-grouped new-issue-link", title: "New Issue", id: "new_issue_link" do
%i.fa.fa-plus %i.fa.fa-plus
New Issue New Issue
- if can?(current_user, :modify_issue, @issue) - if can?(current_user, :modify_issue, @issue)
......
...@@ -14,13 +14,13 @@ ...@@ -14,13 +14,13 @@
%span.slead.has_tooltip{:"data-original-title" => 'Cross-project reference'} %span.slead.has_tooltip{:"data-original-title" => 'Cross-project reference'}
= cross_project_reference(@project, @merge_request) = cross_project_reference(@project, @merge_request)
%hr %hr
.votes-holder.hidden-sm.hidden-xs
%h6 Votes
#votes= render 'votes/votes_block', votable: @merge_request
%hr
.context .context
%cite.cgray %cite.cgray
= render partial: 'projects/merge_requests/show/context', locals: { merge_request: @merge_request } = render partial: 'projects/merge_requests/show/context', locals: { merge_request: @merge_request }
%hr
.votes-holder.hidden-sm.hidden-xs
%h6 Votes
#votes= render 'votes/votes_block', votable: @merge_request
- if @merge_request.labels.any? - if @merge_request.labels.any?
%hr %hr
......
...@@ -19,12 +19,7 @@ ...@@ -19,12 +19,7 @@
Encoding Encoding
.col-sm-10 .col-sm-10
= select_tag :encoding, options_for_select([ "base64", "text" ], "text"), class: 'form-control' = select_tag :encoding, options_for_select([ "base64", "text" ], "text"), class: 'form-control'
.file-holder = render 'projects/blob_editor', ref: @ref
.file-title
%i.fa.fa-file
.file-content.code
%pre#editor= params[:content]
= render 'shared/commit_message_container', params: params, = render 'shared/commit_message_container', params: params,
placeholder: 'Add new file' placeholder: 'Add new file'
= hidden_field_tag 'content', '', id: 'file-content' = hidden_field_tag 'content', '', id: 'file-content'
......
.note-edit-form
= form_for note, url: project_note_path(@project, note), method: :put, remote: true, authenticity_token: true do |f|
= render layout: 'projects/md_preview' do
= render 'projects/zen', f: f, attr: :note,
classes: 'note_text js-note-text'
.comment-hints.clearfix
.pull-left Comments are parsed with #{link_to "GitLab Flavored Markdown", help_page_path("markdown", "markdown"),{ target: '_blank', tabindex: -1 }}
.pull-right Attach images (JPG, PNG, GIF) by dragging &amp; dropping or #{link_to "selecting them", '#', class: 'markdown-selector', tabindex: -1 }.
.note-form-actions
.buttons
= f.submit 'Save Comment', class: "btn btn-primary btn-save btn-grouped js-comment-button"
= link_to 'Cancel', "#", class: "btn btn-cancel note-edit-cancel"
.note-form-option.hidden-xs
%a.choose-btn.btn.js-choose-note-attachment-button
%i.fa.fa-paperclip
%span Choose File ...
&nbsp;
%span.file_name.js-attachment-filename
= f.file_field :attachment, class: "js-note-attachment-input hidden"
...@@ -7,8 +7,9 @@ ...@@ -7,8 +7,9 @@
= render layout: 'projects/md_preview' do = render layout: 'projects/md_preview' do
= render 'projects/zen', f: f, attr: :note, = render 'projects/zen', f: f, attr: :note,
classes: 'note_text js-note-text' classes: 'note_text js-note-text'
.light.clearfix
.comment-hints.clearfix
.pull-left Comments are parsed with #{link_to "GitLab Flavored Markdown", help_page_path("markdown", "markdown"),{ target: '_blank', tabindex: -1 }} .pull-left Comments are parsed with #{link_to "GitLab Flavored Markdown", help_page_path("markdown", "markdown"),{ target: '_blank', tabindex: -1 }}
.pull-right Attach images (JPG, PNG, GIF) by dragging &amp; dropping or #{link_to "selecting them", '#', class: 'markdown-selector', tabindex: -1 }. .pull-right Attach images (JPG, PNG, GIF) by dragging &amp; dropping or #{link_to "selecting them", '#', class: 'markdown-selector', tabindex: -1 }.
...@@ -24,7 +25,7 @@ ...@@ -24,7 +25,7 @@
%i.fa.fa-paperclip %i.fa.fa-paperclip
%span Choose File ... %span Choose File ...
&nbsp; &nbsp;
%span.file_name.js-attachment-filename File name... %span.file_name.js-attachment-filename
= f.file_field :attachment, class: "js-note-attachment-input hidden" = f.file_field :attachment, class: "js-note-attachment-input hidden"
:javascript :javascript
......
%li.timeline-entry{ id: dom_id(note), class: [dom_class(note), ('system-note' if note.system)], data: { discussion: note.discussion_id } } %li.timeline-entry{ id: dom_id(note), class: [dom_class(note), "note-row-#{note.id}", ('system-note' if note.system)], data: { discussion: note.discussion_id } }
.timeline-entry-inner .timeline-entry-inner
.timeline-icon .timeline-icon
- if note.system - if note.system
...@@ -42,25 +42,7 @@ ...@@ -42,25 +42,7 @@
.note-text .note-text
= preserve do = preserve do
= markdown(note.note, {no_header_anchors: true}) = markdown(note.note, {no_header_anchors: true})
= render 'projects/notes/edit_form', note: note
.note-edit-form
= form_for note, url: project_note_path(@project, note), method: :put, remote: true, authenticity_token: true do |f|
= render layout: 'projects/md_preview' do
= f.text_area :note, class: 'note_text js-note-text js-gfm-input turn-on'
.form-actions.clearfix
= f.submit 'Save changes', class: "btn btn-primary btn-save js-comment-button"
.note-form-option
%a.choose-btn.btn.js-choose-note-attachment-button
%i.fa.fa-paperclip
%span Choose File ...
&nbsp;
%span.file_name.js-attachment-filename File name...
= f.file_field :attachment, class: "js-note-attachment-input hidden"
= link_to 'Cancel', "#", class: "btn btn-cancel note-edit-cancel"
- if note.attachment.url - if note.attachment.url
.note-attachment .note-attachment
......
- tree, commit = submodule_links(submodule_item)
%tr{ class: "tree-item" } %tr{ class: "tree-item" }
%td.tree-item-file-name %td.tree-item-file-name
%i.fa.fa-archive %i.fa.fa-archive
%span = submodule_link(submodule_item, @ref)
= link_to truncate(submodule_item.name, length: 40), tree
@
%span.monospace
- if commit.nil?
#{truncate_sha(submodule_item.id)}
- else
= link_to "#{truncate_sha(submodule_item.id)}", commit
%td %td
%td.hidden-xs %td.hidden-xs
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
- if @path.present? - if @path.present?
%tr.tree-item %tr.tree-item
%td.tree-item-file-name %td.tree-item-file-name
= link_to "..", project_tree_path(@project, up_dir_path(tree)), class: 'prepend-left-10' = link_to "..", project_tree_path(@project, up_dir_path), class: 'prepend-left-10'
%td %td
%td.hidden-xs %td.hidden-xs
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
%td %td
= commit.message = commit.message
%td %td
#{time_ago_with_tooltip(version.date)} #{time_ago_with_tooltip(version.authored_date)}
%td %td
%strong %strong
= @page.page.wiki.page(@page.page.name, commit.id).try(:format) = @page.page.wiki.page(@page.page.name, commit.id).try(:format)
...@@ -6,4 +6,4 @@ ...@@ -6,4 +6,4 @@
%strong %strong
= blob.filename = blob.filename
.file-content.code.term .file-content.code.term
= render 'shared/file_hljs', blob: blob, first_line_number: blob.startline = render 'shared/file_highlight', blob: blob, first_line_number: blob.startline, user_color_scheme_class: 'white'
...@@ -6,4 +6,4 @@ ...@@ -6,4 +6,4 @@
%strong %strong
= wiki_blob.filename = wiki_blob.filename
.file-content.code.term .file-content.code.term
= render 'shared/file_hljs', blob: wiki_blob, first_line_number: wiki_blob.startline = render 'shared/file_highlight', blob: wiki_blob, first_line_number: wiki_blob.startline, user_color_scheme_class: 'white'
%div.highlighted-data{class: user_color_scheme_class} .file-content.code{class: user_color_scheme_class}
.line-numbers .line-numbers
- if blob.data.present? - if blob.data.present?
- blob.data.lines.to_a.size.times do |index| - blob.data.lines.to_a.size.times do |index|
...@@ -7,7 +7,4 @@ ...@@ -7,7 +7,4 @@
= link_to "#L#{i}", id: "L#{i}", rel: "#L#{i}" do = link_to "#L#{i}", id: "L#{i}", rel: "#L#{i}" do
%i.fa.fa-link %i.fa.fa-link
= i = i
.highlight = highlight(blob.name, blob.data)
%pre
%code{ class: highlightjs_class(blob.name) }
#{blob.data}
.fixed.sidebar-expand-button.hidden-lg.hidden-md .milestones-filters.append-bottom-10
%i.fa.fa-list.fa-2x
.responsive-side.milestones-filters.append-bottom-10
%ul.nav.nav-pills.nav-compact %ul.nav.nav-pills.nav-compact
%li{class: ("active" if params[:state].blank? || params[:state] == 'opened')} %li{class: ("active" if params[:state].blank? || params[:state] == 'opened')}
= link_to milestones_filter_path(state: 'opened') do = link_to milestones_filter_path(state: 'opened') do
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
- else - else
Newest Newest
%b.caret %b.caret
%ul.dropdown-menu %ul.dropdown-menu.dropdown-menu-align-right
%li %li
= link_to page_filter_path(sort: 'newest') do = link_to page_filter_path(sort: 'newest') do
= sort_title_recently_created = sort_title_recently_created
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
= render_markup(@snippet.file_name, @snippet.data) = render_markup(@snippet.file_name, @snippet.data)
- else - else
.file-content.code .file-content.code
= render 'shared/file_hljs', blob: @snippet = render 'shared/file_highlight', blob: @snippet
- else - else
.file-content.code .file-content.code
.nothing-here-block Empty file .nothing-here-block Empty file
...@@ -18,6 +18,3 @@ rm config/resque.yml ...@@ -18,6 +18,3 @@ rm config/resque.yml
# Set default unicorn.rb file # Set default unicorn.rb file
echo "" > config/unicorn.rb echo "" > config/unicorn.rb
# Required for assets precompilation
sudo service postgresql start
...@@ -44,7 +44,7 @@ production: &base ...@@ -44,7 +44,7 @@ production: &base
# Email address used in the "From" field in mails sent by GitLab # Email address used in the "From" field in mails sent by GitLab
email_from: example@example.com email_from: example@example.com
# Email server smtp settings are in [a separate file](initializers/smtp_settings.rb.sample). # Email server smtp settings are in config/initializers/smtp_settings.rb.sample
## User settings ## User settings
default_projects_limit: 10 default_projects_limit: 10
...@@ -77,7 +77,7 @@ production: &base ...@@ -77,7 +77,7 @@ production: &base
# This happens when the commit is pushed or merged into the default branch of a project. # This happens when the commit is pushed or merged into the default branch of a project.
# When not specified the default issue_closing_pattern as specified below will be used. # When not specified the default issue_closing_pattern as specified below will be used.
# Tip: you can test your closing pattern at http://rubular.com # Tip: you can test your closing pattern at http://rubular.com
# issue_closing_pattern: '([Cc]lose[sd]|[Ff]ixe[sd]) (#\d+|([A-Z\-]+-)\d+)' # issue_closing_pattern: '((?:[Cc]los(?:e[sd]|ing)|[Ff]ix(?:e[sd]|ing)?) +(?:(?:issues? +)?#\d+(?:(?:, *| +and +)?))+)'
## Default project features settings ## Default project features settings
default_projects_features: default_projects_features:
......
...@@ -112,11 +112,11 @@ rescue ArgumentError # no user configured ...@@ -112,11 +112,11 @@ rescue ArgumentError # no user configured
'/home/' + Settings.gitlab['user'] '/home/' + Settings.gitlab['user']
end end
Settings.gitlab['time_zone'] ||= nil Settings.gitlab['time_zone'] ||= nil
Settings.gitlab['signup_enabled'] ||= true Settings.gitlab['signup_enabled'] ||= true if Settings.gitlab['signup_enabled'].nil?
Settings.gitlab['signin_enabled'] ||= true if Settings.gitlab['signin_enabled'].nil? Settings.gitlab['signin_enabled'] ||= true if Settings.gitlab['signin_enabled'].nil?
Settings.gitlab['restricted_visibility_levels'] = Settings.send(:verify_constant_array, Gitlab::VisibilityLevel, Settings.gitlab['restricted_visibility_levels'], []) Settings.gitlab['restricted_visibility_levels'] = Settings.send(:verify_constant_array, Gitlab::VisibilityLevel, Settings.gitlab['restricted_visibility_levels'], [])
Settings.gitlab['username_changing_enabled'] = true if Settings.gitlab['username_changing_enabled'].nil? Settings.gitlab['username_changing_enabled'] = true if Settings.gitlab['username_changing_enabled'].nil?
Settings.gitlab['issue_closing_pattern'] = '([Cc]lose[sd]|[Ff]ixe[sd]) (#\d+|([A-Z\-]+-)\d+)' if Settings.gitlab['issue_closing_pattern'].nil? Settings.gitlab['issue_closing_pattern'] = '((?:[Cc]los(?:e[sd]|ing)|[Ff]ix(?:e[sd]|ing)?) +(?:(?:issues? +)?#\d+(?:(?:, *| +and +)?))+)' if Settings.gitlab['issue_closing_pattern'].nil?
Settings.gitlab['default_projects_features'] ||= {} Settings.gitlab['default_projects_features'] ||= {}
Settings.gitlab['webhook_timeout'] ||= 10 Settings.gitlab['webhook_timeout'] ||= 10
Settings.gitlab.default_projects_features['issues'] = true if Settings.gitlab.default_projects_features['issues'].nil? Settings.gitlab.default_projects_features['issues'] = true if Settings.gitlab.default_projects_features['issues'].nil?
......
...@@ -40,7 +40,7 @@ Doorkeeper.configure do ...@@ -40,7 +40,7 @@ Doorkeeper.configure do
# Optional parameter :confirmation => true (default false) if you want to enforce ownership of # Optional parameter :confirmation => true (default false) if you want to enforce ownership of
# a registered application # a registered application
# Note: you must also run the rails g doorkeeper:application_owner generator to provide the necessary support # Note: you must also run the rails g doorkeeper:application_owner generator to provide the necessary support
enable_application_owner :confirmation => true enable_application_owner :confirmation => false
# Define access token scopes for your provider # Define access token scopes for your provider
# For more information go to # For more information go to
......
...@@ -58,6 +58,7 @@ Gitlab::Application.routes.draw do ...@@ -58,6 +58,7 @@ Gitlab::Application.routes.draw do
resource :github_import, only: [:create, :new] do resource :github_import, only: [:create, :new] do
get :status get :status
get :callback get :callback
get :jobs
end end
# #
...@@ -98,6 +99,8 @@ Gitlab::Application.routes.draw do ...@@ -98,6 +99,8 @@ Gitlab::Application.routes.draw do
end end
end end
resources :applications
resources :groups, constraints: { id: /[^\/]+/ } do resources :groups, constraints: { id: /[^\/]+/ } do
member do member do
put :project_teams_update put :project_teams_update
...@@ -163,8 +166,8 @@ Gitlab::Application.routes.draw do ...@@ -163,8 +166,8 @@ Gitlab::Application.routes.draw do
end end
end end
match "/u/:username" => "users#show", as: :user, get '/u/:username' => 'users#show', as: :user,
constraints: {username: /(?:[^.]|\.(?!atom$))+/, format: /atom/}, via: :get constraints: { username: /(?:[^.]|\.(?!atom$))+/, format: /atom/ }
# #
# Dashboard Area # Dashboard Area
......
...@@ -5,7 +5,6 @@ Gitlab::Seeder.quiet do ...@@ -5,7 +5,6 @@ Gitlab::Seeder.quiet do
s.email = 'admin@example.com' s.email = 'admin@example.com'
s.username = 'root' s.username = 'root'
s.password = '5iveL!fe' s.password = '5iveL!fe'
s.password_confirmation = '5iveL!fe'
s.admin = true s.admin = true
s.projects_limit = 100 s.projects_limit = 100
s.confirmed_at = DateTime.now s.confirmed_at = DateTime.now
......
...@@ -11,7 +11,6 @@ admin = User.create( ...@@ -11,7 +11,6 @@ admin = User.create(
name: "Administrator", name: "Administrator",
username: 'root', username: 'root',
password: password, password: password,
password_confirmation: password,
password_expires_at: expire_time, password_expires_at: expire_time,
theme_id: Gitlab::Theme::MARS theme_id: Gitlab::Theme::MARS
......
class AddHomePageUrlForApplicationSettings < ActiveRecord::Migration
def change
add_column :application_settings, :home_page_url, :string
end
end
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20150108073740) do ActiveRecord::Schema.define(version: 20150116234544) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
...@@ -49,6 +49,7 @@ ActiveRecord::Schema.define(version: 20150108073740) do ...@@ -49,6 +49,7 @@ ActiveRecord::Schema.define(version: 20150108073740) do
t.text "sign_in_text" t.text "sign_in_text"
t.datetime "created_at" t.datetime "created_at"
t.datetime "updated_at" t.datetime "updated_at"
t.string "home_page_url"
end end
create_table "broadcast_messages", force: true do |t| create_table "broadcast_messages", force: true do |t|
......
...@@ -14,7 +14,8 @@ GET /groups ...@@ -14,7 +14,8 @@ GET /groups
"id": 1, "id": 1,
"name": "Foobar Group", "name": "Foobar Group",
"path": "foo-bar", "path": "foo-bar",
"owner_id": 18 "owner_id": 18,
"description": "An interesting group"
} }
] ]
``` ```
...@@ -45,6 +46,7 @@ Parameters: ...@@ -45,6 +46,7 @@ Parameters:
- `name` (required) - The name of the group - `name` (required) - The name of the group
- `path` (required) - The path of the group - `path` (required) - The path of the group
- `description` (optional) - The group's description
## Transfer project to group ## Transfer project to group
......
...@@ -109,6 +109,7 @@ Parameters: ...@@ -109,6 +109,7 @@ Parameters:
- `target_branch` (required) - The target branch - `target_branch` (required) - The target branch
- `assignee_id` (optional) - Assignee user ID - `assignee_id` (optional) - Assignee user ID
- `title` (required) - Title of MR - `title` (required) - Title of MR
- `description` (optional) - Description of MR
- `target_project_id` (optional) - The target project (numeric id) - `target_project_id` (optional) - The target project (numeric id)
```json ```json
...@@ -160,6 +161,7 @@ Parameters: ...@@ -160,6 +161,7 @@ Parameters:
- `target_branch` - The target branch - `target_branch` - The target branch
- `assignee_id` - Assignee user ID - `assignee_id` - Assignee user ID
- `title` - Title of MR - `title` - Title of MR
- `description` - Description of MR
- `state_event` - New state (close|reopen|merge) - `state_event` - New state (close|reopen|merge)
```json ```json
...@@ -169,6 +171,7 @@ Parameters: ...@@ -169,6 +171,7 @@ Parameters:
"source_branch": "test1", "source_branch": "test1",
"project_id": 3, "project_id": 3,
"title": "test1", "title": "test1",
"description": "description1",
"state": "opened", "state": "opened",
"upvotes": 0, "upvotes": 0,
"downvotes": 0, "downvotes": 0,
......
...@@ -280,7 +280,7 @@ We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](da ...@@ -280,7 +280,7 @@ We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](da
GitLab Shell is an SSH access and repository management software developed specially for GitLab. GitLab Shell is an SSH access and repository management software developed specially for GitLab.
# Run the installation task for gitlab-shell (replace `REDIS_URL` if needed): # Run the installation task for gitlab-shell (replace `REDIS_URL` if needed):
sudo -u git -H bundle exec rake gitlab:shell:install[v2.4.0] REDIS_URL=unix:/var/run/redis/redis.sock RAILS_ENV=production sudo -u git -H bundle exec rake gitlab:shell:install[v2.4.1] REDIS_URL=unix:/var/run/redis/redis.sock RAILS_ENV=production
# By default, the gitlab-shell config is generated from your main GitLab config. # By default, the gitlab-shell config is generated from your main GitLab config.
# You can review (and modify) the gitlab-shell config as follows: # You can review (and modify) the gitlab-shell config as follows:
......
...@@ -14,7 +14,7 @@ To enable the GitHub OmniAuth provider you must register your application with G ...@@ -14,7 +14,7 @@ To enable the GitHub OmniAuth provider you must register your application with G
- Application name: This can be anything. Consider something like "\<Organization\>'s GitLab" or "\<Your Name\>'s GitLab" or something else descriptive. - Application name: This can be anything. Consider something like "\<Organization\>'s GitLab" or "\<Your Name\>'s GitLab" or something else descriptive.
- Homepage URL: The URL to your GitLab installation. 'https://gitlab.company.com' - Homepage URL: The URL to your GitLab installation. 'https://gitlab.company.com'
- Application description: Fill this in if you wish. - Application description: Fill this in if you wish.
- Authorization callback URL: 'https://gitlab.company.com/users/auth/github/callback' - Authorization callback URL: 'https://gitlab.company.com/'
1. Select "Register application". 1. Select "Register application".
1. You should now see a Client ID and Client Secret near the top right of the page (see screenshot). Keep this page open as you continue configuration. ![GitHub app](github_app.png) 1. You should now see a Client ID and Client Secret near the top right of the page (see screenshot). Keep this page open as you continue configuration. ![GitHub app](github_app.png)
......
doc/integration/github_app.png

73.8 KB | W: | H:

doc/integration/github_app.png

73.5 KB | W: | H:

doc/integration/github_app.png
doc/integration/github_app.png
doc/integration/github_app.png
doc/integration/github_app.png
  • 2-up
  • Swipe
  • Onion skin
...@@ -16,12 +16,22 @@ it in the `/etc/gitlab/gitlab.rb` file. ...@@ -16,12 +16,22 @@ it in the `/etc/gitlab/gitlab.rb` file.
- For manual installations, it is usually located at: `/home/git/repositories` or you can see where - For manual installations, it is usually located at: `/home/git/repositories` or you can see where
your repositories are located by looking at `config/gitlab.yml` under the `gitlab_shell => repos_path` entry. your repositories are located by looking at `config/gitlab.yml` under the `gitlab_shell => repos_path` entry.
New folder needs to have git user ownership and read/write/execute access for git user and its group:
```
$ mkdir new_group
$ chown git:git new_group
$ chmod 770 new_group
```
### Copy your bare repositories inside this newly created folder: ### Copy your bare repositories inside this newly created folder:
``` ```
$ cp -r /old/git/foo.git/ /home/git/repositories/new_group/ $ cp -r /old/git/foo.git/ /home/git/repositories/new_group/
``` ```
`foo.git` needs to be owned by the git user and git users group.
### Run the command below depending on your type of installation: ### Run the command below depending on your type of installation:
#### Omnibus Installation #### Omnibus Installation
......
...@@ -121,6 +121,6 @@ Add to your local `gitlab-ci/.git/config`: ...@@ -121,6 +121,6 @@ Add to your local `gitlab-ci/.git/config`:
* Create a stable branch `x-y-stable` * Create a stable branch `x-y-stable`
* Bump VERSION to `x.y.0.rc1` * Bump VERSION to `x.y.0.rc1`
* `git tag -a v$(cat VERSION) -m "Version $(cat VERSION)" * `git tag -a v$(cat VERSION) -m "Version $(cat VERSION)"`
* `git push public x-y-stable v$(cat VERSION)` * `git push public x-y-stable v$(cat VERSION)`
...@@ -119,7 +119,7 @@ sudo apt-get install pkg-config cmake ...@@ -119,7 +119,7 @@ sudo apt-get install pkg-config cmake
```bash ```bash
cd /home/git/gitlab-shell cd /home/git/gitlab-shell
sudo -u git -H git fetch sudo -u git -H git fetch
sudo -u git -H git checkout v2.4.0 sudo -u git -H git checkout v2.4.1
``` ```
## 7. Install libs, migrations, etc. ## 7. Install libs, migrations, etc.
......
...@@ -37,7 +37,7 @@ sudo -u git -H git checkout 7-7-stable-ee ...@@ -37,7 +37,7 @@ sudo -u git -H git checkout 7-7-stable-ee
```bash ```bash
cd /home/git/gitlab-shell cd /home/git/gitlab-shell
sudo -u git -H git fetch sudo -u git -H git fetch
sudo -u git -H git checkout v2.4.0 sudo -u git -H git checkout v2.4.1
``` ```
### 4. Install libs, migrations, etc. ### 4. Install libs, migrations, etc.
...@@ -99,6 +99,11 @@ To make sure you didn't miss anything run a more thorough check with: ...@@ -99,6 +99,11 @@ To make sure you didn't miss anything run a more thorough check with:
If all items are green, then congratulations upgrade is complete! If all items are green, then congratulations upgrade is complete!
### 8. GitHub settings (if applicable)
If you are using GitHub as an OAuth provider for authentication, you should change the callback url so that it
only contains a root url (ex. `https://gitlab.example.com/`)
## Things went south? Revert to previous version (7.6) ## Things went south? Revert to previous version (7.6)
### 1. Revert the code to the previous version ### 1. Revert the code to the previous version
......
...@@ -166,7 +166,9 @@ Triggered when a new merge request is created or an existing merge request was u ...@@ -166,7 +166,9 @@ Triggered when a new merge request is created or an existing merge request was u
"name": "GitLab dev user", "name": "GitLab dev user",
"email": "gitlabdev@dv6700.(none)" "email": "gitlabdev@dv6700.(none)"
} }
} },
"url": "http://example.com/diaspora/merge_requests/1",
"action": "open"
} }
} }
``` ```
......
...@@ -9,4 +9,5 @@ ...@@ -9,4 +9,5 @@
- [GitLab Flow](gitlab_flow.md) - [GitLab Flow](gitlab_flow.md)
- [Notifications](notifications.md) - [Notifications](notifications.md)
- [Migrating from SVN to GitLab](migrating_from_svn.md) - [Migrating from SVN to GitLab](migrating_from_svn.md)
- [Project importing from GitHub to GitLab](import_projects_from_github.md)
- [Protected branches](protected_branches.md) - [Protected branches](protected_branches.md)
# Project importing from GitHub to GitLab
You can import your existing GitHub projects to GitLab. But keep in mind that it is possible only if
GitHub support is enabled on your GitLab instance. You can read more about GitHub support [here](http://doc.gitlab.com/ce/integration/github.html)
To get to the importer page you need to go to "New project" page.
![New project page](github_importer/new_project_page.png)
Click on the "Import project from GitHub" link and you will be redirected to GitHub for permission to access your projects. After accepting, you'll be automatically redirected to the importer.
![Importer page](github_importer/importer.png)
To import a project, you can simple click "Add". The importer will import your repository and issues. Once the importer is done, a new GitLab project will be created with your imported data.
\ No newline at end of file
...@@ -11,7 +11,7 @@ RUN apt-get update -q \ ...@@ -11,7 +11,7 @@ RUN apt-get update -q \
# If the Omnibus package version below is outdated please contribute a merge request to update it. # If the Omnibus package version below is outdated please contribute a merge request to update it.
# If you run GitLab Enterprise Edition point it to a location where you have downloaded it. # If you run GitLab Enterprise Edition point it to a location where you have downloaded it.
RUN TMP_FILE=$(mktemp); \ RUN TMP_FILE=$(mktemp); \
wget -q -O $TMP_FILE https://downloads-packages.s3.amazonaws.com/ubuntu-14.04/gitlab_7.5.3-omnibus.5.2.1.ci-1_amd64.deb \ wget -q -O $TMP_FILE https://downloads-packages.s3.amazonaws.com/ubuntu-14.04/gitlab_7.6.2-omnibus.5.3.0.ci.1-1_amd64.deb \
&& dpkg -i $TMP_FILE \ && dpkg -i $TMP_FILE \
&& rm -f $TMP_FILE && rm -f $TMP_FILE
......
@admin
Feature: Admin Applications
Background:
Given I sign in as an admin
And I visit applications page
Scenario: I can manage application
Then I click on new application button
And I should see application form
Then I fill application form out and submit
And I see application
Then I click edit
And I see edit application form
Then I change name of application and submit
And I see that application was changed
Then I visit applications page
And I click to remove application
Then I see that application is removed
\ No newline at end of file
...@@ -5,5 +5,5 @@ Feature: Admin Settings ...@@ -5,5 +5,5 @@ Feature: Admin Settings
And I visit admin settings page And I visit admin settings page
Scenario: Change application settings Scenario: Change application settings
When I disable gravatars and save form When I modify settings and save form
Then I should be see gravatar disabled Then I should see application settings saved
...@@ -97,22 +97,3 @@ Feature: Profile ...@@ -97,22 +97,3 @@ Feature: Profile
Given I visit profile design page Given I visit profile design page
When I change my code preview theme When I change my code preview theme
Then I should receive feedback that the changes were saved Then I should receive feedback that the changes were saved
@javascript
Scenario: I see the password strength indicator
Given I visit profile password page
When I try to set a weak password
Then I should see the input field yellow
@javascript
Scenario: I see the password strength indicator error
Given I visit profile password page
When I try to set a short password
Then I should see the input field red
And I should see the password error message
@javascript
Scenario: I see the password strength indicator with success
Given I visit profile password page
When I try to set a strong password
Then I should see the input field green
...@@ -13,11 +13,6 @@ Feature: Project Commits Comments ...@@ -13,11 +13,6 @@ Feature: Project Commits Comments
Scenario: I can't cancel the main form Scenario: I can't cancel the main form
Then I should not see the cancel comment button Then I should not see the cancel comment button
@javascript
Scenario: I can't preview without text
Given I haven't written any comment text
Then The comment preview tab should say there is nothing to do
@javascript @javascript
Scenario: I can preview with text Scenario: I can preview with text
Given I write a comment like ":+1: Nice" Given I write a comment like ":+1: Nice"
......
...@@ -54,12 +54,6 @@ Feature: Project Commits Diff Comments ...@@ -54,12 +54,6 @@ Feature: Project Commits Diff Comments
Given I leave a diff comment like "Typo, please fix" Given I leave a diff comment like "Typo, please fix"
Then I should see a discussion reply button Then I should see a discussion reply button
@javascript
Scenario: I can't preview without text
Given I open a diff comment form
And I haven't written any diff comment text
Then The diff comment preview tab should say there is nothing to do
@javascript @javascript
Scenario: I can preview with text Scenario: I can preview with text
Given I open a diff comment form Given I open a diff comment form
......
class Spinach::Features::AdminApplications < Spinach::FeatureSteps
include SharedAuthentication
include SharedPaths
include SharedAdmin
step 'I click on new application button' do
click_on 'New Application'
end
step 'I should see application form' do
page.should have_content "New application"
end
step 'I fill application form out and submit' do
fill_in :doorkeeper_application_name, with: 'test'
fill_in :doorkeeper_application_redirect_uri, with: 'https://test.com'
click_on "Submit"
end
step 'I see application' do
page.should have_content "Application: test"
page.should have_content "Application Id"
page.should have_content "Secret"
end
step 'I click edit' do
click_on "Edit"
end
step 'I see edit application form' do
page.should have_content "Edit application"
end
step 'I change name of application and submit' do
page.should have_content "Edit application"
fill_in :doorkeeper_application_name, with: 'test_changed'
click_on "Submit"
end
step 'I see that application was changed' do
page.should have_content "test_changed"
page.should have_content "Application Id"
page.should have_content "Secret"
end
step 'I click to remove application' do
within '.oauth-applications' do
click_on "Destroy"
end
end
step "I see that application is removed" do
page.find(".oauth-applications").should_not have_content "test_changed"
end
end
...@@ -4,13 +4,15 @@ class Spinach::Features::AdminSettings < Spinach::FeatureSteps ...@@ -4,13 +4,15 @@ class Spinach::Features::AdminSettings < Spinach::FeatureSteps
include SharedAdmin include SharedAdmin
include Gitlab::CurrentSettings include Gitlab::CurrentSettings
step 'I disable gravatars and save form' do step 'I modify settings and save form' do
uncheck 'Gravatar enabled' uncheck 'Gravatar enabled'
fill_in 'Home page url', with: 'https://about.gitlab.com/'
click_button 'Save' click_button 'Save'
end end
step 'I should be see gravatar disabled' do step 'I should see application settings saved' do
current_application_settings.gravatar_enabled.should be_false current_application_settings.gravatar_enabled.should be_false
current_application_settings.home_page_url.should == 'https://about.gitlab.com/'
page.should have_content 'Application settings saved successfully' page.should have_content 'Application settings saved successfully'
end end
end end
...@@ -58,34 +58,16 @@ class Spinach::Features::Profile < Spinach::FeatureSteps ...@@ -58,34 +58,16 @@ class Spinach::Features::Profile < Spinach::FeatureSteps
step 'I try change my password w/o old one' do step 'I try change my password w/o old one' do
within '.update-password' do within '.update-password' do
fill_in "user_password_profile", with: "22233344" fill_in "user_password", with: "22233344"
fill_in "user_password_confirmation", with: "22233344" fill_in "user_password_confirmation", with: "22233344"
click_button "Save" click_button "Save"
end end
end end
step 'I try to set a weak password' do
within '.update-password' do
fill_in "user_password_profile", with: "22233344"
end
end
step 'I try to set a short password' do
within '.update-password' do
fill_in "user_password_profile", with: "short"
end
end
step 'I try to set a strong password' do
within '.update-password' do
fill_in "user_password_profile", with: "Itulvo9z8uud%$"
end
end
step 'I change my password' do step 'I change my password' do
within '.update-password' do within '.update-password' do
fill_in "user_current_password", with: "12345678" fill_in "user_current_password", with: "12345678"
fill_in "user_password_profile", with: "22233344" fill_in "user_password", with: "22233344"
fill_in "user_password_confirmation", with: "22233344" fill_in "user_password_confirmation", with: "22233344"
click_button "Save" click_button "Save"
end end
...@@ -94,7 +76,7 @@ class Spinach::Features::Profile < Spinach::FeatureSteps ...@@ -94,7 +76,7 @@ class Spinach::Features::Profile < Spinach::FeatureSteps
step 'I unsuccessfully change my password' do step 'I unsuccessfully change my password' do
within '.update-password' do within '.update-password' do
fill_in "user_current_password", with: "12345678" fill_in "user_current_password", with: "12345678"
fill_in "user_password_profile", with: "password" fill_in "user_password", with: "password"
fill_in "user_password_confirmation", with: "confirmation" fill_in "user_password_confirmation", with: "confirmation"
click_button "Save" click_button "Save"
end end
...@@ -104,22 +86,6 @@ class Spinach::Features::Profile < Spinach::FeatureSteps ...@@ -104,22 +86,6 @@ class Spinach::Features::Profile < Spinach::FeatureSteps
page.should have_content "You must provide a valid current password" page.should have_content "You must provide a valid current password"
end end
step 'I should see the input field yellow' do
page.should have_css 'div.has-warning'
end
step 'I should see the input field green' do
page.should have_css 'div.has-success'
end
step 'I should see the input field red' do
page.should have_css 'div.has-error'
end
step 'I should see the password error message' do
page.should have_content 'Your password is too short'
end
step "I should see a password error message" do step "I should see a password error message" do
page.should have_content "Password confirmation doesn't match" page.should have_content "Password confirmation doesn't match"
end end
...@@ -180,7 +146,7 @@ class Spinach::Features::Profile < Spinach::FeatureSteps ...@@ -180,7 +146,7 @@ class Spinach::Features::Profile < Spinach::FeatureSteps
step 'I submit new password' do step 'I submit new password' do
fill_in :user_current_password, with: '12345678' fill_in :user_current_password, with: '12345678'
fill_in :user_password_profile, with: '12345678' fill_in :user_password, with: '12345678'
fill_in :user_password_confirmation, with: '12345678' fill_in :user_password_confirmation, with: '12345678'
click_button "Set new password" click_button "Set new password"
end end
......
...@@ -194,13 +194,13 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps ...@@ -194,13 +194,13 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
step 'I click link "Hide inline discussion" of the second file' do step 'I click link "Hide inline discussion" of the second file' do
within '.files [id^=diff]:nth-child(2)' do within '.files [id^=diff]:nth-child(2)' do
click_link "Diff comments" click_link 'Show/Hide comments'
end end
end end
step 'I click link "Show inline discussion" of the second file' do step 'I click link "Show inline discussion" of the second file' do
within '.files [id^=diff]:nth-child(2)' do within '.files [id^=diff]:nth-child(2)' do
click_link "Diff comments" click_link 'Show/Hide comments'
end end
end end
......
...@@ -80,7 +80,7 @@ module SharedDiffNote ...@@ -80,7 +80,7 @@ module SharedDiffNote
step 'I should not see the diff comment text field' do step 'I should not see the diff comment text field' do
within(diff_file_selector) do within(diff_file_selector) do
page.should have_css(".js-note-text", visible: false) expect(find('.js-note-text')).not_to be_visible
end end
end end
...@@ -115,7 +115,7 @@ module SharedDiffNote ...@@ -115,7 +115,7 @@ module SharedDiffNote
end end
step 'I should see add a diff comment button' do step 'I should see add a diff comment button' do
page.should have_css(".js-add-diff-note-button", visible: false) page.should have_css('.js-add-diff-note-button', visible: true)
end end
step 'I should see an empty diff comment form' do step 'I should see an empty diff comment form' do
......
...@@ -64,7 +64,7 @@ module SharedNote ...@@ -64,7 +64,7 @@ module SharedNote
step 'I should not see the comment text field' do step 'I should not see the comment text field' do
within(".js-main-target-form") do within(".js-main-target-form") do
page.should have_css(".js-note-text", visible: false) expect(find('.js-note-text')).not_to be_visible
end end
end end
......
...@@ -187,6 +187,10 @@ module SharedPaths ...@@ -187,6 +187,10 @@ module SharedPaths
visit admin_application_settings_path visit admin_application_settings_path
end end
step 'I visit applications page' do
visit admin_applications_path
end
# ---------------------------------------- # ----------------------------------------
# Generic Project # Generic Project
# ---------------------------------------- # ----------------------------------------
......
...@@ -70,7 +70,7 @@ module API ...@@ -70,7 +70,7 @@ module API
end end
class Group < Grape::Entity class Group < Grape::Entity
expose :id, :name, :path, :owner_id, :ldap_cn, :ldap_access expose :id, :name, :path, :owner_id, :ldap_cn, :ldap_access, :description
expose :ldap_group_links, if: ->(group, _) { group.ldap_group_links.any? } do |group, _| expose :ldap_group_links, if: ->(group, _) { group.ldap_group_links.any? } do |group, _|
group.ldap_group_links.map do |group_link| group.ldap_group_links.map do |group_link|
group_link.slice(:cn, :group_access) group_link.slice(:cn, :group_access)
......
...@@ -47,8 +47,8 @@ module API ...@@ -47,8 +47,8 @@ module API
authenticated_as_admin! authenticated_as_admin!
required_attributes! [:name, :path] required_attributes! [:name, :path]
group_attrs = attributes_for_keys [:name, :path] attrs = attributes_for_keys [:name, :path, :description]
@group = Group.new(group_attrs) @group = Group.new(attrs)
@group.owner = current_user @group.owner = current_user
if @group.save if @group.save
......
...@@ -25,8 +25,8 @@ module API ...@@ -25,8 +25,8 @@ module API
# project. This applies the correct project permissions to # project. This applies the correct project permissions to
# the wiki repository as well. # the wiki repository as well.
access = access =
if project_path =~ /\.wiki\Z/ if project_path.end_with?('.wiki')
project_path.sub!(/\.wiki\Z/, '') project_path.chomp!('.wiki')
Gitlab::GitAccessWiki.new Gitlab::GitAccessWiki.new
else else
Gitlab::GitAccess.new Gitlab::GitAccess.new
......
...@@ -167,13 +167,9 @@ module API ...@@ -167,13 +167,9 @@ module API
put ":id/merge_request/:merge_request_id/merge" do put ":id/merge_request/:merge_request_id/merge" do
merge_request = user_project.merge_requests.find(params[:merge_request_id]) merge_request = user_project.merge_requests.find(params[:merge_request_id])
action = if user_project.protected_branch?(merge_request.target_branch) allowed = ::Gitlab::GitAccess.can_push_to_branch?(current_user, user_project, merge_request.target_branch)
:push_code_to_protected_branches
else
:push_code
end
if can?(current_user, action, user_project) if allowed
if merge_request.unchecked? if merge_request.unchecked?
merge_request.check_if_can_be_merged merge_request.check_if_can_be_merged
end end
......
...@@ -96,7 +96,7 @@ module API ...@@ -96,7 +96,7 @@ module API
# Parameters: # Parameters:
# id (required) - The ID of a project # id (required) - The ID of a project
# Example Request: # Example Request:
# GET /projects/:id # GET /projects/:id/events
get ":id/events" do get ":id/events" do
limit = (params[:per_page] || 20).to_i limit = (params[:per_page] || 20).to_i
offset = (params[:page] || 0).to_i * limit offset = (params[:page] || 0).to_i * limit
......
...@@ -3,14 +3,19 @@ module Gitlab ...@@ -3,14 +3,19 @@ module Gitlab
ISSUE_CLOSING_REGEX = Regexp.new(Gitlab.config.gitlab.issue_closing_pattern) ISSUE_CLOSING_REGEX = Regexp.new(Gitlab.config.gitlab.issue_closing_pattern)
def self.closed_by_message_in_project(message, project) def self.closed_by_message_in_project(message, project)
md = ISSUE_CLOSING_REGEX.match(message) issues = []
if md
extractor = Gitlab::ReferenceExtractor.new unless message.nil?
extractor.analyze(md[0], project) md = message.scan(ISSUE_CLOSING_REGEX)
extractor.issues_for(project)
else md.each do |ref|
[] extractor = Gitlab::ReferenceExtractor.new
extractor.analyze(ref[0], project)
issues += extractor.issues_for(project)
end
end end
issues.uniq
end end
end end
end end
module Gitlab module Gitlab
module CurrentSettings module CurrentSettings
def current_application_settings def current_application_settings
begin if ActiveRecord::Base.connected? && ActiveRecord::Base.connection.table_exists?('application_settings')
if ActiveRecord::Base.connection.table_exists?('application_settings') ApplicationSetting.current ||
ApplicationSetting.current || ApplicationSetting.create_from_defaults
ApplicationSetting.create_from_defaults else
else
fake_application_settings
end
rescue ActiveRecord::NoDatabaseError, database_adapter.constantize::Error
fake_application_settings fake_application_settings
end end
end end
...@@ -22,16 +18,5 @@ module Gitlab ...@@ -22,16 +18,5 @@ module Gitlab
sign_in_text: Settings.extra['sign_in_text'], sign_in_text: Settings.extra['sign_in_text'],
) )
end end
# We need to check which database is setup
# but we cannot assume that the database exists already.
# Not checking this will break "rake gitlab:setup".
def database_adapter
if Rails.configuration.database_configuration[Rails.env]['adapter'] == 'mysql2'
"Mysql2"
else
"PG"
end
end
end end
end end
module Gitlab module Gitlab
module Git module Git
BLANK_SHA = '0' * 40 BLANK_SHA = '0' * 40
def self.extract_ref_name(ref)
ref.gsub(/\Arefs\/(tags|heads)\//, '')
end
end end
end end
...@@ -5,6 +5,15 @@ module Gitlab ...@@ -5,6 +5,15 @@ module Gitlab
attr_reader :params, :project, :git_cmd, :user attr_reader :params, :project, :git_cmd, :user
def self.can_push_to_branch?(user, project, ref)
if project.protected_branch?(ref) &&
!(project.developers_can_push_to_protected_branch?(ref) && project.team.developer?(user))
user.can?(:push_code_to_protected_branches, project)
else
user.can?(:push_code, project)
end
end
def check(actor, cmd, project, changes = nil) def check(actor, cmd, project, changes = nil)
case cmd case cmd
when *DOWNLOAD_COMMANDS when *DOWNLOAD_COMMANDS
......
...@@ -31,6 +31,8 @@ module Gitlab ...@@ -31,6 +31,8 @@ module Gitlab
@project.import_start @project.import_start
end end
end end
@project
end end
end end
end end
......
module Gitlab module Gitlab
class PushDataBuilder class PushDataBuilder
# Produce a hash of post-receive data class << self
# # Produce a hash of post-receive data
# data = { #
# before: String, # data = {
# after: String, # before: String,
# ref: String, # after: String,
# user_id: String, # ref: String,
# user_name: String, # user_id: String,
# project_id: String, # user_name: String,
# repository: { # project_id: String,
# name: String, # repository: {
# url: String, # name: String,
# description: String, # url: String,
# homepage: String, # description: String,
# }, # homepage: String,
# commits: Array, # },
# total_commits_count: Fixnum # commits: Array,
# } # total_commits_count: Fixnum
# # }
def self.build(project, user, oldrev, newrev, ref, commits = []) #
# Total commits count def build(project, user, oldrev, newrev, ref, commits = [])
commits_count = commits.size # Total commits count
commits_count = commits.size
# Get latest 20 commits ASC # Get latest 20 commits ASC
commits_limited = commits.last(20) commits_limited = commits.last(20)
# Hash to be passed as post_receive_data # Hash to be passed as post_receive_data
data = { data = {
before: oldrev, before: oldrev,
after: newrev, after: newrev,
ref: ref, ref: ref,
user_id: user.id, checkout_sha: checkout_sha(project.repository, newrev, ref),
user_name: user.name, user_id: user.id,
project_id: project.id, user_name: user.name,
repository: { project_id: project.id,
name: project.name, repository: {
url: project.url_to_repo, name: project.name,
description: project.description, url: project.url_to_repo,
homepage: project.web_url, description: project.description,
}, homepage: project.web_url,
commits: [], },
total_commits_count: commits_count commits: [],
} total_commits_count: commits_count
}
# For performance purposes maximum 20 latest commits # For performance purposes maximum 20 latest commits
# will be passed as post receive hook data. # will be passed as post receive hook data.
commits_limited.each do |commit| commits_limited.each do |commit|
data[:commits] << commit.hook_attrs(project) data[:commits] << commit.hook_attrs(project)
end
data
end end
data # This method provide a sample data generated with
end # existing project and commits to test web hooks
def build_sample(project, user)
commits = project.repository.commits(project.default_branch, nil, 3)
build(project, user, commits.last.id, commits.first.id, "refs/heads/#{project.default_branch}", commits)
end
# This method provide a sample data generated with def checkout_sha(repository, newrev, ref)
# existing project and commits to test web hooks if newrev != Gitlab::Git::BLANK_SHA && ref.start_with?('refs/tags/')
def self.build_sample(project, user) tag_name = Gitlab::Git.extract_ref_name(ref)
commits = project.repository.commits(project.default_branch, nil, 3) tag = repository.find_tag(tag_name)
build(project, user, commits.last.id, commits.first.id, "refs/heads/#{project.default_branch}", commits)
if tag
commit = repository.commit(tag.target)
commit.try(:sha)
end
else
newrev
end
end
end end
end end
end end
...@@ -21,23 +21,22 @@ class Redcarpet::Render::GitlabHTML < Redcarpet::Render::HTML ...@@ -21,23 +21,22 @@ class Redcarpet::Render::GitlabHTML < Redcarpet::Render::HTML
text.gsub("'", "&rsquo;") text.gsub("'", "&rsquo;")
end end
# Stolen from Rugments::Plugins::Redcarpet as this module is not required
# from Rugments's gem root.
def block_code(code, language) def block_code(code, language)
# New lines are placed to fix an rendering issue lexer = Rugments::Lexer.find_fancy(language, code) || Rugments::Lexers::PlainText
# with code wrapped inside <h1> tag for next case:
#
# # Title kinda h1
#
# ruby code here
#
<<-HTML
<div class="highlighted-data #{h.user_color_scheme_class}"> # XXX HACK: Redcarpet strips hard tabs out of code blocks,
<div class="highlight"> # so we assume you're not using leading spaces that aren't tabs,
<pre><code class="#{language}">#{h.send(:html_escape, code)}</code></pre> # and just replace them here.
</div> if lexer.tag == 'make'
</div> code.gsub! /^ /, "\t"
end
HTML formatter = Rugments::Formatters::HTML.new(
cssclass: "code highlight white #{lexer.tag}"
)
formatter.format(lexer.lex(code))
end end
def link(link, title, content) def link(link, title, content)
......
...@@ -25,7 +25,7 @@ namespace :gitlab do ...@@ -25,7 +25,7 @@ namespace :gitlab do
puts "Processing #{repo_path}".yellow puts "Processing #{repo_path}".yellow
if path =~ /\.wiki\Z/ if path.end_with?('.wiki')
puts " * Skipping wiki repo" puts " * Skipping wiki repo"
next next
end end
...@@ -66,6 +66,7 @@ namespace :gitlab do ...@@ -66,6 +66,7 @@ namespace :gitlab do
puts " * Created #{project.name} (#{repo_path})".green puts " * Created #{project.name} (#{repo_path})".green
else else
puts " * Failed trying to create #{project.name} (#{repo_path})".red puts " * Failed trying to create #{project.name} (#{repo_path})".red
puts " Validation Errors: #{project.errors.messages}".red
end end
end end
end end
......
...@@ -54,8 +54,8 @@ namespace :gitlab do ...@@ -54,8 +54,8 @@ namespace :gitlab do
<div class='footer' style='margin-top: 10px;'> <div class='footer' style='margin-top: 10px;'>
<p> <p>
<br> <br>
You're receiving this notification because you are a member of the Base / Rails Project project team.
<a href=\"#{url}\">View it on GitLab</a> <a href=\"#{url}\">View it on GitLab</a>
You're receiving this notification because you are a member of the Base / Rails Project project team.
#{schema} #{schema}
</p> </p>
</div> </div>
......
...@@ -20,7 +20,6 @@ FactoryGirl.define do ...@@ -20,7 +20,6 @@ FactoryGirl.define do
name name
sequence(:username) { |n| "#{Faker::Internet.user_name}#{n}" } sequence(:username) { |n| "#{Faker::Internet.user_name}#{n}" }
password "12345678" password "12345678"
password_confirmation { password }
confirmed_at { Time.now } confirmed_at { Time.now }
confirmation_token { nil } confirmation_token { nil }
......
require 'spec_helper'
describe 'Help Pages', feature: true do
describe 'Show SSH page' do
before do
login_as :user
end
it 'replace the variable $your_email with the email of the user' do
visit help_page_path(category: 'ssh', file: 'ssh.md')
page.should have_content("ssh-keygen -t rsa -C \"#{@user.email}\"")
end
end
end
...@@ -72,34 +72,30 @@ describe 'Comments' do ...@@ -72,34 +72,30 @@ describe 'Comments' do
it "should show the note edit form and hide the note body" do it "should show the note edit form and hide the note body" do
within("#note_#{note.id}") do within("#note_#{note.id}") do
find(".current-note-edit-form", visible: true).should be_visible
find(".note-edit-form", visible: true).should be_visible find(".note-edit-form", visible: true).should be_visible
find(".note-text", visible: false).should_not be_visible find(:css, ".note-text", visible: false).should_not be_visible
end end
end end
it "should reset the edit note form textarea with the original content of the note if cancelled" do # TODO: fix after 7.7 release
find('.note').hover #it "should reset the edit note form textarea with the original content of the note if cancelled" do
find(".js-note-edit").click #within(".current-note-edit-form") do
#fill_in "note[note]", with: "Some new content"
within(".note-edit-form") do #find(".btn-cancel").click
fill_in "note[note]", with: "Some new content" #find(".js-note-text", visible: false).text.should == note.note
find(".btn-cancel").click #end
find(".js-note-text", visible: false).text.should == note.note #end
end
end
it "appends the edited at time to the note" do it "appends the edited at time to the note" do
find('.note').hover within(".current-note-edit-form") do
find(".js-note-edit").click
within(".note-edit-form") do
fill_in "note[note]", with: "Some new content" fill_in "note[note]", with: "Some new content"
find(".btn-save").click find(".btn-save").click
end end
within("#note_#{note.id}") do within("#note_#{note.id}") do
should have_css(".note-last-update small") should have_css(".note_edited_ago")
find(".note-last-update small").text.should match(/Edited less than a minute ago/) find(".note_edited_ago").text.should match(/less than a minute ago/)
end end
end end
end end
...@@ -119,7 +115,7 @@ describe 'Comments' do ...@@ -119,7 +115,7 @@ describe 'Comments' do
it "removes the attachment div and resets the edit form" do it "removes the attachment div and resets the edit form" do
find(".js-note-attachment-delete").click find(".js-note-attachment-delete").click
should_not have_css(".note-attachment") should_not have_css(".note-attachment")
find(".note-edit-form", visible: false).should_not be_visible find(".current-note-edit-form", visible: false).should_not be_visible
end end
end end
end end
......
...@@ -11,7 +11,7 @@ describe 'Users', feature: true do ...@@ -11,7 +11,7 @@ describe 'Users', feature: true do
fill_in "user_name", with: "Name Surname" fill_in "user_name", with: "Name Surname"
fill_in "user_username", with: "Great" fill_in "user_username", with: "Great"
fill_in "user_email", with: "name@mail.com" fill_in "user_email", with: "name@mail.com"
fill_in "user_password_sign_up", with: "password1234" fill_in "user_password", with: "password1234"
fill_in "user_password_confirmation", with: "password1234" fill_in "user_password_confirmation", with: "password1234"
expect { click_button "Sign up" }.to change {User.count}.by(1) expect { click_button "Sign up" }.to change {User.count}.by(1)
end end
......
...@@ -73,7 +73,7 @@ describe ApplicationHelper do ...@@ -73,7 +73,7 @@ describe ApplicationHelper do
user = create(:user) user = create(:user)
user.avatar = File.open(avatar_file_path) user.avatar = File.open(avatar_file_path)
user.save! user.save!
avatar_icon(user.email).to_s.should match("/gitlab//uploads/user/avatar/#{ user.id }/gitlab_logo.png") avatar_icon(user.email).to_s.should match("/gitlab/uploads/user/avatar/#{ user.id }/gitlab_logo.png")
end end
it "should call gravatar_icon when no avatar is present" do it "should call gravatar_icon when no avatar is present" do
......
...@@ -26,7 +26,8 @@ describe EventsHelper do ...@@ -26,7 +26,8 @@ describe EventsHelper do
it 'should display the first line of a code block' do it 'should display the first line of a code block' do
input = "```\nCode block\nwith two lines\n```" input = "```\nCode block\nwith two lines\n```"
expected = '<pre><code class="">Code block...</code></pre>' expected = '<pre class="code highlight white plaintext"><code>' \
'Code block...</code></pre>'
expect(event_note(input)).to match(expected) expect(event_note(input)).to match(expected)
end end
......
...@@ -612,7 +612,7 @@ describe GitlabMarkdownHelper do ...@@ -612,7 +612,7 @@ describe GitlabMarkdownHelper do
it "should leave code blocks untouched" do it "should leave code blocks untouched" do
helper.stub(:user_color_scheme_class).and_return(:white) helper.stub(:user_color_scheme_class).and_return(:white)
target_html = "\n<div class=\"highlighted-data white\">\n <div class=\"highlight\">\n <pre><code class=\"\">some code from $#{snippet.id}\nhere too\n</code></pre>\n </div>\n</div>\n\n" target_html = "<pre class=\"code highlight white plaintext\"><code>some code from $40\nhere too\n</code></pre>\n"
helper.markdown("\n some code from $#{snippet.id}\n here too\n").should == target_html helper.markdown("\n some code from $#{snippet.id}\n here too\n").should == target_html
helper.markdown("\n```\nsome code from $#{snippet.id}\nhere too\n```\n").should == target_html helper.markdown("\n```\nsome code from $#{snippet.id}\nhere too\n```\n").should == target_html
......
require 'spec_helper'
describe Gitlab::ClosingIssueExtractor do
let(:project) { create(:project) }
let(:issue) { create(:issue, project: project) }
let(:iid1) { issue.iid }
describe :closed_by_message_in_project do
context 'with a single reference' do
it do
message = "Awesome commit (Closes ##{iid1})"
subject.closed_by_message_in_project(message, project).should == [issue]
end
it do
message = "Awesome commit (closes ##{iid1})"
subject.closed_by_message_in_project(message, project).should == [issue]
end
it do
message = "Closed ##{iid1}"
subject.closed_by_message_in_project(message, project).should == [issue]
end
it do
message = "closed ##{iid1}"
subject.closed_by_message_in_project(message, project).should == [issue]
end
it do
message = "Awesome commit (fixes ##{iid1})"
subject.closed_by_message_in_project(message, project).should == [issue]
end
it do
message = "Awesome commit (fix ##{iid1})"
subject.closed_by_message_in_project(message, project).should == [issue]
end
end
context 'with multiple references' do
let(:other_issue) { create(:issue, project: project) }
let(:third_issue) { create(:issue, project: project) }
let(:iid2) { other_issue.iid }
let(:iid3) { third_issue.iid }
it 'fetches issues in single line message' do
message = "Closes ##{iid1} and fix ##{iid2}"
subject.closed_by_message_in_project(message, project).
should == [issue, other_issue]
end
it 'fetches comma-separated issues references in single line message' do
message = "Closes ##{iid1}, closes ##{iid2}"
subject.closed_by_message_in_project(message, project).
should == [issue, other_issue]
end
it 'fetches comma-separated issues numbers in single line message' do
message = "Closes ##{iid1}, ##{iid2} and ##{iid3}"
subject.closed_by_message_in_project(message, project).
should == [issue, other_issue, third_issue]
end
it 'fetches issues in multi-line message' do
message = "Awesome commit (closes ##{iid1})\nAlso fixes ##{iid2}"
subject.closed_by_message_in_project(message, project).
should == [issue, other_issue]
end
it 'fetches issues in hybrid message' do
message = "Awesome commit (closes ##{iid1})\n"\
"Also fixing issues ##{iid2}, ##{iid3} and #4"
subject.closed_by_message_in_project(message, project).
should == [issue, other_issue, third_issue]
end
end
end
end
...@@ -5,6 +5,68 @@ describe Gitlab::GitAccess do ...@@ -5,6 +5,68 @@ describe Gitlab::GitAccess do
let(:project) { create(:project) } let(:project) { create(:project) }
let(:user) { create(:user) } let(:user) { create(:user) }
describe 'can_push_to_branch?' do
describe 'push to none protected branch' do
it "returns true if user is a master" do
project.team << [user, :master]
Gitlab::GitAccess.can_push_to_branch?(user, project, "random_branch").should be_true
end
it "returns true if user is a developer" do
project.team << [user, :developer]
Gitlab::GitAccess.can_push_to_branch?(user, project, "random_branch").should be_true
end
it "returns false if user is a reporter" do
project.team << [user, :reporter]
Gitlab::GitAccess.can_push_to_branch?(user, project, "random_branch").should be_false
end
end
describe 'push to protected branch' do
before do
@branch = create :protected_branch, project: project
end
it "returns true if user is a master" do
project.team << [user, :master]
Gitlab::GitAccess.can_push_to_branch?(user, project, @branch.name).should be_true
end
it "returns false if user is a developer" do
project.team << [user, :developer]
Gitlab::GitAccess.can_push_to_branch?(user, project, @branch.name).should be_false
end
it "returns false if user is a reporter" do
project.team << [user, :reporter]
Gitlab::GitAccess.can_push_to_branch?(user, project, @branch.name).should be_false
end
end
describe 'push to protected branch if allowed for developers' do
before do
@branch = create :protected_branch, project: project, developers_can_push: true
end
it "returns true if user is a master" do
project.team << [user, :master]
Gitlab::GitAccess.can_push_to_branch?(user, project, @branch.name).should be_true
end
it "returns true if user is a developer" do
project.team << [user, :developer]
Gitlab::GitAccess.can_push_to_branch?(user, project, @branch.name).should be_true
end
it "returns false if user is a reporter" do
project.team << [user, :reporter]
Gitlab::GitAccess.can_push_to_branch?(user, project, @branch.name).should be_false
end
end
end
describe 'download_access_check' do describe 'download_access_check' do
describe 'master permissions' do describe 'master permissions' do
before { project.team << [user, :master] } before { project.team << [user, :master] }
......
...@@ -21,13 +21,14 @@ describe 'Gitlab::PushDataBuilder' do ...@@ -21,13 +21,14 @@ describe 'Gitlab::PushDataBuilder' do
Gitlab::PushDataBuilder.build(project, Gitlab::PushDataBuilder.build(project,
user, user,
Gitlab::Git::BLANK_SHA, Gitlab::Git::BLANK_SHA,
'5937ac0a7beb003549fc5fd26fc247adbce4a52e', '8a2a6eb295bb170b34c24c76c49ed0e9b2eaf34b',
'refs/tags/v1.1.0') 'refs/tags/v1.1.0')
end end
it { data.should be_a(Hash) } it { data.should be_a(Hash) }
it { data[:before].should == Gitlab::Git::BLANK_SHA } it { data[:before].should == Gitlab::Git::BLANK_SHA }
it { data[:after].should == '5937ac0a7beb003549fc5fd26fc247adbce4a52e' } it { data[:checkout_sha].should == '5937ac0a7beb003549fc5fd26fc247adbce4a52e' }
it { data[:after].should == '8a2a6eb295bb170b34c24c76c49ed0e9b2eaf34b' }
it { data[:ref].should == 'refs/tags/v1.1.0' } it { data[:ref].should == 'refs/tags/v1.1.0' }
it { data[:commits].should be_empty } it { data[:commits].should be_empty }
it { data[:total_commits_count].should be_zero } it { data[:total_commits_count].should be_zero }
......
...@@ -57,16 +57,12 @@ eos ...@@ -57,16 +57,12 @@ eos
let(:other_issue) { create :issue, project: other_project } let(:other_issue) { create :issue, project: other_project }
it 'detects issues that this commit is marked as closing' do it 'detects issues that this commit is marked as closing' do
stub_const('Gitlab::ClosingIssueExtractor::ISSUE_CLOSING_REGEX',
/Fixes #\d+/)
commit.stub(safe_message: "Fixes ##{issue.iid}") commit.stub(safe_message: "Fixes ##{issue.iid}")
commit.closes_issues(project).should == [issue] commit.closes_issues(project).should == [issue]
end end
it 'does not detect issues from other projects' do it 'does not detect issues from other projects' do
ext_ref = "#{other_project.path_with_namespace}##{other_issue.iid}" ext_ref = "#{other_project.path_with_namespace}##{other_issue.iid}"
stub_const('Gitlab::ClosingIssueExtractor::ISSUE_CLOSING_REGEX',
/^([Cc]loses|[Ff]ixes)/)
commit.stub(safe_message: "Fixes #{ext_ref}") commit.stub(safe_message: "Fixes #{ext_ref}")
commit.closes_issues(project).should be_empty commit.closes_issues(project).should be_empty
end end
......
...@@ -36,7 +36,7 @@ describe WikiPage do ...@@ -36,7 +36,7 @@ describe WikiPage do
end end
it "sets the version attribute" do it "sets the version attribute" do
@wiki_page.version.should be_a Grit::Commit @wiki_page.version.should be_a Gollum::Git::Commit
end end
end end
end end
......
...@@ -12,14 +12,23 @@ describe MergeRequests::CloseService do ...@@ -12,14 +12,23 @@ describe MergeRequests::CloseService do
end end
describe :execute do describe :execute do
context "valid params" do context 'valid params' do
let(:service) { MergeRequests::CloseService.new(project, user, {}) }
before do before do
@merge_request = MergeRequests::CloseService.new(project, user, {}).execute(merge_request) service.stub(:execute_hooks)
@merge_request = service.execute(merge_request)
end end
it { @merge_request.should be_valid } it { @merge_request.should be_valid }
it { @merge_request.should be_closed } it { @merge_request.should be_closed }
it 'should execute hooks with close action' do
expect(service).to have_received(:execute_hooks).
with(@merge_request, 'close')
end
it 'should send email to user2 about assign of new merge_request' do it 'should send email to user2 about assign of new merge_request' do
email = ActionMailer::Base.deliveries.last email = ActionMailer::Base.deliveries.last
email.to.first.should == user2.email email.to.first.should == user2.email
...@@ -28,7 +37,7 @@ describe MergeRequests::CloseService do ...@@ -28,7 +37,7 @@ describe MergeRequests::CloseService do
it 'should create system note about merge_request reassign' do it 'should create system note about merge_request reassign' do
note = @merge_request.notes.last note = @merge_request.notes.last
note.note.should include "Status changed to closed" note.note.should include 'Status changed to closed'
end end
end end
end end
......
...@@ -5,21 +5,30 @@ describe MergeRequests::CreateService do ...@@ -5,21 +5,30 @@ describe MergeRequests::CreateService do
let(:user) { create(:user) } let(:user) { create(:user) }
describe :execute do describe :execute do
context "valid params" do context 'valid params' do
before do let(:opts) do
project.team << [user, :master] {
opts = {
title: 'Awesome merge_request', title: 'Awesome merge_request',
description: 'please fix', description: 'please fix',
source_branch: 'stable', source_branch: 'stable',
target_branch: 'master' target_branch: 'master'
} }
end
let(:service) { MergeRequests::CreateService.new(project, user, opts) }
before do
project.team << [user, :master]
service.stub(:execute_hooks)
@merge_request = MergeRequests::CreateService.new(project, user, opts).execute @merge_request = service.execute
end end
it { @merge_request.should be_valid } it { @merge_request.should be_valid }
it { @merge_request.title.should == 'Awesome merge_request' } it { @merge_request.title.should == 'Awesome merge_request' }
it 'should execute hooks with default action' do
expect(service).to have_received(:execute_hooks).with(@merge_request)
end
end end
end end
end end
require 'spec_helper'
describe MergeRequests::MergeService do
let(:user) { create(:user) }
let(:user2) { create(:user) }
let(:merge_request) { create(:merge_request, assignee: user2) }
let(:project) { merge_request.project }
before do
project.team << [user, :master]
project.team << [user2, :developer]
end
describe :execute do
context 'valid params' do
let(:service) { MergeRequests::MergeService.new(project, user, {}) }
before do
service.stub(:execute_hooks)
service.execute(merge_request, 'Awesome message')
end
it { merge_request.should be_valid }
it { merge_request.should be_merged }
it 'should execute hooks with merge action' do
expect(service).to have_received(:execute_hooks).
with(merge_request, 'merge')
end
it 'should send email to user2 about merge of new merge_request' do
email = ActionMailer::Base.deliveries.last
email.to.first.should == user2.email
email.subject.should include(merge_request.title)
end
it 'should create system note about merge_request merge' do
note = merge_request.notes.last
note.note.should include 'Status changed to merged'
end
end
end
end
require 'spec_helper'
describe MergeRequests::ReopenService do
let(:user) { create(:user) }
let(:user2) { create(:user) }
let(:merge_request) { create(:merge_request, assignee: user2) }
let(:project) { merge_request.project }
before do
project.team << [user, :master]
project.team << [user2, :developer]
end
describe :execute do
context 'valid params' do
let(:service) { MergeRequests::ReopenService.new(project, user, {}) }
before do
service.stub(:execute_hooks)
merge_request.state = :closed
service.execute(merge_request)
end
it { merge_request.should be_valid }
it { merge_request.should be_reopened }
it 'should execute hooks with reopen action' do
expect(service).to have_received(:execute_hooks).
with(merge_request, 'reopen')
end
it 'should send email to user2 about reopen of merge_request' do
email = ActionMailer::Base.deliveries.last
email.to.first.should == user2.email
email.subject.should include(merge_request.title)
end
it 'should create system note about merge_request reopen' do
note = merge_request.notes.last
note.note.should include 'Status changed to reopened'
end
end
end
end
...@@ -12,16 +12,21 @@ describe MergeRequests::UpdateService do ...@@ -12,16 +12,21 @@ describe MergeRequests::UpdateService do
end end
describe :execute do describe :execute do
context "valid params" do context 'valid params' do
before do let(:opts) do
opts = { {
title: 'New title', title: 'New title',
description: 'Also please fix', description: 'Also please fix',
assignee_id: user2.id, assignee_id: user2.id,
state_event: 'close' state_event: 'close'
} }
end
let(:service) { MergeRequests::UpdateService.new(project, user, opts) }
before do
service.stub(:execute_hooks)
@merge_request = MergeRequests::UpdateService.new(project, user, opts).execute(merge_request) @merge_request = service.execute(merge_request)
end end
it { @merge_request.should be_valid } it { @merge_request.should be_valid }
...@@ -29,6 +34,11 @@ describe MergeRequests::UpdateService do ...@@ -29,6 +34,11 @@ describe MergeRequests::UpdateService do
it { @merge_request.assignee.should == user2 } it { @merge_request.assignee.should == user2 }
it { @merge_request.should be_closed } it { @merge_request.should be_closed }
it 'should execute hooks with update action' do
expect(service).to have_received(:execute_hooks).
with(@merge_request, 'update')
end
it 'should send email to user2 about assign of new merge_request' do it 'should send email to user2 about assign of new merge_request' do
email = ActionMailer::Base.deliveries.last email = ActionMailer::Base.deliveries.last
email.to.first.should == user2.email email.to.first.should == user2.email
......
This source diff could not be displayed because it is too large. You can view the blob instead.
/*!
* jQuery Password Strength plugin for Twitter Bootstrap
*
* Copyright (c) 2008-2013 Tane Piper
* Copyright (c) 2013 Alejandro Blanco
* Dual licensed under the MIT and GPL licenses.
*/
(function (jQuery) {
// Source: src/rules.js
var rulesEngine = {};
try {
if (!jQuery && module && module.exports) {
var jQuery = require("jquery"),
jsdom = require("jsdom").jsdom;
jQuery = jQuery(jsdom().parentWindow);
}
} catch (ignore) {}
(function ($, rulesEngine) {
"use strict";
var validation = {};
rulesEngine.forbiddenSequences = [
"0123456789", "abcdefghijklmnopqrstuvwxyz", "qwertyuiop", "asdfghjkl",
"zxcvbnm", "!@#$%^&*()_+"
];
validation.wordNotEmail = function (options, word, score) {
if (word.match(/^([\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+\.)*[\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+@((((([a-z0-9]{1}[a-z0-9\-]{0,62}[a-z0-9]{1})|[a-z])\.)+[a-z]{2,6})|(\d{1,3}\.){3}\d{1,3}(\:\d{1,5})?)$/i)) {
return score;
}
return 0;
};
validation.wordLength = function (options, word, score) {
var wordlen = word.length,
lenScore = Math.pow(wordlen, options.rules.raisePower);
if (wordlen < options.common.minChar) {
lenScore = (lenScore + score);
}
return lenScore;
};
validation.wordSimilarToUsername = function (options, word, score) {
var username = $(options.common.usernameField).val();
if (username && word.toLowerCase().match(username.toLowerCase())) {
return score;
}
return 0;
};
validation.wordTwoCharacterClasses = function (options, word, score) {
if (word.match(/([a-z].*[A-Z])|([A-Z].*[a-z])/) ||
(word.match(/([a-zA-Z])/) && word.match(/([0-9])/)) ||
(word.match(/(.[!,@,#,$,%,\^,&,*,?,_,~])/) && word.match(/[a-zA-Z0-9_]/))) {
return score;
}
return 0;
};
validation.wordRepetitions = function (options, word, score) {
if (word.match(/(.)\1\1/)) { return score; }
return 0;
};
validation.wordSequences = function (options, word, score) {
var found = false,
j;
if (word.length > 2) {
$.each(rulesEngine.forbiddenSequences, function (idx, seq) {
var sequences = [seq, seq.split('').reverse().join('')];
$.each(sequences, function (idx, sequence) {
for (j = 0; j < (word.length - 2); j += 1) { // iterate the word trough a sliding window of size 3:
if (sequence.indexOf(word.toLowerCase().substring(j, j + 3)) > -1) {
found = true;
}
}
});
});
if (found) { return score; }
}
return 0;
};
validation.wordLowercase = function (options, word, score) {
return word.match(/[a-z]/) && score;
};
validation.wordUppercase = function (options, word, score) {
return word.match(/[A-Z]/) && score;
};
validation.wordOneNumber = function (options, word, score) {
return word.match(/\d+/) && score;
};
validation.wordThreeNumbers = function (options, word, score) {
return word.match(/(.*[0-9].*[0-9].*[0-9])/) && score;
};
validation.wordOneSpecialChar = function (options, word, score) {
return word.match(/.[!,@,#,$,%,\^,&,*,?,_,~]/) && score;
};
validation.wordTwoSpecialChar = function (options, word, score) {
return word.match(/(.*[!,@,#,$,%,\^,&,*,?,_,~].*[!,@,#,$,%,\^,&,*,?,_,~])/) && score;
};
validation.wordUpperLowerCombo = function (options, word, score) {
return word.match(/([a-z].*[A-Z])|([A-Z].*[a-z])/) && score;
};
validation.wordLetterNumberCombo = function (options, word, score) {
return word.match(/([a-zA-Z])/) && word.match(/([0-9])/) && score;
};
validation.wordLetterNumberCharCombo = function (options, word, score) {
return word.match(/([a-zA-Z0-9].*[!,@,#,$,%,\^,&,*,?,_,~])|([!,@,#,$,%,\^,&,*,?,_,~].*[a-zA-Z0-9])/) && score;
};
rulesEngine.validation = validation;
rulesEngine.executeRules = function (options, word) {
var totalScore = 0;
$.each(options.rules.activated, function (rule, active) {
if (active) {
var score = options.rules.scores[rule],
funct = rulesEngine.validation[rule],
result,
errorMessage;
if (!$.isFunction(funct)) {
funct = options.rules.extra[rule];
}
if ($.isFunction(funct)) {
result = funct(options, word, score);
if (result) {
totalScore += result;
}
if (result < 0 || (!$.isNumeric(result) && !result)) {
errorMessage = options.ui.spanError(options, rule);
if (errorMessage.length > 0) {
options.instances.errors.push(errorMessage);
}
}
}
}
});
return totalScore;
};
}(jQuery, rulesEngine));
try {
if (module && module.exports) {
module.exports = rulesEngine;
}
} catch (ignore) {}
// Source: src/options.js
var defaultOptions = {};
defaultOptions.common = {};
defaultOptions.common.minChar = 6;
defaultOptions.common.usernameField = "#username";
defaultOptions.common.userInputs = [
// Selectors for input fields with user input
];
defaultOptions.common.onLoad = undefined;
defaultOptions.common.onKeyUp = undefined;
defaultOptions.common.zxcvbn = false;
defaultOptions.common.debug = false;
defaultOptions.rules = {};
defaultOptions.rules.extra = {};
defaultOptions.rules.scores = {
wordNotEmail: -100,
wordLength: -50,
wordSimilarToUsername: -100,
wordSequences: -50,
wordTwoCharacterClasses: 2,
wordRepetitions: -25,
wordLowercase: 1,
wordUppercase: 3,
wordOneNumber: 3,
wordThreeNumbers: 5,
wordOneSpecialChar: 3,
wordTwoSpecialChar: 5,
wordUpperLowerCombo: 2,
wordLetterNumberCombo: 2,
wordLetterNumberCharCombo: 2
};
defaultOptions.rules.activated = {
wordNotEmail: true,
wordLength: true,
wordSimilarToUsername: true,
wordSequences: true,
wordTwoCharacterClasses: false,
wordRepetitions: false,
wordLowercase: true,
wordUppercase: true,
wordOneNumber: true,
wordThreeNumbers: true,
wordOneSpecialChar: true,
wordTwoSpecialChar: true,
wordUpperLowerCombo: true,
wordLetterNumberCombo: true,
wordLetterNumberCharCombo: true
};
defaultOptions.rules.raisePower = 1.4;
defaultOptions.ui = {};
defaultOptions.ui.bootstrap2 = false;
defaultOptions.ui.showProgressBar = true;
defaultOptions.ui.showPopover = false;
defaultOptions.ui.showStatus = false;
defaultOptions.ui.spanError = function (options, key) {
"use strict";
var text = options.ui.errorMessages[key];
if (!text) { return ''; }
return '<span style="color: #d52929">' + text + '</span>';
};
defaultOptions.ui.errorMessages = {
wordLength: "Your password is too short",
wordNotEmail: "Do not use your email as your password",
wordSimilarToUsername: "Your password cannot contain your username",
wordTwoCharacterClasses: "Use different character classes",
wordRepetitions: "Too many repetitions",
wordSequences: "Your password contains sequences"
};
defaultOptions.ui.verdicts = ["Weak", "Normal", "Medium", "Strong", "Very Strong"];
defaultOptions.ui.showVerdicts = true;
defaultOptions.ui.showVerdictsInsideProgressBar = false;
defaultOptions.ui.showErrors = false;
defaultOptions.ui.container = undefined;
defaultOptions.ui.viewports = {
progress: undefined,
verdict: undefined,
errors: undefined
};
defaultOptions.ui.scores = [14, 26, 38, 50];
// Source: src/ui.js
var ui = {};
(function ($, ui) {
"use strict";
var barClasses = ["danger", "warning", "success"],
statusClasses = ["error", "warning", "success"];
ui.getContainer = function (options, $el) {
var $container;
$container = $(options.ui.container);
if (!($container && $container.length === 1)) {
$container = $el.parent();
}
return $container;
};
ui.findElement = function ($container, viewport, cssSelector) {
if (viewport) {
return $container.find(viewport).find(cssSelector);
}
return $container.find(cssSelector);
};
ui.getUIElements = function (options, $el) {
var $container, result;
if (options.instances.viewports) {
return options.instances.viewports;
}
$container = ui.getContainer(options, $el);
result = {};
result.$progressbar = ui.findElement($container, options.ui.viewports.progress, "div.progress");
if (options.ui.showVerdictsInsideProgressBar) {
result.$verdict = result.$progressbar.find("span.password-verdict");
}
if (!options.ui.showPopover) {
if (!options.ui.showVerdictsInsideProgressBar) {
result.$verdict = ui.findElement($container, options.ui.viewports.verdict, "span.password-verdict");
}
result.$errors = ui.findElement($container, options.ui.viewports.errors, "ul.error-list");
}
options.instances.viewports = result;
return result;
};
ui.initProgressBar = function (options, $el) {
var $container = ui.getContainer(options, $el),
progressbar = "<div class='progress'><div class='";
if (!options.ui.bootstrap2) {
progressbar += "progress-";
}
progressbar += "bar'>";
if (options.ui.showVerdictsInsideProgressBar) {
progressbar += "<span class='password-verdict'></span>";
}
progressbar += "</div></div>";
if (options.ui.viewports.progress) {
$container.find(options.ui.viewports.progress).append(progressbar);
} else {
$(progressbar).insertAfter($el);
}
};
ui.initHelper = function (options, $el, html, viewport) {
var $container = ui.getContainer(options, $el);
if (viewport) {
$container.find(viewport).append(html);
} else {
$(html).insertAfter($el);
}
};
ui.initVerdict = function (options, $el) {
ui.initHelper(options, $el, "<span class='password-verdict'></span>",
options.ui.viewports.verdict);
};
ui.initErrorList = function (options, $el) {
ui.initHelper(options, $el, "<ul class='error-list'></ul>",
options.ui.viewports.errors);
};
ui.initPopover = function (options, $el) {
$el.popover("destroy");
$el.popover({
html: true,
placement: "top",
trigger: "manual",
content: " "
});
};
ui.initUI = function (options, $el) {
if (options.ui.showPopover) {
ui.initPopover(options, $el);
} else {
if (options.ui.showErrors) { ui.initErrorList(options, $el); }
if (options.ui.showVerdicts && !options.ui.showVerdictsInsideProgressBar) {
ui.initVerdict(options, $el);
}
}
if (options.ui.showProgressBar) {
ui.initProgressBar(options, $el);
}
};
ui.possibleProgressBarClasses = ["danger", "warning", "success"];
ui.updateProgressBar = function (options, $el, cssClass, percentage) {
var $progressbar = ui.getUIElements(options, $el).$progressbar,
$bar = $progressbar.find(".progress-bar"),
cssPrefix = "progress-";
if (options.ui.bootstrap2) {
$bar = $progressbar.find(".bar");
cssPrefix = "";
}
$.each(ui.possibleProgressBarClasses, function (idx, value) {
$bar.removeClass(cssPrefix + "bar-" + value);
});
$bar.addClass(cssPrefix + "bar-" + barClasses[cssClass]);
$bar.css("width", percentage + '%');
};
ui.updateVerdict = function (options, $el, text) {
var $verdict = ui.getUIElements(options, $el).$verdict;
$verdict.text(text);
};
ui.updateErrors = function (options, $el) {
var $errors = ui.getUIElements(options, $el).$errors,
html = "";
$.each(options.instances.errors, function (idx, err) {
html += "<li>" + err + "</li>";
});
$errors.html(html);
};
ui.updatePopover = function (options, $el, verdictText) {
var popover = $el.data("bs.popover"),
html = "",
hide = true;
if (options.ui.showVerdicts &&
!options.ui.showVerdictsInsideProgressBar &&
verdictText.length > 0) {
html = "<h5><span class='password-verdict'>" + verdictText +
"</span></h5>";
hide = false;
}
if (options.ui.showErrors) {
html += "<div><ul class='error-list' style='margin-bottom: 0; margin-left: -20px'>";
$.each(options.instances.errors, function (idx, err) {
html += "<li>" + err + "</li>";
hide = false;
});
html += "</ul></div>";
}
if (hide) {
$el.popover("hide");
return;
}
if (options.ui.bootstrap2) { popover = $el.data("popover"); }
if (popover.$arrow && popover.$arrow.parents("body").length > 0) {
$el.find("+ .popover .popover-content").html(html);
} else {
// It's hidden
popover.options.content = html;
$el.popover("show");
}
};
ui.updateFieldStatus = function (options, $el, cssClass) {
var targetClass = options.ui.bootstrap2 ? ".control-group" : ".form-group",
$container = $el.parents(targetClass).first();
$.each(statusClasses, function (idx, css) {
if (!options.ui.bootstrap2) { css = "has-" + css; }
$container.removeClass(css);
});
cssClass = statusClasses[cssClass];
if (!options.ui.bootstrap2) { cssClass = "has-" + cssClass; }
$container.addClass(cssClass);
};
ui.percentage = function (score, maximun) {
var result = Math.floor(100 * score / maximun);
result = result < 0 ? 0 : result;
result = result > 100 ? 100 : result;
return result;
};
ui.getVerdictAndCssClass = function (options, score) {
var cssClass, verdictText, level;
if (score <= 0) {
cssClass = 0;
level = -1;
verdictText = options.ui.verdicts[0];
} else if (score < options.ui.scores[0]) {
cssClass = 0;
level = 0;
verdictText = options.ui.verdicts[0];
} else if (score < options.ui.scores[1]) {
cssClass = 0;
level = 1;
verdictText = options.ui.verdicts[1];
} else if (score < options.ui.scores[2]) {
cssClass = 1;
level = 2;
verdictText = options.ui.verdicts[2];
} else if (score < options.ui.scores[3]) {
cssClass = 1;
level = 3;
verdictText = options.ui.verdicts[3];
} else {
cssClass = 2;
level = 4;
verdictText = options.ui.verdicts[4];
}
return [verdictText, cssClass, level];
};
ui.updateUI = function (options, $el, score) {
var cssClass, barPercentage, verdictText;
cssClass = ui.getVerdictAndCssClass(options, score);
verdictText = cssClass[0];
cssClass = cssClass[1];
if (options.ui.showProgressBar) {
barPercentage = ui.percentage(score, options.ui.scores[3]);
ui.updateProgressBar(options, $el, cssClass, barPercentage);
if (options.ui.showVerdictsInsideProgressBar) {
ui.updateVerdict(options, $el, verdictText);
}
}
if (options.ui.showStatus) {
ui.updateFieldStatus(options, $el, cssClass);
}
if (options.ui.showPopover) {
ui.updatePopover(options, $el, verdictText);
} else {
if (options.ui.showVerdicts && !options.ui.showVerdictsInsideProgressBar) {
ui.updateVerdict(options, $el, verdictText);
}
if (options.ui.showErrors) {
ui.updateErrors(options, $el);
}
}
};
}(jQuery, ui));
// Source: src/methods.js
var methods = {};
(function ($, methods) {
"use strict";
var onKeyUp, applyToAll;
onKeyUp = function (event) {
var $el = $(event.target),
options = $el.data("pwstrength-bootstrap"),
word = $el.val(),
userInputs,
verdictText,
verdictLevel,
score;
if (options === undefined) { return; }
options.instances.errors = [];
if (options.common.zxcvbn) {
userInputs = [];
$.each(options.common.userInputs, function (idx, selector) {
userInputs.push($(selector).val());
});
userInputs.push($(options.common.usernameField).val());
score = zxcvbn(word, userInputs).entropy;
} else {
score = rulesEngine.executeRules(options, word);
}
ui.updateUI(options, $el, score);
verdictText = ui.getVerdictAndCssClass(options, score);
verdictLevel = verdictText[2];
verdictText = verdictText[0];
if (options.common.debug) { console.log(score + ' - ' + verdictText); }
if ($.isFunction(options.common.onKeyUp)) {
options.common.onKeyUp(event, {
score: score,
verdictText: verdictText,
verdictLevel: verdictLevel
});
}
};
methods.init = function (settings) {
this.each(function (idx, el) {
// Make it deep extend (first param) so it extends too the
// rules and other inside objects
var clonedDefaults = $.extend(true, {}, defaultOptions),
localOptions = $.extend(true, clonedDefaults, settings),
$el = $(el);
localOptions.instances = {};
$el.data("pwstrength-bootstrap", localOptions);
$el.on("keyup", onKeyUp);
$el.on("change", onKeyUp);
$el.on("onpaste", onKeyUp);
ui.initUI(localOptions, $el);
if ($.trim($el.val())) { // Not empty, calculate the strength
$el.trigger("keyup");
}
if ($.isFunction(localOptions.common.onLoad)) {
localOptions.common.onLoad();
}
});
return this;
};
methods.destroy = function () {
this.each(function (idx, el) {
var $el = $(el),
options = $el.data("pwstrength-bootstrap"),
elements = ui.getUIElements(options, $el);
elements.$progressbar.remove();
elements.$verdict.remove();
elements.$errors.remove();
$el.removeData("pwstrength-bootstrap");
});
};
methods.forceUpdate = function () {
this.each(function (idx, el) {
var event = { target: el };
onKeyUp(event);
});
};
methods.addRule = function (name, method, score, active) {
this.each(function (idx, el) {
var options = $(el).data("pwstrength-bootstrap");
options.rules.activated[name] = active;
options.rules.scores[name] = score;
options.rules.extra[name] = method;
});
};
applyToAll = function (rule, prop, value) {
this.each(function (idx, el) {
$(el).data("pwstrength-bootstrap").rules[prop][rule] = value;
});
};
methods.changeScore = function (rule, score) {
applyToAll.call(this, rule, "scores", score);
};
methods.ruleActive = function (rule, active) {
applyToAll.call(this, rule, "activated", active);
};
$.fn.pwstrength = function (method) {
var result;
if (methods[method]) {
result = methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
} else if (typeof method === "object" || !method) {
result = methods.init.apply(this, arguments);
} else {
$.error("Method " + method + " does not exist on jQuery.pwstrength-bootstrap");
}
return result;
};
}(jQuery, methods));
}(jQuery));
\ No newline at end of file
.hljs{display:block;padding:.5em;background:#f0f0f0}.hljs,.hljs-subst,.hljs-tag .hljs-title,.lisp .hljs-title,.clojure .hljs-built_in,.nginx .hljs-title{color:black}.hljs-string,.hljs-title,.hljs-constant,.hljs-parent,.hljs-tag .hljs-value,.hljs-rules .hljs-value,.hljs-rules .hljs-value .hljs-number,.hljs-preprocessor,.hljs-pragma,.haml .hljs-symbol,.ruby .hljs-symbol,.ruby .hljs-symbol .hljs-string,.hljs-aggregate,.hljs-template_tag,.django .hljs-variable,.smalltalk .hljs-class,.hljs-addition,.hljs-flow,.hljs-stream,.bash .hljs-variable,.apache .hljs-tag,.apache .hljs-cbracket,.tex .hljs-command,.tex .hljs-special,.erlang_repl .hljs-function_or_atom,.asciidoc .hljs-header,.markdown .hljs-header,.coffeescript .hljs-attribute{color:#800}.smartquote,.hljs-comment,.hljs-annotation,.hljs-template_comment,.diff .hljs-header,.hljs-chunk,.asciidoc .hljs-blockquote,.markdown .hljs-blockquote{color:#888}.hljs-number,.hljs-date,.hljs-regexp,.hljs-literal,.hljs-hexcolor,.smalltalk .hljs-symbol,.smalltalk .hljs-char,.go .hljs-constant,.hljs-change,.lasso .hljs-variable,.makefile .hljs-variable,.asciidoc .hljs-bullet,.markdown .hljs-bullet,.asciidoc .hljs-link_url,.markdown .hljs-link_url{color:#080}.hljs-label,.hljs-javadoc,.ruby .hljs-string,.hljs-decorator,.hljs-filter .hljs-argument,.hljs-localvars,.hljs-array,.hljs-attr_selector,.hljs-important,.hljs-pseudo,.hljs-pi,.haml .hljs-bullet,.hljs-doctype,.hljs-deletion,.hljs-envvar,.hljs-shebang,.apache .hljs-sqbracket,.nginx .hljs-built_in,.tex .hljs-formula,.erlang_repl .hljs-reserved,.hljs-prompt,.asciidoc .hljs-link_label,.markdown .hljs-link_label,.vhdl .hljs-attribute,.clojure .hljs-attribute,.asciidoc .hljs-attribute,.lasso .hljs-attribute,.coffeescript .hljs-property,.hljs-phony{color:#88F}.hljs-keyword,.hljs-id,.hljs-title,.hljs-built_in,.hljs-aggregate,.css .hljs-tag,.hljs-javadoctag,.hljs-phpdoc,.hljs-yardoctag,.smalltalk .hljs-class,.hljs-winutils,.bash .hljs-variable,.apache .hljs-tag,.go .hljs-typename,.tex .hljs-command,.asciidoc .hljs-strong,.markdown .hljs-strong,.hljs-request,.hljs-status{font-weight:bold}.asciidoc .hljs-emphasis,.markdown .hljs-emphasis{font-style:italic}.nginx .hljs-built_in{font-weight:normal}.coffeescript .javascript,.javascript .xml,.lasso .markup,.tex .hljs-formula,.xml .javascript,.xml .vbscript,.xml .css,.xml .hljs-cdata{opacity:.5}
\ No newline at end of file
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