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
group: git
services:
- postgres
before_precompile: ./bin/pkgr_before_precompile.sh
targets:
debian-7: &wheezy
build_dependencies:
- libkrb5-dev
- libicu-dev
- cmake
- pkg-config
......@@ -14,6 +17,7 @@ targets:
ubuntu-12.04: *wheezy
ubuntu-14.04:
build_dependencies:
- libkrb5-dev
- libicu-dev
- cmake
- pkg-config
......@@ -23,6 +27,7 @@ targets:
- git
centos-6:
build_dependencies:
- krb5-devel
- libicu-devel
- cmake
- pkgconfig
......
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
- Import from GitHub.com feature
- Add Jetbrains Teamcity CI service (Jason Lippert)
......@@ -24,6 +82,10 @@ v 7.7.0
- Trigger GitLab CI when push tags
- When accept merge request - do merge using sidaekiq job
- 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
......
......@@ -47,7 +47,7 @@ gem 'gitlab_omniauth-ldap', '1.2.0', require: "omniauth-ldap"
gem 'net-ldap'
# Git Wiki
gem 'gollum-lib', '~> 3.0.0'
gem 'gollum-lib', '~> 4.0.0'
# Language detection
gem "gitlab-linguist", "~> 3.0.0", require: "linguist"
......@@ -267,3 +267,4 @@ end
gem "newrelic_rpm"
gem 'octokit', '3.7.0'
gem "rugments"
......@@ -166,13 +166,14 @@ GEM
rugged (~> 0.19)
gherkin-ruby (0.3.1)
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-grit (>= 2.4.1)
multi_json
gitlab-grack (2.0.0.pre)
rack (~> 1.5.1)
gitlab-grit (2.6.12)
gitlab-grit (2.7.2)
charlock_holmes (~> 0.6)
diff-lcs (~> 1.1)
mime-types (~> 1.15)
......@@ -194,11 +195,13 @@ GEM
omniauth (~> 1.0)
pyu-ruby-sasl (~> 0.0.3.1)
rubyntlm (~> 0.3)
gollum-lib (3.0.0)
github-markup (~> 1.1.0)
gitlab-grit (~> 2.6.5)
nokogiri (~> 1.6.1)
rouge (~> 1.3.3)
gollum-grit_adapter (0.1.0)
gitlab-grit (~> 2.7.1)
gollum-lib (4.0.0)
github-markup (~> 1.3.1)
gollum-grit_adapter (~> 0.1.0)
nokogiri (~> 1.6.4)
rouge (~> 1.7.4)
sanitize (~> 2.1.0)
stringex (~> 2.5.1)
gon (5.0.1)
......@@ -297,7 +300,7 @@ GEM
treetop (~> 1.4.8)
method_source (0.8.2)
mime-types (1.25.1)
mini_portile (0.6.0)
mini_portile (0.6.1)
minitest (5.3.5)
mousetrap-rails (1.4.6)
multi_json (1.10.1)
......@@ -309,8 +312,8 @@ GEM
net-ssh (>= 2.6.5)
net-ssh (2.8.0)
newrelic_rpm (3.9.4.245)
nokogiri (1.6.2.1)
mini_portile (= 0.6.0)
nokogiri (1.6.5)
mini_portile (~> 0.6.0)
nprogress-rails (0.1.2.3)
oauth (0.4.7)
oauth2 (0.8.1)
......@@ -446,7 +449,7 @@ GEM
rest-client (1.6.7)
mime-types (>= 1.16)
rinku (1.7.3)
rouge (1.3.3)
rouge (1.7.4)
rspec (2.14.1)
rspec-core (~> 2.14.0)
rspec-expectations (~> 2.14.0)
......@@ -466,6 +469,7 @@ GEM
rubyntlm (0.4.0)
rubypants (0.2.0)
rugged (0.21.2)
rugments (1.0.0.beta3)
safe_yaml (0.9.7)
sanitize (2.1.0)
nokogiri (>= 1.4.4)
......@@ -541,7 +545,7 @@ GEM
sprockets (~> 2.8)
stamp (0.5.0)
state_machine (1.2.0)
stringex (2.5.1)
stringex (2.5.2)
temple (0.6.7)
term-ansicolor (1.2.2)
tins (~> 0.8)
......@@ -656,7 +660,7 @@ DEPENDENCIES
gitlab_git (= 7.0.0.rc14)
gitlab_meta (= 7.0)
gitlab_omniauth-ldap (= 1.2.0)
gollum-lib (~> 3.0.0)
gollum-lib (~> 4.0.0)
gon (~> 5.0.0)
grape (~> 0.6.1)
grape-entity (~> 0.4.2)
......@@ -709,6 +713,7 @@ DEPENDENCIES
redis-rails
request_store
rspec-rails
rugments
sanitize (~> 2.0)
sass-rails (~> 4.0.2)
sdoc
......
......@@ -73,7 +73,7 @@ On [about.gitlab.com](https://about.gitlab.com/) you can find more information a
## Requirements
- Ubuntu/Debian/CentOS/RHEL**
- ruby 2.0+
- Ruby (MRI) 2.0 or 2.1
- git 1.7.10+
- redis 2.0+
- MySQL or PostgreSQL
......
7.7.0.pre-ee
7.8.0.pre-ee
......@@ -18,14 +18,12 @@
#= require jquery.turbolinks
#= require turbolinks
#= require bootstrap
#= require password_strength
#= require select2
#= require raphael
#= require g.raphael-min
#= require g.bar-min
#= require chart-lib.min
#= require branch-graph
#= require highlight.pack
#= require ace/ace
#= require ace/ext-searchbox
#= require d3
......@@ -109,9 +107,19 @@ window.unbindEvents = ->
$(document).unbind('scroll')
$(document).off('scroll')
window.shiftWindow = ->
scrollBy 0, -50
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
$(".one_click_select").on 'click', -> $(@).select()
......
......@@ -4,7 +4,6 @@ $ ->
class Dispatcher
constructor: () ->
@initSearch()
@initHighlight()
@initPageScripts()
initPageScripts: ->
......@@ -33,17 +32,20 @@ class Dispatcher
GitLab.GfmAutoComplete.setup()
shortcut_handler = new ShortcutsNavigation()
new ZenMode()
new DropzoneInput($('.issue-form'))
when 'projects:merge_requests:new', 'projects:merge_requests:edit'
GitLab.GfmAutoComplete.setup()
new Diff()
shortcut_handler = new ShortcutsNavigation()
new ZenMode()
new DropzoneInput($('.merge-request-form'))
when 'projects:merge_requests:show'
new Diff()
shortcut_handler = new ShortcutsIssueable()
new ZenMode()
when "projects:merge_requests:diffs"
new Diff()
new ZenMode()
when 'projects:merge_requests:index'
shortcut_handler = new ShortcutsNavigation()
when 'dashboard:show'
......@@ -112,6 +114,7 @@ class Dispatcher
new Wikis()
shortcut_handler = new ShortcutsNavigation()
new ZenMode()
new DropzoneInput($('.wiki-form'))
when 'snippets', 'labels', 'graphs'
shortcut_handler = new ShortcutsNavigation()
when 'team_members', 'deploy_keys', 'hooks', 'services', 'protected_branches'
......@@ -130,10 +133,3 @@ class Dispatcher
project_ref = opts.data('autocomplete-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
if @isNewNote(note)
@note_ids.push(note.id)
$('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
......@@ -219,6 +215,7 @@ class @Notes
setupNoteForm: (form) ->
disableButtonIfEmptyField form.find(".js-note-text"), form.find(".js-comment-button")
form.removeClass "js-new-note-form"
form.find('.div-dropzone').remove()
# setup preview buttons
form.find(".js-md-write-button, .js-md-preview-button").tooltip placement: "left"
......@@ -233,6 +230,7 @@ class @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"
GitLab.GfmAutoComplete.setup()
new DropzoneInput(form)
form.show()
......@@ -259,11 +257,10 @@ class @Notes
Updates the current note field.
###
updateNote: (xhr, note, status) =>
note_li = $("#note_" + note.id)
note_li = $(".note-row-" + note.id)
note_li.replaceWith(note.html)
code = "#note_" + note.id + " .highlight pre code"
$(code).each (i, e) ->
hljs.highlightBlock(e)
note_li.find('.note-edit-form').hide()
note_li.find('.note-text').show()
###
Called in response to clicking the edit note link
......@@ -276,11 +273,19 @@ class @Notes
e.preventDefault()
note = $(this).closest(".note")
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
note.find(".js-note-attachment-delete").show()
# Setup markdown form
GitLab.GfmAutoComplete.setup()
form = note.find(".note-edit-form")
new DropzoneInput(form)
form.show()
textarea = form.find("textarea")
textarea.focus()
......@@ -295,8 +300,8 @@ class @Notes
e.preventDefault()
note = $(this).closest(".note")
note.find(".note-text").show()
note.find(".js-note-attachment-delete").hide()
note.find(".note-edit-form").hide()
note.find(".note-header").show()
note.find(".current-note-edit-form").remove()
###
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
if not @active_checkbox
@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
if checkbox.checked
# Disable other keyboard shortcuts in ZEN mode
......@@ -32,8 +40,6 @@ class @ZenMode
@active_zen_area = @active_checkbox.parent().find('textarea')
@active_zen_area.focus()
window.location.hash = ZenMode.fullscreen_prefix + @active_checkbox.prop('id')
# Disable dropzone in ZEN mode
Dropzone.forElement('.div-dropzone').disable()
exitZenMode: =>
if @active_zen_area isnt null
......
......@@ -6,7 +6,6 @@
*= require jquery.ui.autocomplete
*= require jquery.atwho
*= require select2
*= require highlightjs.min
*= require_self
*= require dropzone/basic
*/
......
......@@ -54,6 +54,11 @@ pre {
text-shadow: none;
}
.dropdown-menu-align-right {
left: auto;
right: 0px;
}
.dropdown-menu > li > a:hover,
.dropdown-menu > li > a:focus {
background: $bg_primary;
......@@ -273,10 +278,6 @@ img.emoji {
height: 220px;
}
.navless-container {
margin-top: 68px;
}
.description-block {
@extend .light-well;
@extend .light;
......
......@@ -97,136 +97,3 @@ label {
.wiki-content {
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 @@
.issue-form, .merge-request-form, .wiki-form {
.description {
height: 20em;
border-top-left-radius: 0;
}
}
......@@ -17,4 +18,4 @@
.description {
height: 14em;
}
}
\ No newline at end of file
}
.highlighted-data {
.file-content.code {
border: none;
box-shadow: none;
margin: 0px;
......@@ -13,8 +13,13 @@
font-size: 12px !important;
line-height: 16px !important;
margin: 0;
overflow: auto;
overflow-y: hidden;
white-space: pre;
word-wrap: normal;
code {
font-family: $monospace_font;
white-space: pre;
word-wrap: normal;
padding: 0;
......@@ -25,10 +30,6 @@
}
}
.hljs {
padding: 0;
}
.line-numbers {
padding: 10px;
text-align: right;
......@@ -51,18 +52,18 @@
}
}
}
}
.highlight {
overflow: auto;
overflow-y: hidden;
pre {
white-space: pre;
word-wrap: normal;
.note-text .code {
border: none;
box-shadow: none;
background: $box_bg;
padding: 1em;
code {
font-family: $monospace_font;
}
}
code {
font-family: $monospace_font;
white-space: pre;
word-wrap: normal;
padding: 0;
}
}
......@@ -69,12 +69,11 @@
}
.well-title {
font-size: 14px;
font-size: $list-font-size;
line-height: 18px;
}
.row_title {
font-weight: 500;
color: #444;
&:hover {
color: #444;
......
/** Common mobile (screen XS) styles **/
/** Common mobile (screen XS, SM) styles **/
@media (max-width: $screen-xs-max) {
.container .content {
margin-top: 20px;
......@@ -13,5 +13,41 @@
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 {
background-color: #232323;
.line.hll {
background: #558;
}
.highlight{
border-left: 1px solid #444;
}
.no-highlight {
color: #DDD;
}
/* https://github.com/MozMorris/tomorrow-pygments */
.code.dark {
pre.code,
.line-numbers,
.line-numbers a {
color: #666;
}
pre {
background-color: #232323;
}
.hljs {
display: block;
background: #232323;
color: #E6E1DC;
}
.hljs-comment,
.hljs-template_comment,
.hljs-javadoc,
.hljs-shebang {
color: #BC9458;
font-style: italic;
}
.hljs-keyword,
.ruby .hljs-function .hljs-keyword,
.hljs-request,
.hljs-status,
.nginx .hljs-title,
.method,
.hljs-list .hljs-title {
color: #C26230;
}
.hljs-string,
.hljs-number,
.hljs-regexp,
.hljs-tag .hljs-value,
.hljs-cdata,
.hljs-filter .hljs-argument,
.hljs-attr_selector,
.apache .hljs-cbracket,
.hljs-date,
.tex .hljs-command,
.markdown .hljs-link_label {
color: #A5C261;
}
.hljs-subst {
color: #519F50;
}
.hljs-tag,
.hljs-tag .hljs-keyword,
.hljs-tag .hljs-title,
.hljs-doctype,
.hljs-sub .hljs-identifier,
.hljs-pi,
.input_number {
color: #E8BF6A;
}
.hljs-identifier {
color: #D0D0FF;
}
.hljs-class .hljs-title,
.haskell .hljs-type,
.smalltalk .hljs-class,
.hljs-javadoctag,
.hljs-yardoctag,
.hljs-phpdoc {
text-decoration: none;
}
.hljs-constant {
color: #DA4939;
}
.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;
}
background-color: #1d1f21 !important;
color: #c5c8c6 !important;
}
pre.code {
border-left: 1px solid #666;
}
pre.hll {
background-color: #fff !important;
}
.hll { background-color: #373b41 }
.c { color: #969896 } /* Comment */
.err { color: #cc6666 } /* Error */
.k { color: #b294bb } /* Keyword */
.l { color: #de935f } /* Literal */
.n { color: #c5c8c6 } /* Name */
.o { color: #8abeb7 } /* Operator */
.p { color: #c5c8c6 } /* Punctuation */
.cm { color: #969896 } /* Comment.Multiline */
.cp { color: #969896 } /* Comment.Preproc */
.c1 { color: #969896 } /* Comment.Single */
.cs { color: #969896 } /* Comment.Special */
.gd { color: #cc6666 } /* Generic.Deleted */
.ge { font-style: italic } /* Generic.Emph */
.gh { color: #c5c8c6; font-weight: bold } /* Generic.Heading */
.gi { color: #b5bd68 } /* Generic.Inserted */
.gp { color: #969896; font-weight: bold } /* Generic.Prompt */
.gs { font-weight: bold } /* Generic.Strong */
.gu { color: #8abeb7; font-weight: bold } /* Generic.Subheading */
.kc { color: #b294bb } /* Keyword.Constant */
.kd { color: #b294bb } /* Keyword.Declaration */
.kn { color: #8abeb7 } /* Keyword.Namespace */
.kp { color: #b294bb } /* Keyword.Pseudo */
.kr { color: #b294bb } /* Keyword.Reserved */
.kt { color: #f0c674 } /* Keyword.Type */
.ld { color: #b5bd68 } /* Literal.Date */
.m { color: #de935f } /* Literal.Number */
.s { color: #b5bd68 } /* Literal.String */
.na { color: #81a2be } /* Name.Attribute */
.nb { color: #c5c8c6 } /* Name.Builtin */
.nc { color: #f0c674 } /* Name.Class */
.no { color: #cc6666 } /* Name.Constant */
.nd { color: #8abeb7 } /* Name.Decorator */
.ni { color: #c5c8c6 } /* Name.Entity */
.ne { color: #cc6666 } /* Name.Exception */
.nf { color: #81a2be } /* Name.Function */
.nl { color: #c5c8c6 } /* Name.Label */
.nn { color: #f0c674 } /* Name.Namespace */
.nx { color: #81a2be } /* Name.Other */
.py { color: #c5c8c6 } /* Name.Property */
.nt { color: #8abeb7 } /* Name.Tag */
.nv { color: #cc6666 } /* Name.Variable */
.ow { color: #8abeb7 } /* Operator.Word */
.w { color: #c5c8c6 } /* Text.Whitespace */
.mf { color: #de935f } /* Literal.Number.Float */
.mh { color: #de935f } /* Literal.Number.Hex */
.mi { color: #de935f } /* Literal.Number.Integer */
.mo { color: #de935f } /* Literal.Number.Oct */
.sb { color: #b5bd68 } /* Literal.String.Backtick */
.sc { color: #c5c8c6 } /* Literal.String.Char */
.sd { color: #969896 } /* Literal.String.Doc */
.s2 { color: #b5bd68 } /* Literal.String.Double */
.se { color: #de935f } /* Literal.String.Escape */
.sh { color: #b5bd68 } /* Literal.String.Heredoc */
.si { color: #de935f } /* Literal.String.Interpol */
.sx { color: #b5bd68 } /* Literal.String.Other */
.sr { color: #b5bd68 } /* Literal.String.Regex */
.s1 { color: #b5bd68 } /* Literal.String.Single */
.ss { color: #b5bd68 } /* Literal.String.Symbol */
.bp { color: #c5c8c6 } /* Name.Builtin.Pseudo */
.vc { color: #cc6666 } /* Name.Variable.Class */
.vg { color: #cc6666 } /* Name.Variable.Global */
.vi { color: #cc6666 } /* Name.Variable.Instance */
.il { color: #de935f } /* Literal.Number.Integer.Long */
}
.monokai {
background-color: #272822;
.highlight{
border-left: 1px solid #444;
}
.line.hll {
background: #558;
}
.no-highlight {
color: #DDD;
}
/* https://github.com/richleland/pygments-css/blob/master/monokai.css */
.code.monokai {
pre.highlight,
.line-numbers,
.line-numbers a {
color: #666;
}
pre {
background-color: #272822;
color: #f8f8f2;
}
.hljs {
display: block;
background: #272822;
}
.hljs-tag,
.hljs-tag .hljs-title,
.hljs-strong,
.hljs-change,
.hljs-winutils,
.hljs-flow,
.lisp .hljs-title,
.clojure .hljs-built_in,
.hljs-keyword,
.nginx .hljs-title,
.tex .hljs-special {
color: #F92672;
}
.hljs {
color: #F8F8F2;
}
.asciidoc .hljs-code,
.markdown .hljs-code,
.hljs-literal,
.hljs-function .hljs-keyword {
color: #66D9EF;
}
.hljs-code,
.hljs-class .hljs-title,
.hljs-header {
color: white;
}
.hljs-link_label,
.hljs-attribute,
.hljs-symbol,
.hljs-symbol .hljs-string,
.hljs-value,
.hljs-constant,
.hljs-number,
.hljs-regexp {
color: #AE81FF;
}
.hljs-string {
color: #E6DB74;
}
.hljs-params {
color: #fd971f;
}
.hljs-link_url,
.hljs-tag .hljs-value,
.hljs-bullet,
.hljs-subst,
.hljs-title,
.hljs-emphasis,
.hljs-type,
.hljs-preprocessor,
.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;
}
background:#272822 !important;
color:#f8f8f2 !important;
}
pre.code {
border-left: 1px solid #555;
}
.hll { background-color: #49483e }
.c { color: #75715e } /* Comment */
.err { color: #960050; background-color: #1e0010 } /* Error */
.k { color: #66d9ef } /* Keyword */
.l { color: #ae81ff } /* Literal */
.n { color: #f8f8f2 } /* Name */
.o { color: #f92672 } /* Operator */
.p { color: #f8f8f2 } /* Punctuation */
.cm { color: #75715e } /* Comment.Multiline */
.cp { color: #75715e } /* Comment.Preproc */
.c1 { color: #75715e } /* Comment.Single */
.cs { color: #75715e } /* Comment.Special */
.ge { font-style: italic } /* Generic.Emph */
.gs { font-weight: bold } /* Generic.Strong */
.kc { color: #66d9ef } /* Keyword.Constant */
.kd { color: #66d9ef } /* Keyword.Declaration */
.kn { color: #f92672 } /* Keyword.Namespace */
.kp { color: #66d9ef } /* Keyword.Pseudo */
.kr { color: #66d9ef } /* Keyword.Reserved */
.kt { color: #66d9ef } /* Keyword.Type */
.ld { color: #e6db74 } /* Literal.Date */
.m { color: #ae81ff } /* Literal.Number */
.s { color: #e6db74 } /* Literal.String */
.na { color: #a6e22e } /* Name.Attribute */
.nb { color: #f8f8f2 } /* Name.Builtin */
.nc { color: #a6e22e } /* Name.Class */
.no { color: #66d9ef } /* Name.Constant */
.nd { color: #a6e22e } /* Name.Decorator */
.ni { color: #f8f8f2 } /* Name.Entity */
.ne { color: #a6e22e } /* Name.Exception */
.nf { color: #a6e22e } /* Name.Function */
.nl { color: #f8f8f2 } /* Name.Label */
.nn { color: #f8f8f2 } /* Name.Namespace */
.nx { color: #a6e22e } /* Name.Other */
.py { color: #f8f8f2 } /* Name.Property */
.nt { color: #f92672 } /* Name.Tag */
.nv { color: #f8f8f2 } /* Name.Variable */
.ow { color: #f92672 } /* Operator.Word */
.w { color: #f8f8f2 } /* Text.Whitespace */
.mf { color: #ae81ff } /* Literal.Number.Float */
.mh { color: #ae81ff } /* Literal.Number.Hex */
.mi { color: #ae81ff } /* Literal.Number.Integer */
.mo { color: #ae81ff } /* Literal.Number.Oct */
.sb { color: #e6db74 } /* Literal.String.Backtick */
.sc { color: #e6db74 } /* Literal.String.Char */
.sd { color: #e6db74 } /* Literal.String.Doc */
.s2 { color: #e6db74 } /* Literal.String.Double */
.se { color: #ae81ff } /* Literal.String.Escape */
.sh { color: #e6db74 } /* Literal.String.Heredoc */
.si { color: #e6db74 } /* Literal.String.Interpol */
.sx { color: #e6db74 } /* Literal.String.Other */
.sr { color: #e6db74 } /* Literal.String.Regex */
.s1 { color: #e6db74 } /* Literal.String.Single */
.ss { color: #e6db74 } /* Literal.String.Symbol */
.bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */
.vc { color: #f8f8f2 } /* Name.Variable.Class */
.vg { color: #f8f8f2 } /* Name.Variable.Global */
.vi { color: #f8f8f2 } /* Name.Variable.Instance */
.il { color: #ae81ff } /* Literal.Number.Integer.Long */
.gh { } /* Generic Heading & Diff Header */
.gu { color: #75715e; } /* Generic.Subheading & Diff Unified/Comment? */
.gd { color: #f92672; } /* Generic.Deleted & Diff Deleted */
.gi { color: #a6e22e; } /* Generic.Inserted & Diff Inserted */
}
.solarized-dark {
background-color: #002B36;
.highlight{
border-left: 1px solid #113b46;
}
.line.hll {
background: #000;
}
.no-highlight {
color: #DDD;
}
pre {
background-color: #002B36;
color: #eee;
}
/* https://gist.github.com/qguv/7936275 */
.code.solarized-dark {
pre.code,
.line-numbers,
.line-numbers a {
color: #666;
background-color: #002b36 !important;
color: #93a1a1 !important;
}
.hljs {
display: block;
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;
pre.code {
border-left: 1px solid #113b46;
}
/* Solarized Cyan */
.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 Dark
/* Solarized Blue */
.hljs-title,
.hljs-localvars,
.hljs-chunk,
.hljs-decorator,
.hljs-built_in,
.hljs-identifier,
.vhdl .hljs-literal,
.hljs-id,
.css .hljs-function {
color: #268bd2;
}
For use with Jekyll and Pygments
/* Solarized Yellow */
.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;
}
http://ethanschoonover.com/solarized
/* Solarized Orange */
.hljs-preprocessor,
.hljs-preprocessor .hljs-keyword,
.hljs-pragma,
.hljs-shebang,
.hljs-symbol,
.hljs-symbol .hljs-string,
.diff .hljs-change,
.hljs-special,
.hljs-attr_selector,
.hljs-subst,
.hljs-cdata,
.clojure .hljs-title,
.css .hljs-pseudo,
.hljs-header {
color: #cb4b16;
}
SOLARIZED HEX ROLE
--------- -------- ------------------------------------------
base03 #002b36 background
base01 #586e75 comments / secondary content
base1 #93a1a1 body text / default code / primary content
orange #cb4b16 constants
red #dc322f regex, special keywords
blue #268bd2 reserved keywords
cyan #2aa198 strings, numbers
green #859900 operators, other keywords
*/
/* Solarized Red */
.hljs-deletion,
.hljs-important {
color: #dc322f;
}
/* Solarized Violet */
.hljs-link_label {
color: #6c71c4;
}
.tex .hljs-formula {
background: #073642;
}
.c { color: #586e75 } /* Comment */
.err { color: #93a1a1 } /* Error */
.g { color: #93a1a1 } /* Generic */
.k { color: #859900 } /* Keyword */
.l { color: #93a1a1 } /* Literal */
.n { color: #93a1a1 } /* Name */
.o { color: #859900 } /* Operator */
.x { color: #cb4b16 } /* Other */
.p { color: #93a1a1 } /* Punctuation */
.cm { color: #586e75 } /* Comment.Multiline */
.cp { color: #859900 } /* Comment.Preproc */
.c1 { color: #586e75 } /* Comment.Single */
.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 {
.line.hll {
background: #FFA;
}
pre {
background-color: #fff;
color: #333;
}
.hljs {
background: #FFF;
}
/* https://github.com/aahan/pygments-github-style */
.code.white {
pre.highlight,
.line-numbers,
.line-numbers a {
color: #999;
}
.hljs {
display: block;
background: #fff; color: black;
}
.hljs-comment,
.hljs-template_comment,
.hljs-javadoc,
.hljs-comment * {
color: #006a00;
}
.hljs-keyword,
.hljs-literal,
.nginx .hljs-title {
color: #aa0d91;
}
.method,
.hljs-list .hljs-title,
.hljs-tag .hljs-title,
.setting .hljs-value,
.hljs-winutils,
.tex .hljs-command,
.http .hljs-title,
.hljs-request,
.hljs-status {
color: #008;
}
.hljs-envvar,
.tex .hljs-special {
color: #660;
}
.hljs-string {
color: #c41a16;
}
.hljs-tag .hljs-value,
.hljs-cdata,
.hljs-filter .hljs-argument,
.hljs-attr_selector,
.apache .hljs-cbracket,
.hljs-date,
.hljs-regexp {
color: #080;
}
.hljs-sub .hljs-identifier,
.hljs-pi,
.hljs-tag,
.hljs-tag .hljs-keyword,
.hljs-decorator,
.ini .hljs-title,
.hljs-shebang,
.hljs-prompt,
.hljs-hexcolor,
.hljs-rules .hljs-value,
.hljs-symbol,
.hljs-symbol .hljs-string,
.hljs-number,
.css .hljs-function,
.clojure .hljs-title,
.clojure .hljs-built_in,
.hljs-function .hljs-title,
.coffeescript .hljs-attribute {
color: #1c00cf;
}
.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;
}
}
background-color: #fff !important;
color: #333 !important;
}
pre.code {
border-left: 1px solid #bbb;
}
.hll { background-color: #f8f8f8 }
.c { color: #999988; font-style: italic; }
.err { color: #a61717; background-color: #e3d2d2; }
.k { font-weight: bold; }
.o { font-weight: bold; }
.cm { color: #999988; font-style: italic; }
.cp { color: #999999; font-weight: bold; }
.c1 { color: #999988; font-style: italic; }
.cs { color: #999999; font-weight: bold; font-style: italic; }
.gd { color: #000000; background-color: #ffdddd; }
.gd .x { color: #000000; background-color: #ffaaaa; }
.ge { font-style: italic; }
.gr { color: #aa0000; }
.gh { color: #999999; }
.gi { color: #000000; background-color: #ddffdd; }
.gi .x { color: #000000; background-color: #aaffaa; }
.go { color: #888888; }
.gp { color: #555555; }
.gs { font-weight: bold; }
.gu { color: #800080; font-weight: bold; }
.gt { color: #aa0000; }
.kc { font-weight: bold; }
.kd { font-weight: bold; }
.kn { font-weight: bold; }
.kp { font-weight: bold; }
.kr { font-weight: bold; }
.kt { color: #445588; font-weight: bold; }
.m { color: #009999; }
.s { color: #dd1144; }
.n { color: #333333; }
.na { color: teal; }
.nb { color: #0086b3; }
.nc { color: #445588; font-weight: bold; }
.no { color: teal; }
.ni { color: purple; }
.ne { color: #990000; font-weight: bold; }
.nf { color: #990000; font-weight: bold; }
.nn { color: #555555; }
.nt { color: navy; }
.nv { color: teal; }
.ow { font-weight: bold; }
.w { color: #bbbbbb; }
.mf { color: #009999; }
.mh { color: #009999; }
.mi { color: #009999; }
.mo { color: #009999; }
.sb { color: #dd1144; }
.sc { color: #dd1144; }
.sd { color: #dd1144; }
.s2 { color: #dd1144; }
.se { color: #dd1144; }
.sh { color: #dd1144; }
.si { color: #dd1144; }
.sx { color: #dd1144; }
.sr { color: #009926; }
.s1 { color: #dd1144; }
.ss { color: #990073; }
.bp { color: #999999; }
.vc { color: teal; }
.vg { color: teal; }
.vi { color: teal; }
.il { color: #009999; }
.gc { color: #999; background-color: #EAF2F5; }
}
......@@ -2,6 +2,10 @@ html {
overflow-y: scroll;
&.touch .tooltip { display: none !important; }
body {
padding-top: 47px;
}
}
.container {
......@@ -13,3 +17,6 @@ html {
margin: 0 0;
}
.navless-container {
margin-top: 30px;
}
......@@ -69,7 +69,12 @@
margin-top: 0;
}
code { padding: 0 4px; }
code {
font-family: $monospace_font;
white-space: pre;
word-wrap: normal;
padding: 0;
}
h1 {
margin-top: 45px;
......
......@@ -47,3 +47,13 @@ $deleted: #f77;
* NProgress customize
*/
$nprogress-color: #c0392b;
/**
* Font sizes
*/
$list-font-size: 15px;
/**
* Sidebar navigation width
*/
$sidebar_width: 230px;
......@@ -139,7 +139,7 @@
*/
li.commit {
.commit-row-title {
font-size: 14px;
font-size: $list-font-size;
margin-bottom: 2px;
.notes_count {
......@@ -158,7 +158,6 @@ li.commit {
.commit-row-message {
color: #333;
font-weight: 500;
&:hover {
color: #444;
text-decoration: underline;
......
......@@ -55,11 +55,12 @@
}
.event-body {
margin-left: 35px;
margin-right: 100px;
margin-right: 80px;
color: #777;
.event-note {
margin-top: 5px;
word-wrap: break-word;
.md {
font-size: 13px;
......@@ -71,6 +72,7 @@
border-radius: 0;
color: #777;
margin: 0 20px;
overflow: hidden;
}
.note-image-attach {
......
......@@ -8,8 +8,6 @@ header {
margin-bottom: 0;
min-height: 40px;
border: none;
position: fixed;
top: 0;
width: 100%;
.navbar-inner {
......
......@@ -5,7 +5,7 @@
.issue-title {
margin-bottom: 5px;
font-size: 14px;
font-size: $list-font-size;
}
.issue-info {
......@@ -166,3 +166,7 @@ form.edit-issue {
.issue-title {
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 @@
.merge-request-title {
margin-bottom: 5px;
font-size: 14px;
font-size: $list-font-size;
}
.merge-request-info {
......
.page-with-sidebar {
background: #F5F5F5;
.sidebar-wrapper {
position: fixed;
top: 0;
left: 0;
height: 100%;
border-right: 1px solid #EAEAEA;
}
}
.sidebar-wrapper {
......@@ -12,7 +22,6 @@
width: 100%;
padding: 15px;
background: #FFF;
margin-top: 48px;
}
.nav-sidebar {
......@@ -93,22 +102,17 @@
@mixin expanded-sidebar {
.page-with-sidebar {
padding-left: 250px;
padding-left: $sidebar_width;
}
.sidebar-wrapper {
width: 250px;
position: fixed;
left: 250px;
height: 100%;
margin-left: -250px;
border-right: 1px solid #EAEAEA;
width: $sidebar_width;
.nav-sidebar {
margin-top: 20px;
position: fixed;
top: 45px;
width: 250px;
width: $sidebar_width;
}
}
......@@ -124,11 +128,6 @@
.sidebar-wrapper {
width: 52px;
position: fixed;
top: 0;
left: 0;
height: 100%;
border-right: 1px solid #EAEAEA;
overflow-x: hidden;
.nav-sidebar {
......@@ -151,11 +150,10 @@
}
}
@media (max-width: $screen-sm-max) {
@media (max-width: $screen-md-max) {
@include folded-sidebar;
}
@media(min-width: $screen-sm-max) {
@media(min-width: $screen-md-max) {
@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 {
font-size: 14px;
}
.note-body {
@include md-typography;
overflow: auto;
.note-text {
overflow: auto;
word-wrap: break-word;
@include md-typography;
}
}
.note-header {
padding-bottom: 3px;
......@@ -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 @@
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 {
}
}
@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 {
th, td {
border: 0;
......
......@@ -98,6 +98,11 @@
background: #f1f1f1;
border-left: 1px solid #DDD;
}
td.lines {
code {
font-family: $monospace_font;
}
}
}
}
......
......@@ -26,6 +26,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
:signin_enabled,
:gravatar_enabled,
:sign_in_text,
:home_page_url
)
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
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)
application_trace = ActionDispatch::ExceptionWrapper.new(env, exception).application_trace
application_trace.map!{ |t| " #{t}\n" }
......
......@@ -22,6 +22,11 @@ class GithubImportsController < ApplicationController
@repos.reject!{|repo| already_added_projects_names.include? repo.full_name}
end
def jobs
jobs = current_user.created_projects.where(import_type: "github").to_json(:only => [:id, :import_status])
render json: jobs
end
def create
@repo_id = params[:repo_id].to_i
repo = octo_client.repo(@repo_id)
......@@ -42,7 +47,7 @@ class GithubImportsController < ApplicationController
namespace.add_owner(current_user)
end
Gitlab::Github::ProjectCreator.new(repo, namespace, current_user).execute
@project = Gitlab::Github::ProjectCreator.new(repo, namespace, current_user).execute
end
private
......
......@@ -9,10 +9,8 @@ class Oauth::ApplicationsController < Doorkeeper::ApplicationsController
def create
@application = Doorkeeper::Application.new(application_params)
if Doorkeeper.configuration.confirm_application_owner?
@application.owner = current_user
end
@application.owner = current_user
if @application.save
flash[:notice] = I18n.t(:notice, scope: [:doorkeeper, :flash, :applications, :create])
redirect_to oauth_application_url(@application)
......
......@@ -12,6 +12,7 @@ class Projects::CommitController < Projects::ApplicationController
@line_notes = @project.notes.for_commit_id(commit.id).inline
@branches = @project.repository.branch_names_contains(commit.id)
@tags = @project.repository.tag_names_contains(commit.id)
@diffs = @commit.diffs
@note = @project.build_commit_note(commit)
@notes_count = @project.notes.for_commit_id(commit.id).count
......
......@@ -233,13 +233,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
def allowed_to_push_code?(project, branch)
action = if project.protected_branch?(branch)
:push_code_to_protected_branches
else
:push_code
end
can?(current_user, action, project)
::Gitlab::GitAccess.can_push_to_branch?(current_user, project, branch)
end
def merge_request_params
......
......@@ -15,11 +15,11 @@ class RegistrationsController < Devise::RegistrationsController
super
end
def after_sign_up_path_for(resource)
def after_sign_up_path_for(_resource)
new_user_session_path
end
def after_inactive_sign_up_path_for(resource)
def after_inactive_sign_up_path_for(_resource)
new_user_session_path
end
......
......@@ -5,8 +5,9 @@ module ApplicationHelper
COLOR_SCHEMES = {
1 => 'white',
2 => 'dark',
3 => 'solarized-dark',
4 => 'monokai',
3 => 'solarized-light',
4 => 'solarized-dark',
5 => 'monokai',
}
COLOR_SCHEMES.default = 'white'
......@@ -189,20 +190,6 @@ module ApplicationHelper
BroadcastMessage.current
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')
capture_haml do
haml_tag :time, date.to_s,
......@@ -305,9 +292,4 @@ module ApplicationHelper
profile_key_path(key)
end
end
def redirect_from_root?
request.env['rack.session']['user_return_to'] ==
'/'
end
end
module BlobHelper
def highlightjs_class(blob_name)
if no_highlight_files.include?(blob_name.downcase)
'no-highlight'
else
blob_name.downcase
def highlight(blob_name, blob_content, nowrap = false)
formatter = Rugments::Formatters::HTML.new(
nowrap: nowrap,
cssclass: 'code highlight',
lineanchors: true,
lineanchorsid: 'LC'
)
begin
lexer = Rugments::Lexer.guess(filename: blob_name, source: blob_content)
rescue Rugments::Lexer::AmbiguousGuess
lexer = Rugments::Lexers::PlainText
end
formatter.format(lexer.lex(blob_content)).html_safe
end
def no_highlight_files
......
......@@ -11,13 +11,8 @@ module BranchesHelper
def can_push_branch?(project, branch_name)
return false unless project.repository.branch_names.include?(branch_name)
action = if project.protected_branch?(branch_name)
:push_code_to_protected_branches
else
:push_code
end
current_user.can?(action, project)
::Gitlab::GitAccess.can_push_to_branch?(current_user, project, branch_name)
end
def can_rebase?(project, branch_name)
......
......@@ -65,6 +65,12 @@ module CommitsHelper
branches.sort.map { |branch| link_to(branch, project_tree_path(project, branch)) }.join(", ").html_safe
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)
if current_controller?(:projects, :commits)
if @repo.blob_at(commit.id, @path)
......
......@@ -135,4 +135,19 @@ module DiffHelper
'Side-by-side'
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
......@@ -29,4 +29,14 @@ module EmailsHelper
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
......@@ -67,8 +67,10 @@ module IssuesHelper
ts = "#{time_ago_with_tooltip(issue.created_at, 'bottom', 'note_created_ago')}"
if issue.updated_at != issue.created_at
ts << capture_haml do
haml_tag :small do
haml_concat " (Edited #{time_ago_with_tooltip(issue.updated_at, 'bottom', 'issue_edited_ago')})"
haml_tag :span do
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
......
......@@ -20,8 +20,10 @@ module NotesHelper
ts = "#{time_ago_with_tooltip(note.created_at, 'bottom', 'note_created_ago')}"
if note.updated_at != note.created_at
ts << capture_haml do
haml_tag :small do
haml_concat " (Edited #{time_ago_with_tooltip(note.updated_at, 'bottom', 'note_edited_ago')})"
haml_tag :span do
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
......
......@@ -234,8 +234,10 @@ module ProjectsHelper
def hidden_pass_url(original_url)
result = URI(original_url)
result.password = '*****' if result.password.present?
result.password = '*****' unless result.password.nil?
result
rescue
original_url
end
def project_wiki_path_with_version(proj, page, version, is_newest)
......
......@@ -2,8 +2,8 @@ module SubmoduleHelper
include Gitlab::ShellAdapter
# links to files listing for submodule if submodule is a project on this server
def submodule_links(submodule_item)
url = @repository.submodule_url_for(@ref, submodule_item.path)
def submodule_links(submodule_item, ref = nil)
url = @repository.submodule_url_for(ref, submodule_item.path)
return url, nil unless url =~ /([^\/:]+\/[^\/]+\.git)\Z/
......
......@@ -58,11 +58,7 @@ module TreeHelper
ref ||= @ref
return false unless project.repository.branch_names.include?(ref)
if project.protected_branch? ref
can?(current_user, :push_code_to_protected_branches, project)
else
can?(current_user, :push_code, project)
end
::Gitlab::GitAccess.can_push_to_branch?(current_user, project, ref)
end
def edit_blob_link(project, ref, path, options = {})
......@@ -108,7 +104,7 @@ module TreeHelper
end
end
def up_dir_path(tree)
def up_dir_path
file = File.join(@path, "..")
tree_join(@ref, file)
end
......
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
ApplicationSetting.last
end
......@@ -12,4 +16,8 @@ class ApplicationSetting < ActiveRecord::Base
sign_in_text: Settings.extra['sign_in_text'],
)
end
def home_page_url_column_exist
ActiveRecord::Base.connection.column_exists?(:application_settings, :home_page_url)
end
end
......@@ -75,11 +75,11 @@ class Commit
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)
title[0..79] << "&hellip;".html_safe
else
title.split(/\n/, 2).first
title.split("\n", 2).first
end
end
......@@ -87,11 +87,11 @@ class Commit
#
# cut off, ellipses (`&hellp;`) are prepended to the commit message.
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)
"&hellip;".html_safe << safe_message[80..-1]
else
safe_message.split(/\n/, 2)[1].try(:chomp)
safe_message.split("\n", 2)[1].try(:chomp)
end
end
......
......@@ -91,7 +91,7 @@ class Key < ActiveRecord::Base
end
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
end
end
......
......@@ -190,7 +190,12 @@ class Project < ActiveRecord::Base
end
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
def search_by_title(query)
......
......@@ -60,9 +60,9 @@ class CampfireService < Service
message << "[#{project.name_with_namespace}] "
message << "#{push[:user_name]} "
if before =~ /000000/
if before.include?('000000')
message << "pushed new branch #{ref} \n"
elsif after =~ /000000/
elsif after.include?('000000')
message << "removed branch #{ref} \n"
else
message << "pushed #{push[:total_commits_count]} commits to #{ref}. "
......
......@@ -32,8 +32,8 @@ class HipchatService < Service
def fields
[
{ type: 'text', name: 'token', placeholder: '' },
{ type: 'text', name: 'room', placeholder: '' },
{ type: 'text', name: 'token', placeholder: 'Room token' },
{ type: 'text', name: 'room', placeholder: 'Room name or ID' },
{ type: 'text', name: 'server',
placeholder: 'Leave blank for default. https://hipchat.example.com' }
]
......@@ -58,12 +58,12 @@ class HipchatService < Service
message = ""
message << "#{push[:user_name]} "
if before =~ /000000/
if before.include?('000000')
message << "pushed new branch <a href=\""\
"#{project.web_url}/commits/#{URI.escape(ref)}\">#{ref}</a>"\
" to <a href=\"#{project.web_url}\">"\
"#{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"
else
message << "pushed to branch <a href=\""\
......
......@@ -80,9 +80,9 @@ class PushoverService < Service
before = push_data[:before]
after = push_data[:after]
if before =~ /000000/
if before.include?('000000')
message = "#{push_data[:user_name]} pushed new branch \"#{ref}\"."
elsif after =~ /000000/
elsif after.include?('000000')
message = "#{push_data[:user_name]} deleted branch \"#{ref}\"."
else
message = "#{push_data[:user_name]} push to branch \"#{ref}\"."
......
......@@ -77,11 +77,11 @@ class SlackMessage
end
def new_branch?
before =~ /000000/
before.include?('000000')
end
def removed_branch?
after =~ /000000/
after.include?('000000')
end
def branch_url
......
......@@ -312,4 +312,21 @@ class Repository
[]
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
......@@ -495,7 +495,7 @@ class User < ActiveRecord::Base
end
def temp_oauth_email?
email =~ /\Atemp-email-for-oauth/
email.start_with?('temp-email-for-oauth')
end
def public_profile?
......@@ -504,7 +504,7 @@ class User < ActiveRecord::Base
def avatar_url(size = nil)
if avatar.present?
[gitlab_config.url, avatar.url].join("/")
[gitlab_config.url, avatar.url].join
else
GravatarService.new.execute(email, size)
end
......
......@@ -3,11 +3,7 @@ require_relative "base_service"
module Files
class CreateService < BaseService
def execute
allowed = if project.protected_branch?(ref)
can?(current_user, :push_code_to_protected_branches, project)
else
can?(current_user, :push_code, project)
end
allowed = Gitlab::GitAccess.can_push_to_branch?(current_user, project, ref)
unless allowed
return error("You are not allowed to create file in this branch")
......
......@@ -3,11 +3,7 @@ require_relative "base_service"
module Files
class DeleteService < BaseService
def execute
allowed = if project.protected_branch?(ref)
can?(current_user, :push_code_to_protected_branches, project)
else
can?(current_user, :push_code, project)
end
allowed = ::Gitlab::GitAccess.can_push_to_branch?(current_user, project, ref)
unless allowed
return error("You are not allowed to push into this branch")
......
......@@ -3,11 +3,7 @@ require_relative "base_service"
module Files
class UpdateService < BaseService
def execute
allowed = if project.protected_branch?(ref)
can?(current_user, :push_code_to_protected_branches, project)
else
can?(current_user, :push_code, project)
end
allowed = ::Gitlab::GitAccess.can_push_to_branch?(current_user, project, ref)
unless allowed
return error("You are not allowed to push into this branch")
......
......@@ -115,23 +115,23 @@ class GitPushService
ref_parts = ref.split('/')
# 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
def push_to_new_branch?(ref, oldrev)
ref_parts = ref.split('/')
ref_parts[1] =~ /heads/ && oldrev == Gitlab::Git::BLANK_SHA
ref_parts[1].include?('heads') && oldrev == Gitlab::Git::BLANK_SHA
end
def push_remove_branch?(ref, newrev)
ref_parts = ref.split('/')
ref_parts[1] =~ /heads/ && newrev == Gitlab::Git::BLANK_SHA
ref_parts[1].include?('heads') && newrev == Gitlab::Git::BLANK_SHA
end
def push_to_branch?(ref)
ref =~ /refs\/heads/
ref.include?('refs/heads')
end
def is_default_branch?(ref)
......
......@@ -5,9 +5,12 @@ module MergeRequests
Note.create_status_change_note(merge_request, merge_request.target_project, current_user, merge_request.state, nil)
end
def execute_hooks(merge_request)
def execute_hooks(merge_request, action = 'open')
if merge_request.project
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)
end
end
......
......@@ -9,7 +9,7 @@ module MergeRequests
event_service.close_mr(merge_request, current_user)
notification_service.close_mr(merge_request, current_user)
create_note(merge_request)
execute_hooks(merge_request)
execute_hooks(merge_request, 'close')
end
merge_request
......
......@@ -12,7 +12,7 @@ module MergeRequests
notification_service.merge_mr(merge_request, current_user)
create_merge_event(merge_request, current_user)
create_note(merge_request)
execute_hooks(merge_request)
execute_hooks(merge_request, 'merge')
true
rescue
......
......@@ -5,7 +5,7 @@ module MergeRequests
event_service.reopen_mr(merge_request, current_user)
notification_service.reopen_mr(merge_request, current_user)
create_note(merge_request)
execute_hooks(merge_request)
execute_hooks(merge_request, 'reopen')
merge_request.reload_code
merge_request.mark_as_unchecked
end
......
......@@ -38,7 +38,7 @@ module MergeRequests
end
merge_request.notice_added_references(merge_request.project, current_user)
execute_hooks(merge_request)
execute_hooks(merge_request, 'update')
end
merge_request
......
......@@ -118,7 +118,7 @@ class NotificationService
return true unless note.noteable_type.present?
# 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
opts = { noteable_type: note.noteable_type, project_id: note.project_id }
......
......@@ -25,6 +25,11 @@
= f.label :default_projects_limit, class: 'control-label'
.col-sm-10
= 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
= f.label :sign_in_text, class: 'control-label'
.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
.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
.col-md-4
%h4 Stats
%h4 Statistics
%hr
%p
Forks
......@@ -141,3 +79,59 @@
Rails
%span.pull-right
#{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 @@
.devise-errors
= devise_error_messages!
= f.hidden_field :reset_password_token
.form-group#password-strength
= f.password_field :password, class: "form-control top", id: "user_password_recover", placeholder: "New password", required: true
%div
= f.password_field :password, class: "form-control top", placeholder: "New password", required: true
%div
= f.password_field :password_confirmation, class: "form-control bottom", placeholder: "Confirm new password", required: true
.clearfix.append-bottom-10
......
......@@ -11,8 +11,8 @@
= f.text_field :username, class: "form-control middle", placeholder: "Username", required: true
%div
= f.email_field :email, class: "form-control middle", placeholder: "Email", required: true
.form-group#password-strength
= f.password_field :password, class: "form-control middle", id: "user_password_sign_up", placeholder: "Password", required: true
%div
= f.password_field :password, class: "form-control middle", placeholder: "Password", required: true
%div
= f.password_field :password_confirmation, class: "form-control bottom", placeholder: "Confirm password", required: true
%div
......
......@@ -12,5 +12,7 @@
target_field.find('input').prop("value", origin_namespace)
- else
:plain
$("table.import-jobs tbody").prepend($("tr#repo_#{@repo_id}"))
$("tr#repo_#{@repo_id}").addClass("active").find(".import-actions").html("<i class='fa fa-spinner fa-spin'></i> started")
job = $("tr#repo_#{@repo_id}")
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 @@
Import repositories from GitHub.com
%p.light
Select projects you want to import.
%span.pull-right
Reload to see the progress.
Select projects you want to import.
%hr
%table.table.import-jobs
......@@ -16,11 +14,11 @@
%th Status
%tbody
- @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
%strong= link_to project.name_with_namespace, project
%td
%td.job-status
- if project.import_status == 'finished'
%span.cgreen
%i.fa.fa-check
......@@ -33,7 +31,7 @@
%td= repo.full_name
%td.import-target
= repo.full_name
%td.import-actions
%td.import-actions.job-status
= button_tag "Add", class: "btn btn-add-to-import"
......@@ -46,3 +44,20 @@
new_namespace = tr.find(".import-target input").prop("value")
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'
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
= 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 @@
.broadcast-message{ style: broadcast_styling(broadcast_message) }
%i.fa.fa-bullhorn
= broadcast_message.message
:css
.sidebar-wrapper .nav-sidebar {
margin-top: 58px;
}
......@@ -19,6 +19,7 @@
= csrf_meta_tags
= include_gon
%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/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
.container
%div.app_logo
......
%header.navbar.navbar-static-top.navbar-gitlab
%header.navbar.navbar-fixed-top.navbar-gitlab
.navbar-inner
.container
%div.app_logo
......
......@@ -6,8 +6,7 @@
= render "layouts/public_head_panel", title: ''
.container.navless-container
.content
- unless redirect_from_root?
= render "layouts/flash"
= render "layouts/flash"
.row.prepend-top-20
.col-sm-5.pull-right
= yield
......
......@@ -11,7 +11,7 @@
Projects
= nav_link(controller: :users) do
= link_to admin_users_path do
%i.fa.fa-users
%i.fa.fa-user
%span
Users
= nav_link(controller: :groups) do
......@@ -49,3 +49,9 @@
%i.fa.fa-cogs
%span
Settings
= nav_link(controller: :applications) do
= link_to admin_applications_path do
%i.fa.fa-cloud
%span
Applications
......@@ -16,7 +16,7 @@
font-size:small;
color:#777
}
#{add_email_highlight_css}
%body
%div.content
= yield
......@@ -24,8 +24,8 @@
%p
\—
%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
#{link_to "View it on GitLab", @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 @@
= diff.new_path || diff.old_path
%hr
%pre
= diff.diff
= color_email_diff(diff.diff)
%br
- if @compare.timeout
......
......@@ -20,7 +20,7 @@
= radio_button_tag :notification_level, Notification::N_MENTION, @notification.mention?, class: 'trigger-submit'
.level-title
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
= label_tag nil, class: '' do
......
......@@ -24,7 +24,7 @@
.form-group
= f.label :password, 'New password', class: 'control-label'
.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
= f.label :password_confirmation, class: 'control-label'
.col-sm-10
......
......@@ -16,7 +16,7 @@
.col-sm-10= f.password_field :current_password, required: true, class: 'form-control'
.form-group
= 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
= f.label :password_confirmation, class: 'control-label'
.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 @@
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_user
%li.hidden-xs
......@@ -32,9 +27,6 @@
%li.pull-right
.pull-right
%button.btn.btn-default.sidebar-expand-button
%i.icon.fa.fa-list
.pull-left
= 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
......@@ -53,9 +45,6 @@
- if current_controller?(:merge_requests)
%li.pull-right
.pull-right
%button.btn.btn-default.sidebar-expand-button
%i.icon.fa.fa-list
- 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
%i.fa.fa-plus
......
.zennable
%input#zen-toggle-comment{ tabindex: '-1', type: 'checkbox' }
%input#zen-toggle-comment.zen-toggle-comment{ tabindex: '-1', type: 'checkbox' }
.zen-backdrop
- classes << ' js-gfm-input markdown-area'
= f.text_area attr, class: classes, placeholder: 'Leave a comment'
%label{ for: 'zen-toggle-comment', class: 'expand' } Edit in fullscreen
%label{ for: 'zen-toggle-comment', class: 'collapse' }
= link_to nil, class: 'zen-enter-link', tabindex: '-1' do
%i.fa.fa-expand
Edit in fullscreen
= link_to nil, class: 'zen-leave-link' do
%i.fa.fa-compress
......@@ -26,9 +26,9 @@
= i
\
%td.lines
%pre
%code{ class: highlightjs_class(@blob.name) }
%pre{class: 'code highlight white'}
%code
:erb
<% lines.each do |line| %>
<%= line %>
<%= highlight(@blob.name, line, true).html_safe %>
<% end %>
......@@ -8,6 +8,6 @@
- else
.file-content.code
- unless blob.empty?
= render 'shared/file_hljs', blob: blob
= render 'shared/file_highlight', blob: blob
- else
.nothing-here-block Empty file
......@@ -50,6 +50,13 @@
%span.js-details-content.hide
= commit_branches_links(@project, @branches)
- if @tags.any?
.commit-info-row
%span.cgray
Tags:
%span
= commit_tags_links(@project, @tags)
.commit-box
%h3.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|
.row.commits-row
.col-md-2
......
......@@ -9,6 +9,9 @@
.diff-btn-group
- if @commit.parent_ids.present?
= 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
- if diff_file.renamed_file
%span= "#{diff_file.old_path} renamed to #{diff_file.new_path}"
......@@ -26,7 +29,7 @@
&nbsp;
= link_to '#', class: 'js-toggle-diff-comments btn btn-small' do
%i.fa.fa-chevron-down
Diff comments
Show/Hide comments
&nbsp;
- if @merge_request && @merge_request.source_project
......
......@@ -6,21 +6,7 @@
= 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
.file-holder.file
.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 'projects/blob_editor', ref: @ref, path: @path, blob_data: @blob.data
= render 'shared/commit_message_container', params: params,
placeholder: "Update #{@blob.name}"
= hidden_field_tag 'last_commit', @last_commit
......@@ -34,7 +20,6 @@
ace.config.loadModule("ace/ext/searchbox");
var ace_mode = "#{@blob.language.try(:ace_mode)}";
var editor = ace.edit("editor");
editor.setValue("#{escape_javascript(@blob.data)}");
if (ace_mode) {
editor.getSession().setMode('ace/mode/' + ace_mode);
}
......
......@@ -19,14 +19,14 @@
%span.slead.has_tooltip{:"data-original-title" => 'Cross-project reference'}
= cross_project_reference(@project, @issue)
%hr
.context
%cite.cgray
= render partial: 'issue_context', locals: { issue: @issue }
%hr
.clearfix
.votes-holder
%h6 Votes
#votes= render 'votes/votes_block', votable: @issue
%hr
.context
%cite.cgray
= render partial: 'issue_context', locals: { issue: @issue }
- if @issue.labels.any?
%hr
......
......@@ -10,7 +10,7 @@
.pull-right
- if can?(current_user, :write_issue, @project)
= link_to new_project_issue_path(@project), class: "btn btn-grouped", title: "New Issue", id: "new_issue_link" do
= 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
New Issue
- if can?(current_user, :modify_issue, @issue)
......
......@@ -14,13 +14,13 @@
%span.slead.has_tooltip{:"data-original-title" => 'Cross-project reference'}
= cross_project_reference(@project, @merge_request)
%hr
.votes-holder.hidden-sm.hidden-xs
%h6 Votes
#votes= render 'votes/votes_block', votable: @merge_request
%hr
.context
%cite.cgray
= render partial: 'projects/merge_requests/show/context', locals: { merge_request: @merge_request }
%hr
.votes-holder.hidden-sm.hidden-xs
%h6 Votes
#votes= render 'votes/votes_block', votable: @merge_request
- if @merge_request.labels.any?
%hr
......
......@@ -19,12 +19,7 @@
Encoding
.col-sm-10
= select_tag :encoding, options_for_select([ "base64", "text" ], "text"), class: 'form-control'
.file-holder
.file-title
%i.fa.fa-file
.file-content.code
%pre#editor= params[:content]
= render 'projects/blob_editor', ref: @ref
= render 'shared/commit_message_container', params: params,
placeholder: 'Add new file'
= 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 @@
= render layout: 'projects/md_preview' do
= render 'projects/zen', f: f, attr: :note,
classes: 'note_text js-note-text'
.light.clearfix
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 }.
......@@ -24,7 +25,7 @@
%i.fa.fa-paperclip
%span Choose File ...
&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"
: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-icon
- if note.system
......@@ -42,25 +42,7 @@
.note-text
= preserve do
= markdown(note.note, {no_header_anchors: true})
.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"
= render 'projects/notes/edit_form', note: note
- if note.attachment.url
.note-attachment
......
- tree, commit = submodule_links(submodule_item)
%tr{ class: "tree-item" }
%td.tree-item-file-name
%i.fa.fa-archive
%span
= 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
= submodule_link(submodule_item, @ref)
%td
%td.hidden-xs
......@@ -35,7 +35,7 @@
- if @path.present?
%tr.tree-item
%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.hidden-xs
......
......@@ -24,7 +24,7 @@
%td
= commit.message
%td
#{time_ago_with_tooltip(version.date)}
#{time_ago_with_tooltip(version.authored_date)}
%td
%strong
= @page.page.wiki.page(@page.page.name, commit.id).try(:format)
......@@ -6,4 +6,4 @@
%strong
= blob.filename
.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 @@
%strong
= wiki_blob.filename
.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
- if blob.data.present?
- blob.data.lines.to_a.size.times do |index|
......@@ -7,7 +7,4 @@
= link_to "#L#{i}", id: "L#{i}", rel: "#L#{i}" do
%i.fa.fa-link
= i
.highlight
%pre
%code{ class: highlightjs_class(blob.name) }
#{blob.data}
= highlight(blob.name, blob.data)
.fixed.sidebar-expand-button.hidden-lg.hidden-md
%i.fa.fa-list.fa-2x
.responsive-side.milestones-filters.append-bottom-10
.milestones-filters.append-bottom-10
%ul.nav.nav-pills.nav-compact
%li{class: ("active" if params[:state].blank? || params[:state] == 'opened')}
= link_to milestones_filter_path(state: 'opened') do
......
......@@ -6,7 +6,7 @@
- else
Newest
%b.caret
%ul.dropdown-menu
%ul.dropdown-menu.dropdown-menu-align-right
%li
= link_to page_filter_path(sort: 'newest') do
= sort_title_recently_created
......
......@@ -8,7 +8,7 @@
= render_markup(@snippet.file_name, @snippet.data)
- else
.file-content.code
= render 'shared/file_hljs', blob: @snippet
= render 'shared/file_highlight', blob: @snippet
- else
.file-content.code
.nothing-here-block Empty file
......@@ -18,6 +18,3 @@ rm config/resque.yml
# Set default unicorn.rb file
echo "" > config/unicorn.rb
# Required for assets precompilation
sudo service postgresql start
......@@ -44,7 +44,7 @@ production: &base
# Email address used in the "From" field in mails sent by GitLab
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
default_projects_limit: 10
......@@ -77,7 +77,7 @@ production: &base
# 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.
# 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_projects_features:
......
......@@ -112,11 +112,11 @@ rescue ArgumentError # no user configured
'/home/' + Settings.gitlab['user']
end
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['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['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['webhook_timeout'] ||= 10
Settings.gitlab.default_projects_features['issues'] = true if Settings.gitlab.default_projects_features['issues'].nil?
......
......@@ -40,7 +40,7 @@ Doorkeeper.configure do
# Optional parameter :confirmation => true (default false) if you want to enforce ownership of
# a registered application
# 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
# For more information go to
......
......@@ -58,6 +58,7 @@ Gitlab::Application.routes.draw do
resource :github_import, only: [:create, :new] do
get :status
get :callback
get :jobs
end
#
......@@ -98,6 +99,8 @@ Gitlab::Application.routes.draw do
end
end
resources :applications
resources :groups, constraints: { id: /[^\/]+/ } do
member do
put :project_teams_update
......@@ -163,8 +166,8 @@ Gitlab::Application.routes.draw do
end
end
match "/u/:username" => "users#show", as: :user,
constraints: {username: /(?:[^.]|\.(?!atom$))+/, format: /atom/}, via: :get
get '/u/:username' => 'users#show', as: :user,
constraints: { username: /(?:[^.]|\.(?!atom$))+/, format: /atom/ }
#
# Dashboard Area
......
......@@ -5,7 +5,6 @@ Gitlab::Seeder.quiet do
s.email = 'admin@example.com'
s.username = 'root'
s.password = '5iveL!fe'
s.password_confirmation = '5iveL!fe'
s.admin = true
s.projects_limit = 100
s.confirmed_at = DateTime.now
......
......@@ -11,7 +11,6 @@ admin = User.create(
name: "Administrator",
username: 'root',
password: password,
password_confirmation: password,
password_expires_at: expire_time,
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 @@
#
# 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
enable_extension "plpgsql"
......@@ -49,6 +49,7 @@ ActiveRecord::Schema.define(version: 20150108073740) do
t.text "sign_in_text"
t.datetime "created_at"
t.datetime "updated_at"
t.string "home_page_url"
end
create_table "broadcast_messages", force: true do |t|
......
......@@ -14,7 +14,8 @@ GET /groups
"id": 1,
"name": "Foobar Group",
"path": "foo-bar",
"owner_id": 18
"owner_id": 18,
"description": "An interesting group"
}
]
```
......@@ -45,6 +46,7 @@ Parameters:
- `name` (required) - The name of the group
- `path` (required) - The path of the group
- `description` (optional) - The group's description
## Transfer project to group
......
......@@ -109,6 +109,7 @@ Parameters:
- `target_branch` (required) - The target branch
- `assignee_id` (optional) - Assignee user ID
- `title` (required) - Title of MR
- `description` (optional) - Description of MR
- `target_project_id` (optional) - The target project (numeric id)
```json
......@@ -160,6 +161,7 @@ Parameters:
- `target_branch` - The target branch
- `assignee_id` - Assignee user ID
- `title` - Title of MR
- `description` - Description of MR
- `state_event` - New state (close|reopen|merge)
```json
......@@ -169,6 +171,7 @@ Parameters:
"source_branch": "test1",
"project_id": 3,
"title": "test1",
"description": "description1",
"state": "opened",
"upvotes": 0,
"downvotes": 0,
......
......@@ -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.
# 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.
# 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
- 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'
- 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. 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.
- 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.
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:
```
$ 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:
#### Omnibus Installation
......
......@@ -121,6 +121,6 @@ Add to your local `gitlab-ci/.git/config`:
* Create a stable branch `x-y-stable`
* 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)`
......@@ -119,7 +119,7 @@ sudo apt-get install pkg-config cmake
```bash
cd /home/git/gitlab-shell
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.
......
......@@ -37,7 +37,7 @@ sudo -u git -H git checkout 7-7-stable-ee
```bash
cd /home/git/gitlab-shell
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.
......@@ -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!
### 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)
### 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
"name": "GitLab dev user",
"email": "gitlabdev@dv6700.(none)"
}
}
},
"url": "http://example.com/diaspora/merge_requests/1",
"action": "open"
}
}
```
......
......@@ -9,4 +9,5 @@
- [GitLab Flow](gitlab_flow.md)
- [Notifications](notifications.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)
# 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 \
# 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.
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 \
&& 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
And I visit admin settings page
Scenario: Change application settings
When I disable gravatars and save form
Then I should be see gravatar disabled
When I modify settings and save form
Then I should see application settings saved
......@@ -97,22 +97,3 @@ Feature: Profile
Given I visit profile design page
When I change my code preview theme
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
Scenario: I can't cancel the main form
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
Scenario: I can preview with text
Given I write a comment like ":+1: Nice"
......
......@@ -54,12 +54,6 @@ Feature: Project Commits Diff Comments
Given I leave a diff comment like "Typo, please fix"
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
Scenario: I can preview with text
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
include SharedAdmin
include Gitlab::CurrentSettings
step 'I disable gravatars and save form' do
step 'I modify settings and save form' do
uncheck 'Gravatar enabled'
fill_in 'Home page url', with: 'https://about.gitlab.com/'
click_button 'Save'
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.home_page_url.should == 'https://about.gitlab.com/'
page.should have_content 'Application settings saved successfully'
end
end
......@@ -58,34 +58,16 @@ class Spinach::Features::Profile < Spinach::FeatureSteps
step 'I try change my password w/o old one' 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"
click_button "Save"
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
within '.update-password' do
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"
click_button "Save"
end
......@@ -94,7 +76,7 @@ class Spinach::Features::Profile < Spinach::FeatureSteps
step 'I unsuccessfully change my password' do
within '.update-password' do
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"
click_button "Save"
end
......@@ -104,22 +86,6 @@ class Spinach::Features::Profile < Spinach::FeatureSteps
page.should have_content "You must provide a valid current password"
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
page.should have_content "Password confirmation doesn't match"
end
......@@ -180,7 +146,7 @@ class Spinach::Features::Profile < Spinach::FeatureSteps
step 'I submit new password' do
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'
click_button "Set new password"
end
......
......@@ -194,13 +194,13 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
step 'I click link "Hide inline discussion" of the second file' do
within '.files [id^=diff]:nth-child(2)' do
click_link "Diff comments"
click_link 'Show/Hide comments'
end
end
step 'I click link "Show inline discussion" of the second file' do
within '.files [id^=diff]:nth-child(2)' do
click_link "Diff comments"
click_link 'Show/Hide comments'
end
end
......
......@@ -80,7 +80,7 @@ module SharedDiffNote
step 'I should not see the diff comment text field' 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
......@@ -115,7 +115,7 @@ module SharedDiffNote
end
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
step 'I should see an empty diff comment form' do
......
......@@ -64,7 +64,7 @@ module SharedNote
step 'I should not see the comment text field' 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
......
......@@ -187,6 +187,10 @@ module SharedPaths
visit admin_application_settings_path
end
step 'I visit applications page' do
visit admin_applications_path
end
# ----------------------------------------
# Generic Project
# ----------------------------------------
......
......@@ -70,7 +70,7 @@ module API
end
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, _|
group.ldap_group_links.map do |group_link|
group_link.slice(:cn, :group_access)
......
......@@ -47,8 +47,8 @@ module API
authenticated_as_admin!
required_attributes! [:name, :path]
group_attrs = attributes_for_keys [:name, :path]
@group = Group.new(group_attrs)
attrs = attributes_for_keys [:name, :path, :description]
@group = Group.new(attrs)
@group.owner = current_user
if @group.save
......
......@@ -25,8 +25,8 @@ module API
# project. This applies the correct project permissions to
# the wiki repository as well.
access =
if project_path =~ /\.wiki\Z/
project_path.sub!(/\.wiki\Z/, '')
if project_path.end_with?('.wiki')
project_path.chomp!('.wiki')
Gitlab::GitAccessWiki.new
else
Gitlab::GitAccess.new
......
......@@ -167,13 +167,9 @@ module API
put ":id/merge_request/:merge_request_id/merge" do
merge_request = user_project.merge_requests.find(params[:merge_request_id])
action = if user_project.protected_branch?(merge_request.target_branch)
:push_code_to_protected_branches
else
:push_code
end
allowed = ::Gitlab::GitAccess.can_push_to_branch?(current_user, user_project, merge_request.target_branch)
if can?(current_user, action, user_project)
if allowed
if merge_request.unchecked?
merge_request.check_if_can_be_merged
end
......
......@@ -96,7 +96,7 @@ module API
# Parameters:
# id (required) - The ID of a project
# Example Request:
# GET /projects/:id
# GET /projects/:id/events
get ":id/events" do
limit = (params[:per_page] || 20).to_i
offset = (params[:page] || 0).to_i * limit
......
......@@ -3,14 +3,19 @@ module Gitlab
ISSUE_CLOSING_REGEX = Regexp.new(Gitlab.config.gitlab.issue_closing_pattern)
def self.closed_by_message_in_project(message, project)
md = ISSUE_CLOSING_REGEX.match(message)
if md
extractor = Gitlab::ReferenceExtractor.new
extractor.analyze(md[0], project)
extractor.issues_for(project)
else
[]
issues = []
unless message.nil?
md = message.scan(ISSUE_CLOSING_REGEX)
md.each do |ref|
extractor = Gitlab::ReferenceExtractor.new
extractor.analyze(ref[0], project)
issues += extractor.issues_for(project)
end
end
issues.uniq
end
end
end
module Gitlab
module CurrentSettings
def current_application_settings
begin
if ActiveRecord::Base.connection.table_exists?('application_settings')
ApplicationSetting.current ||
ApplicationSetting.create_from_defaults
else
fake_application_settings
end
rescue ActiveRecord::NoDatabaseError, database_adapter.constantize::Error
if ActiveRecord::Base.connected? && ActiveRecord::Base.connection.table_exists?('application_settings')
ApplicationSetting.current ||
ApplicationSetting.create_from_defaults
else
fake_application_settings
end
end
......@@ -22,16 +18,5 @@ module Gitlab
sign_in_text: Settings.extra['sign_in_text'],
)
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
module Gitlab
module Git
BLANK_SHA = '0' * 40
def self.extract_ref_name(ref)
ref.gsub(/\Arefs\/(tags|heads)\//, '')
end
end
end
......@@ -5,6 +5,15 @@ module Gitlab
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)
case cmd
when *DOWNLOAD_COMMANDS
......
......@@ -31,6 +31,8 @@ module Gitlab
@project.import_start
end
end
@project
end
end
end
......
module Gitlab
class PushDataBuilder
# Produce a hash of post-receive data
#
# data = {
# before: String,
# after: String,
# ref: String,
# user_id: String,
# user_name: String,
# project_id: String,
# repository: {
# name: String,
# url: String,
# description: String,
# homepage: String,
# },
# commits: Array,
# total_commits_count: Fixnum
# }
#
def self.build(project, user, oldrev, newrev, ref, commits = [])
# Total commits count
commits_count = commits.size
class << self
# Produce a hash of post-receive data
#
# data = {
# before: String,
# after: String,
# ref: String,
# user_id: String,
# user_name: String,
# project_id: String,
# repository: {
# name: String,
# url: String,
# description: String,
# homepage: String,
# },
# commits: Array,
# total_commits_count: Fixnum
# }
#
def build(project, user, oldrev, newrev, ref, commits = [])
# Total commits count
commits_count = commits.size
# Get latest 20 commits ASC
commits_limited = commits.last(20)
# Get latest 20 commits ASC
commits_limited = commits.last(20)
# Hash to be passed as post_receive_data
data = {
before: oldrev,
after: newrev,
ref: ref,
user_id: user.id,
user_name: user.name,
project_id: project.id,
repository: {
name: project.name,
url: project.url_to_repo,
description: project.description,
homepage: project.web_url,
},
commits: [],
total_commits_count: commits_count
}
# Hash to be passed as post_receive_data
data = {
before: oldrev,
after: newrev,
ref: ref,
checkout_sha: checkout_sha(project.repository, newrev, ref),
user_id: user.id,
user_name: user.name,
project_id: project.id,
repository: {
name: project.name,
url: project.url_to_repo,
description: project.description,
homepage: project.web_url,
},
commits: [],
total_commits_count: commits_count
}
# For performance purposes maximum 20 latest commits
# will be passed as post receive hook data.
commits_limited.each do |commit|
data[:commits] << commit.hook_attrs(project)
# For performance purposes maximum 20 latest commits
# will be passed as post receive hook data.
commits_limited.each do |commit|
data[:commits] << commit.hook_attrs(project)
end
data
end
data
end
# This method provide a sample data generated with
# 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
# existing project and commits to test web hooks
def self.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)
def checkout_sha(repository, newrev, ref)
if newrev != Gitlab::Git::BLANK_SHA && ref.start_with?('refs/tags/')
tag_name = Gitlab::Git.extract_ref_name(ref)
tag = repository.find_tag(tag_name)
if tag
commit = repository.commit(tag.target)
commit.try(:sha)
end
else
newrev
end
end
end
end
end
......@@ -21,23 +21,22 @@ class Redcarpet::Render::GitlabHTML < Redcarpet::Render::HTML
text.gsub("'", "&rsquo;")
end
# Stolen from Rugments::Plugins::Redcarpet as this module is not required
# from Rugments's gem root.
def block_code(code, language)
# New lines are placed to fix an rendering issue
# with code wrapped inside <h1> tag for next case:
#
# # Title kinda h1
#
# ruby code here
#
<<-HTML
lexer = Rugments::Lexer.find_fancy(language, code) || Rugments::Lexers::PlainText
<div class="highlighted-data #{h.user_color_scheme_class}">
<div class="highlight">
<pre><code class="#{language}">#{h.send(:html_escape, code)}</code></pre>
</div>
</div>
# XXX HACK: Redcarpet strips hard tabs out of code blocks,
# so we assume you're not using leading spaces that aren't tabs,
# and just replace them here.
if lexer.tag == 'make'
code.gsub! /^ /, "\t"
end
HTML
formatter = Rugments::Formatters::HTML.new(
cssclass: "code highlight white #{lexer.tag}"
)
formatter.format(lexer.lex(code))
end
def link(link, title, content)
......
......@@ -25,7 +25,7 @@ namespace :gitlab do
puts "Processing #{repo_path}".yellow
if path =~ /\.wiki\Z/
if path.end_with?('.wiki')
puts " * Skipping wiki repo"
next
end
......@@ -66,6 +66,7 @@ namespace :gitlab do
puts " * Created #{project.name} (#{repo_path})".green
else
puts " * Failed trying to create #{project.name} (#{repo_path})".red
puts " Validation Errors: #{project.errors.messages}".red
end
end
end
......
......@@ -54,8 +54,8 @@ namespace :gitlab do
<div class='footer' style='margin-top: 10px;'>
<p>
<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>
You're receiving this notification because you are a member of the Base / Rails Project project team.
#{schema}
</p>
</div>
......
......@@ -20,7 +20,6 @@ FactoryGirl.define do
name
sequence(:username) { |n| "#{Faker::Internet.user_name}#{n}" }
password "12345678"
password_confirmation { password }
confirmed_at { Time.now }
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
it "should show the note edit form and hide the note body" 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-text", visible: false).should_not be_visible
find(:css, ".note-text", visible: false).should_not be_visible
end
end
it "should reset the edit note form textarea with the original content of the note if cancelled" do
find('.note').hover
find(".js-note-edit").click
within(".note-edit-form") do
fill_in "note[note]", with: "Some new content"
find(".btn-cancel").click
find(".js-note-text", visible: false).text.should == note.note
end
end
# TODO: fix after 7.7 release
#it "should reset the edit note form textarea with the original content of the note if cancelled" do
#within(".current-note-edit-form") do
#fill_in "note[note]", with: "Some new content"
#find(".btn-cancel").click
#find(".js-note-text", visible: false).text.should == note.note
#end
#end
it "appends the edited at time to the note" do
find('.note').hover
find(".js-note-edit").click
within(".note-edit-form") do
within(".current-note-edit-form") do
fill_in "note[note]", with: "Some new content"
find(".btn-save").click
end
within("#note_#{note.id}") do
should have_css(".note-last-update small")
find(".note-last-update small").text.should match(/Edited less than a minute ago/)
should have_css(".note_edited_ago")
find(".note_edited_ago").text.should match(/less than a minute ago/)
end
end
end
......@@ -119,7 +115,7 @@ describe 'Comments' do
it "removes the attachment div and resets the edit form" do
find(".js-note-attachment-delete").click
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
......
......@@ -11,7 +11,7 @@ describe 'Users', feature: true do
fill_in "user_name", with: "Name Surname"
fill_in "user_username", with: "Great"
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"
expect { click_button "Sign up" }.to change {User.count}.by(1)
end
......
......@@ -73,7 +73,7 @@ describe ApplicationHelper do
user = create(:user)
user.avatar = File.open(avatar_file_path)
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
it "should call gravatar_icon when no avatar is present" do
......
......@@ -26,7 +26,8 @@ describe EventsHelper do
it 'should display the first line of a code block' do
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)
end
......
......@@ -612,7 +612,7 @@ describe GitlabMarkdownHelper do
it "should leave code blocks untouched" do
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```\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
let(:project) { create(:project) }
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 'master permissions' do
before { project.team << [user, :master] }
......
......@@ -21,13 +21,14 @@ describe 'Gitlab::PushDataBuilder' do
Gitlab::PushDataBuilder.build(project,
user,
Gitlab::Git::BLANK_SHA,
'5937ac0a7beb003549fc5fd26fc247adbce4a52e',
'8a2a6eb295bb170b34c24c76c49ed0e9b2eaf34b',
'refs/tags/v1.1.0')
end
it { data.should be_a(Hash) }
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[:commits].should be_empty }
it { data[:total_commits_count].should be_zero }
......
......@@ -57,16 +57,12 @@ eos
let(:other_issue) { create :issue, project: other_project }
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.closes_issues(project).should == [issue]
end
it 'does not detect issues from other projects' do
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.closes_issues(project).should be_empty
end
......
......@@ -36,7 +36,7 @@ describe WikiPage do
end
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
......
......@@ -12,14 +12,23 @@ describe MergeRequests::CloseService do
end
describe :execute do
context "valid params" do
context 'valid params' do
let(:service) { MergeRequests::CloseService.new(project, user, {}) }
before do
@merge_request = MergeRequests::CloseService.new(project, user, {}).execute(merge_request)
service.stub(:execute_hooks)
@merge_request = service.execute(merge_request)
end
it { @merge_request.should be_valid }
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
email = ActionMailer::Base.deliveries.last
email.to.first.should == user2.email
......@@ -28,7 +37,7 @@ describe MergeRequests::CloseService do
it 'should create system note about merge_request reassign' do
note = @merge_request.notes.last
note.note.should include "Status changed to closed"
note.note.should include 'Status changed to closed'
end
end
end
......
......@@ -5,21 +5,30 @@ describe MergeRequests::CreateService do
let(:user) { create(:user) }
describe :execute do
context "valid params" do
before do
project.team << [user, :master]
opts = {
context 'valid params' do
let(:opts) do
{
title: 'Awesome merge_request',
description: 'please fix',
source_branch: 'stable',
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
it { @merge_request.should be_valid }
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
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
end
describe :execute do
context "valid params" do
before do
opts = {
context 'valid params' do
let(:opts) do
{
title: 'New title',
description: 'Also please fix',
assignee_id: user2.id,
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
it { @merge_request.should be_valid }
......@@ -29,6 +34,11 @@ describe MergeRequests::UpdateService do
it { @merge_request.assignee.should == user2 }
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
email = ActionMailer::Base.deliveries.last
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