summaryrefslogtreecommitdiff
path: root/app/assets
diff options
context:
space:
mode:
authorFelipe Artur <felipefac@gmail.com>2016-06-22 10:47:48 -0300
committerFelipe Artur <felipefac@gmail.com>2016-06-22 10:47:48 -0300
commit2674b548601b279ada46d4b218a9def6fd5b9f6d (patch)
treeca1f09225e4d5b80c800af521735bf34f04e16d0 /app/assets
parent8447c6b180297840d835a609d95808834f498d87 (diff)
parent6f6c6f68ea7cb976b6c1598e705ba8b2bdaf05a1 (diff)
downloadgitlab-ce-2674b548601b279ada46d4b218a9def6fd5b9f6d.tar.gz
merge master into issue_3359_3
Diffstat (limited to 'app/assets')
-rw-r--r--app/assets/javascripts/LabelManager.js.coffee12
-rw-r--r--app/assets/javascripts/api.js.coffee7
-rw-r--r--app/assets/javascripts/application.js.coffee80
-rw-r--r--app/assets/javascripts/awards_handler.coffee2
-rw-r--r--app/assets/javascripts/blob/blob_ci_yaml.js.coffee23
-rw-r--r--app/assets/javascripts/blob/blob_gitignore_selector.js.coffee61
-rw-r--r--app/assets/javascripts/blob/blob_gitignore_selectors.js.coffee17
-rw-r--r--app/assets/javascripts/blob/blob_license_selector.js.coffee35
-rw-r--r--app/assets/javascripts/blob/blob_license_selectors.js.coffee17
-rw-r--r--app/assets/javascripts/blob/edit_blob.js.coffee6
-rw-r--r--app/assets/javascripts/blob/template_selector.js.coffee56
-rw-r--r--app/assets/javascripts/ci/build.coffee9
-rw-r--r--app/assets/javascripts/dispatcher.js.coffee19
-rw-r--r--app/assets/javascripts/due_date_select.js.coffee21
-rw-r--r--app/assets/javascripts/gfm_auto_complete.js.coffee24
-rw-r--r--app/assets/javascripts/gl_dropdown.js.coffee15
-rw-r--r--app/assets/javascripts/gl_form.js.coffee3
-rw-r--r--app/assets/javascripts/graphs/stat_graph_contributors_graph.js.coffee6
-rw-r--r--app/assets/javascripts/issuable.js.coffee57
-rw-r--r--app/assets/javascripts/issuable_form.js.coffee4
-rw-r--r--app/assets/javascripts/issues-bulk-assignment.js.coffee3
-rw-r--r--app/assets/javascripts/labels_select.js.coffee29
-rw-r--r--app/assets/javascripts/layout_nav.js.coffee39
-rw-r--r--app/assets/javascripts/lib/common_utils.js.coffee41
-rw-r--r--app/assets/javascripts/lib/text_utility.js.coffee79
-rw-r--r--app/assets/javascripts/logo.js.coffee6
-rw-r--r--app/assets/javascripts/merge_request.js.coffee2
-rw-r--r--app/assets/javascripts/merge_request_tabs.js.coffee2
-rw-r--r--app/assets/javascripts/merged_buttons.js.coffee30
-rw-r--r--app/assets/javascripts/milestone_select.js.coffee10
-rw-r--r--app/assets/javascripts/network/application.js.coffee20
-rw-r--r--app/assets/javascripts/network/branch-graph.js.coffee (renamed from app/assets/javascripts/branch-graph.js.coffee)0
-rw-r--r--app/assets/javascripts/network/network.js.coffee (renamed from app/assets/javascripts/network.js.coffee)0
-rw-r--r--app/assets/javascripts/notes.js.coffee11
-rw-r--r--app/assets/javascripts/notifications_dropdown.js.coffee18
-rw-r--r--app/assets/javascripts/notifications_form.js.coffee3
-rw-r--r--app/assets/javascripts/project.js.coffee38
-rw-r--r--app/assets/javascripts/right_sidebar.js.coffee55
-rw-r--r--app/assets/javascripts/search_autocomplete.js.coffee56
-rw-r--r--app/assets/javascripts/shortcuts.js.coffee4
-rw-r--r--app/assets/javascripts/shortcuts_blob.coffee10
-rw-r--r--app/assets/javascripts/sidebar.js.coffee24
-rw-r--r--app/assets/javascripts/star.js.coffee2
-rw-r--r--app/assets/javascripts/users/calendar.js.coffee17
-rw-r--r--app/assets/javascripts/users_select.js.coffee6
-rw-r--r--app/assets/stylesheets/framework.scss1
-rw-r--r--app/assets/stylesheets/framework/blank.scss23
-rw-r--r--app/assets/stylesheets/framework/blocks.scss20
-rw-r--r--app/assets/stylesheets/framework/dropdowns.scss10
-rw-r--r--app/assets/stylesheets/framework/gitlab-theme.scss4
-rw-r--r--app/assets/stylesheets/framework/header.scss47
-rw-r--r--app/assets/stylesheets/framework/lists.scss2
-rw-r--r--app/assets/stylesheets/framework/markdown_area.scss30
-rw-r--r--app/assets/stylesheets/framework/mixins.scss14
-rw-r--r--app/assets/stylesheets/framework/mobile.scss13
-rw-r--r--app/assets/stylesheets/framework/nav.scss46
-rw-r--r--app/assets/stylesheets/framework/panels.scss4
-rw-r--r--app/assets/stylesheets/framework/selects.scss5
-rw-r--r--app/assets/stylesheets/framework/sidebar.scss204
-rw-r--r--app/assets/stylesheets/framework/variables.scss12
-rw-r--r--app/assets/stylesheets/mailers/devise.scss4
-rw-r--r--app/assets/stylesheets/pages/commit.scss2
-rw-r--r--app/assets/stylesheets/pages/commits.scss142
-rw-r--r--app/assets/stylesheets/pages/diff.scss5
-rw-r--r--app/assets/stylesheets/pages/editor.scss12
-rw-r--r--app/assets/stylesheets/pages/environments.scss5
-rw-r--r--app/assets/stylesheets/pages/events.scss7
-rw-r--r--app/assets/stylesheets/pages/groups.scss17
-rw-r--r--app/assets/stylesheets/pages/help.scss7
-rw-r--r--app/assets/stylesheets/pages/issuable.scss31
-rw-r--r--app/assets/stylesheets/pages/labels.scss18
-rw-r--r--app/assets/stylesheets/pages/merge_requests.scss33
-rw-r--r--app/assets/stylesheets/pages/note_form.scss17
-rw-r--r--app/assets/stylesheets/pages/notes.scss35
-rw-r--r--app/assets/stylesheets/pages/profile.scss19
-rw-r--r--app/assets/stylesheets/pages/projects.scss67
-rw-r--r--app/assets/stylesheets/pages/stat_graph.scss22
-rw-r--r--app/assets/stylesheets/pages/todos.scss4
-rw-r--r--app/assets/stylesheets/pages/tree.scss4
79 files changed, 1341 insertions, 524 deletions
diff --git a/app/assets/javascripts/LabelManager.js.coffee b/app/assets/javascripts/LabelManager.js.coffee
index 365a062bb81..6d8faba40d7 100644
--- a/app/assets/javascripts/LabelManager.js.coffee
+++ b/app/assets/javascripts/LabelManager.js.coffee
@@ -27,6 +27,11 @@ class @LabelManager
$btn = $(e.currentTarget)
$label = $("##{$btn.data('domId')}")
action = if $btn.parents('.js-prioritized-labels').length then 'remove' else 'add'
+
+ # Make sure tooltip will hide
+ $tooltip = $ "##{$btn.find('.has-tooltip:visible').attr('aria-describedby')}"
+ $tooltip.tooltip 'destroy'
+
_this.toggleLabelPriority($label, action)
toggleLabelPriority: ($label, action, persistState = true) ->
@@ -42,10 +47,10 @@ class @LabelManager
$from = @prioritizedLabels
if $from.find('li').length is 1
- $from.find('.empty-message').show()
+ $from.find('.empty-message').removeClass('hidden')
if not $target.find('li').length
- $target.find('.empty-message').hide()
+ $target.find('.empty-message').addClass('hidden')
$label.detach().appendTo($target)
@@ -54,6 +59,9 @@ class @LabelManager
if action is 'remove'
xhr = $.ajax url: url, type: 'DELETE'
+
+ # Restore empty message
+ $from.find('.empty-message').removeClass('hidden') unless $from.find('li').length
else
xhr = @savePrioritySort($label, action)
diff --git a/app/assets/javascripts/api.js.coffee b/app/assets/javascripts/api.js.coffee
index 3f61ea1eaf4..cf46f15a156 100644
--- a/app/assets/javascripts/api.js.coffee
+++ b/app/assets/javascripts/api.js.coffee
@@ -7,6 +7,7 @@
labelsPath: "/api/:version/projects/:id/labels"
licensePath: "/api/:version/licenses/:key"
gitignorePath: "/api/:version/gitignores/:key"
+ gitlabCiYmlPath: "/api/:version/gitlab_ci_ymls/:key"
group: (group_id, callback) ->
url = Api.buildUrl(Api.groupPath)
@@ -110,6 +111,12 @@
$.get url, (gitignore) ->
callback(gitignore)
+ gitlabCiYml: (key, callback) ->
+ url = Api.buildUrl(Api.gitlabCiYmlPath).replace(':key', key)
+
+ $.get url, (file) ->
+ callback(file)
+
buildUrl: (url) ->
url = gon.relative_url_root + url if gon.relative_url_root?
return url.replace(':version', gon.api_version)
diff --git a/app/assets/javascripts/application.js.coffee b/app/assets/javascripts/application.js.coffee
index 69d4c4f5dd3..0206db461da 100644
--- a/app/assets/javascripts/application.js.coffee
+++ b/app/assets/javascripts/application.js.coffee
@@ -32,10 +32,6 @@
#= require bootstrap/tooltip
#= require bootstrap/popover
#= require select2
-#= require raphael
-#= require g.raphael
-#= require g.bar
-#= require branch-graph
#= require ace/ace
#= require ace/ext-searchbox
#= require underscore
@@ -125,9 +121,15 @@ window.onload = ->
setTimeout shiftWindow, 100
$ ->
+
+ $document = $(document)
+ $window = $(window)
+ $body = $('body')
+
+ gl.utils.preventDisabledButtons()
bootstrapBreakpoint = bp.getBreakpointSize()
- $(".nicescroll").niceScroll(cursoropacitymax: '0.4', cursorcolor: '#FFF', cursorborder: "1px solid #FFF")
+ $(".nav-sidebar").niceScroll(cursoropacitymax: '0.4', cursorcolor: '#FFF', cursorborder: "1px solid #FFF")
# Click a .js-select-on-focus field, select the contents
$(".js-select-on-focus").on "focusin", ->
@@ -155,7 +157,7 @@ $ ->
), 1
# Initialize tooltips
- $('body').tooltip(
+ $body.tooltip(
selector: '.has-tooltip, [data-toggle="tooltip"]'
placement: (_, el) ->
$el = $(el)
@@ -174,7 +176,7 @@ $ ->
flash.show()
# Disable form buttons while a form is submitting
- $('body').on 'ajax:complete, ajax:beforeSend, submit', 'form', (e) ->
+ $body.on 'ajax:complete, ajax:beforeSend, submit', 'form', (e) ->
buttons = $('[type="submit"]', @)
switch e.type
@@ -187,7 +189,7 @@ $ ->
$('.account-box').hover -> $(@).toggleClass('hover')
# Commit show suppressed diff
- $(document).on 'click', '.diff-content .js-show-suppressed-diff', ->
+ $document.on 'click', '.diff-content .js-show-suppressed-diff', ->
$container = $(@).parent()
$container.next('table').show()
$container.remove()
@@ -200,13 +202,13 @@ $ ->
$('.navbar-toggle i').toggleClass("fa-angle-right fa-angle-left")
# Show/hide comments on diff
- $("body").on "click", ".js-toggle-diff-comments", (e) ->
+ $body.on "click", ".js-toggle-diff-comments", (e) ->
$(@).toggleClass('active')
$(@).closest(".diff-file").find(".notes_holder").toggle()
e.preventDefault()
- $(document).off "click", '.js-confirm-danger'
- $(document).on "click", '.js-confirm-danger', (e) ->
+ $document.off "click", '.js-confirm-danger'
+ $document.on "click", '.js-confirm-danger', (e) ->
e.preventDefault()
btn = $(e.target)
text = btn.data("confirm-danger-message")
@@ -214,7 +216,7 @@ $ ->
new ConfirmDangerModal(form, text)
- $(document).on 'click', 'button', ->
+ $document.on 'click', 'button', ->
$(this).blur()
$('input[type="search"]').each ->
@@ -222,7 +224,7 @@ $ ->
$this.attr 'value', $this.val()
return
- $(document)
+ $document
.off 'keyup', 'input[type="search"]'
.on 'keyup', 'input[type="search"]' , (e) ->
$this = $(this)
@@ -230,7 +232,7 @@ $ ->
$sidebarGutterToggle = $('.js-sidebar-toggle')
- $(document)
+ $document
.off 'breakpoint:change'
.on 'breakpoint:change', (e, breakpoint) ->
if breakpoint is 'sm' or breakpoint is 'xs'
@@ -242,14 +244,14 @@ $ ->
oldBootstrapBreakpoint = bootstrapBreakpoint
bootstrapBreakpoint = bp.getBreakpointSize()
if bootstrapBreakpoint != oldBootstrapBreakpoint
- $(document).trigger('breakpoint:change', [bootstrapBreakpoint])
+ $document.trigger('breakpoint:change', [bootstrapBreakpoint])
checkInitialSidebarSize = ->
bootstrapBreakpoint = bp.getBreakpointSize()
if bootstrapBreakpoint is "xs" or "sm"
- $(document).trigger('breakpoint:change', [bootstrapBreakpoint])
+ $document.trigger('breakpoint:change', [bootstrapBreakpoint])
- $(window)
+ $window
.off "resize.app"
.on "resize.app", (e) ->
fitSidebarForSize()
@@ -257,3 +259,47 @@ $ ->
gl.awardsHandler = new AwardsHandler()
checkInitialSidebarSize()
new Aside()
+
+ # Sidenav pinning
+ if $window.width() < 1440 and $.cookie('pin_nav') is 'true'
+ $.cookie('pin_nav', 'false', { path: '/' })
+ $('.page-with-sidebar')
+ .toggleClass('page-sidebar-collapsed page-sidebar-expanded')
+ .removeClass('page-sidebar-pinned')
+ $('.navbar-fixed-top').removeClass('header-pinned-nav')
+
+ $document
+ .off 'click', '.js-nav-pin'
+ .on 'click', '.js-nav-pin', (e) ->
+ e.preventDefault()
+
+ $pinBtn = $(e.currentTarget)
+ $page = $ '.page-with-sidebar'
+ $topNav = $ '.navbar-fixed-top'
+ $tooltip = $ "##{$pinBtn.attr('aria-describedby')}"
+ doPinNav = not $page.is('.page-sidebar-pinned')
+ tooltipText = 'Pin navigation'
+
+ $(this).toggleClass 'is-active'
+
+ if doPinNav
+ $page.addClass('page-sidebar-pinned')
+ $topNav.addClass('header-pinned-nav')
+ else
+ $tooltip.remove() # Remove it immediately when collapsing the sidebar
+ $page.removeClass('page-sidebar-pinned')
+ .toggleClass('page-sidebar-collapsed page-sidebar-expanded')
+ $topNav.removeClass('header-pinned-nav')
+ .toggleClass('header-collapsed header-expanded')
+
+ # Save settings
+ $.cookie 'pin_nav', doPinNav, { path: '/' }
+
+ if $.cookie('pin_nav') is 'true' or doPinNav
+ tooltipText = 'Unpin navigation'
+
+ # Update tooltip text immediately
+ $tooltip.find('.tooltip-inner').text(tooltipText)
+
+ # Persist tooltip title
+ $pinBtn.attr('title', tooltipText).tooltip('fixTitle')
diff --git a/app/assets/javascripts/awards_handler.coffee b/app/assets/javascripts/awards_handler.coffee
index 136db8ee14d..030f1564862 100644
--- a/app/assets/javascripts/awards_handler.coffee
+++ b/app/assets/javascripts/awards_handler.coffee
@@ -40,7 +40,7 @@ class @AwardsHandler
$menu = $ '.emoji-menu'
if $addBtn.hasClass 'js-note-emoji'
- $addBtn.parents('.note').find('.js-awards-block').addClass 'current'
+ $addBtn.closest('.note').find('.js-awards-block').addClass 'current'
else
$addBtn.closest('.js-awards-block').addClass 'current'
diff --git a/app/assets/javascripts/blob/blob_ci_yaml.js.coffee b/app/assets/javascripts/blob/blob_ci_yaml.js.coffee
new file mode 100644
index 00000000000..d9a03d05529
--- /dev/null
+++ b/app/assets/javascripts/blob/blob_ci_yaml.js.coffee
@@ -0,0 +1,23 @@
+#= require blob/template_selector
+
+class @BlobCiYamlSelector extends TemplateSelector
+ requestFile: (query) ->
+ Api.gitlabCiYml query.name, @requestFileSuccess.bind(@)
+
+class @BlobCiYamlSelectors
+ constructor: (opts) ->
+ {
+ @$dropdowns = $('.js-gitlab-ci-yml-selector')
+ @editor
+ } = opts
+
+ @$dropdowns.each (i, dropdown) =>
+ $dropdown = $(dropdown)
+
+ new BlobCiYamlSelector(
+ pattern: /(.gitlab-ci.yml)/,
+ data: $dropdown.data('data'),
+ wrapper: $dropdown.closest('.js-gitlab-ci-yml-selector-wrap'),
+ dropdown: $dropdown,
+ editor: @editor
+ )
diff --git a/app/assets/javascripts/blob/blob_gitignore_selector.js.coffee b/app/assets/javascripts/blob/blob_gitignore_selector.js.coffee
index cc8a497d081..8d0e3f363d1 100644
--- a/app/assets/javascripts/blob/blob_gitignore_selector.js.coffee
+++ b/app/assets/javascripts/blob/blob_gitignore_selector.js.coffee
@@ -1,58 +1,5 @@
-class @BlobGitignoreSelector
- constructor: (opts) ->
- {
- @dropdown
- @editor
- @$wrapper = @dropdown.closest('.gitignore-selector')
- @$filenameInput = $('#file_name')
- @data = @dropdown.data('filenames')
- } = opts
+#= require blob/template_selector
- @dropdown.glDropdown(
- data: @data,
- filterable: true,
- selectable: true,
- search:
- fields: ['name']
- clicked: @onClick
- text: (gitignore) ->
- gitignore.name
- )
-
- @toggleGitignoreSelector()
- @bindEvents()
-
- bindEvents: ->
- @$filenameInput
- .on 'keyup blur', (e) =>
- @toggleGitignoreSelector()
-
- toggleGitignoreSelector: ->
- filename = @$filenameInput.val() or $('.editor-file-name').text().trim()
- @$wrapper.toggleClass 'hidden', filename isnt '.gitignore'
-
- onClick: (item, el, e) =>
- e.preventDefault()
- @requestIgnoreFile(item.name)
-
- requestIgnoreFile: (name) ->
- Api.gitignoreText name, @requestIgnoreFileSuccess.bind(@)
-
- requestIgnoreFileSuccess: (gitignore) ->
- @editor.setValue(gitignore.content, 1)
- @editor.focus()
-
-class @BlobGitignoreSelectors
- constructor: (opts) ->
- {
- @$dropdowns = $('.js-gitignore-selector')
- @editor
- } = opts
-
- @$dropdowns.each (i, dropdown) =>
- $dropdown = $(dropdown)
-
- new BlobGitignoreSelector(
- dropdown: $dropdown,
- editor: @editor
- )
+class @BlobGitignoreSelector extends TemplateSelector
+ requestFile: (query) ->
+ Api.gitignoreText query.name, @requestFileSuccess.bind(@)
diff --git a/app/assets/javascripts/blob/blob_gitignore_selectors.js.coffee b/app/assets/javascripts/blob/blob_gitignore_selectors.js.coffee
new file mode 100644
index 00000000000..a719ba25122
--- /dev/null
+++ b/app/assets/javascripts/blob/blob_gitignore_selectors.js.coffee
@@ -0,0 +1,17 @@
+class @BlobGitignoreSelectors
+ constructor: (opts) ->
+ {
+ @$dropdowns = $('.js-gitignore-selector')
+ @editor
+ } = opts
+
+ @$dropdowns.each (i, dropdown) =>
+ $dropdown = $(dropdown)
+
+ new BlobGitignoreSelector(
+ pattern: /(.gitignore)/,
+ data: $dropdown.data('data'),
+ wrapper: $dropdown.closest('.js-gitignore-selector-wrap'),
+ dropdown: $dropdown,
+ editor: @editor
+ )
diff --git a/app/assets/javascripts/blob/blob_license_selector.js.coffee b/app/assets/javascripts/blob/blob_license_selector.js.coffee
index e17eaa75dc1..a3cc8dd844c 100644
--- a/app/assets/javascripts/blob/blob_license_selector.js.coffee
+++ b/app/assets/javascripts/blob/blob_license_selector.js.coffee
@@ -1,30 +1,9 @@
-class @BlobLicenseSelector
- licenseRegex: /^(.+\/)?(licen[sc]e|copying)($|\.)/i
+#= require blob/template_selector
- constructor: (editor) ->
- @$licenseSelector = $('.js-license-selector')
- $fileNameInput = $('#file_name')
+class @BlobLicenseSelector extends TemplateSelector
+ requestFile: (query) ->
+ data =
+ project: @dropdown.data('project')
+ fullname: @dropdown.data('fullname')
- initialFileNameValue = if $fileNameInput.length
- $fileNameInput.val()
- else if $('.editor-file-name').length
- $('.editor-file-name').text().trim()
-
- @toggleLicenseSelector(initialFileNameValue)
-
- if $fileNameInput
- $fileNameInput.on 'keyup blur', (e) =>
- @toggleLicenseSelector($(e.target).val())
-
- $('select.license-select').on 'change', (e) ->
- data =
- project: $(this).data('project')
- fullname: $(this).data('fullname')
- Api.licenseText $(this).val(), data, (license) ->
- editor.setValue(license.content, -1)
-
- toggleLicenseSelector: (fileName) =>
- if @licenseRegex.test(fileName)
- @$licenseSelector.show()
- else
- @$licenseSelector.hide()
+ Api.licenseText query.id, data, @requestFileSuccess.bind(@)
diff --git a/app/assets/javascripts/blob/blob_license_selectors.js.coffee b/app/assets/javascripts/blob/blob_license_selectors.js.coffee
new file mode 100644
index 00000000000..68438733108
--- /dev/null
+++ b/app/assets/javascripts/blob/blob_license_selectors.js.coffee
@@ -0,0 +1,17 @@
+class @BlobLicenseSelectors
+ constructor: (opts) ->
+ {
+ @$dropdowns = $('.js-license-selector')
+ @editor
+ } = opts
+
+ @$dropdowns.each (i, dropdown) =>
+ $dropdown = $(dropdown)
+
+ new BlobLicenseSelector(
+ pattern: /^(.+\/)?(licen[sc]e|copying)($|\.)/i,
+ data: $dropdown.data('data'),
+ wrapper: $dropdown.closest('.js-license-selector-wrap'),
+ dropdown: $dropdown,
+ editor: @editor
+ )
diff --git a/app/assets/javascripts/blob/edit_blob.js.coffee b/app/assets/javascripts/blob/edit_blob.js.coffee
index 79141e768b8..19e584519d7 100644
--- a/app/assets/javascripts/blob/edit_blob.js.coffee
+++ b/app/assets/javascripts/blob/edit_blob.js.coffee
@@ -12,8 +12,10 @@ class @EditBlob
$("#file-content").val(@editor.getValue())
@initModePanesAndLinks()
- new BlobLicenseSelector(@editor)
- new BlobGitignoreSelectors(editor: @editor)
+
+ new BlobLicenseSelectors { @editor }
+ new BlobGitignoreSelectors { @editor }
+ new BlobCiYamlSelectors { @editor }
initModePanesAndLinks: ->
@$editModePanes = $(".js-edit-mode-pane")
diff --git a/app/assets/javascripts/blob/template_selector.js.coffee b/app/assets/javascripts/blob/template_selector.js.coffee
new file mode 100644
index 00000000000..e76e303189d
--- /dev/null
+++ b/app/assets/javascripts/blob/template_selector.js.coffee
@@ -0,0 +1,56 @@
+class @TemplateSelector
+ constructor: (opts = {}) ->
+ {
+ @dropdown,
+ @data,
+ @pattern,
+ @wrapper,
+ @editor,
+ @fileEndpoint,
+ @$input = $('#file_name')
+ } = opts
+
+ @buildDropdown()
+ @bindEvents()
+ @onFilenameUpdate()
+
+ buildDropdown: ->
+ @dropdown.glDropdown(
+ data: @data,
+ filterable: true,
+ selectable: true,
+ search:
+ fields: ['name']
+ clicked: @onClick
+ text: (item) ->
+ item.name
+ )
+
+ bindEvents: ->
+ @$input.on('keyup blur', (e) =>
+ @onFilenameUpdate()
+ )
+
+ onFilenameUpdate: ->
+ return unless @$input.length
+
+ filenameMatches = @pattern.test(@$input.val().trim())
+
+ if not filenameMatches
+ @wrapper.addClass('hidden')
+ return
+
+ @wrapper.removeClass('hidden')
+
+ onClick: (item, el, e) =>
+ e.preventDefault()
+ @requestFile(item)
+
+ requestFile: (item) ->
+ # To be implemented on the extending class
+ # e.g.
+ # Api.gitignoreText item.name, @requestFileSuccess.bind(@)
+
+ requestFileSuccess: (file) ->
+ @editor.setValue(file.content, 1)
+ @editor.focus()
diff --git a/app/assets/javascripts/ci/build.coffee b/app/assets/javascripts/ci/build.coffee
index f763ba96e33..2d515d7efa2 100644
--- a/app/assets/javascripts/ci/build.coffee
+++ b/app/assets/javascripts/ci/build.coffee
@@ -17,6 +17,8 @@ class @CiBuild
.off 'resize.build'
.on 'resize.build', @hideSidebar
+ @updateArtifactRemoveDate()
+
if $('#build-trace').length
@getInitialBuildTrace()
@initScrollButtonAffix()
@@ -103,3 +105,10 @@ class @CiBuild
$('.js-build-sidebar')
.removeClass 'right-sidebar-collapsed'
.addClass 'right-sidebar-expanded'
+
+ updateArtifactRemoveDate: ->
+ $date = $('.js-artifacts-remove')
+
+ if $date.length
+ date = $date.text()
+ $date.text $.timefor(new Date(date), ' ')
diff --git a/app/assets/javascripts/dispatcher.js.coffee b/app/assets/javascripts/dispatcher.js.coffee
index a4a309810c5..5bb9647f6c2 100644
--- a/app/assets/javascripts/dispatcher.js.coffee
+++ b/app/assets/javascripts/dispatcher.js.coffee
@@ -29,6 +29,7 @@ class Dispatcher
new Todos()
when 'projects:milestones:new', 'projects:milestones:edit'
new ZenMode()
+ new DueDateSelect()
new GLForm($('.milestone-form'))
when 'groups:milestones:new'
new ZenMode()
@@ -53,9 +54,13 @@ class Dispatcher
new Diff()
shortcut_handler = new ShortcutsIssuable(true)
new ZenMode()
+ new MergedButtons()
+ when 'projects:merge_requests:commits', 'projects:merge_requests:builds'
+ new MergedButtons()
when "projects:merge_requests:diffs"
new Diff()
new ZenMode()
+ new MergedButtons()
when 'projects:merge_requests:index'
shortcut_handler = new ShortcutsNavigation()
Issuable.init()
@@ -68,9 +73,7 @@ class Dispatcher
new Diff()
new ZenMode()
shortcut_handler = new ShortcutsNavigation()
- when 'projects:commits:show'
- shortcut_handler = new ShortcutsNavigation()
- when 'projects:activity'
+ when 'projects:commits:show', 'projects:activity'
shortcut_handler = new ShortcutsNavigation()
when 'projects:show'
shortcut_handler = new ShortcutsNavigation()
@@ -98,6 +101,7 @@ class Dispatcher
when 'projects:blob:show', 'projects:blame:show'
new LineHighlighter()
shortcut_handler = new ShortcutsNavigation()
+ new ShortcutsBlob true
when 'projects:labels:new', 'projects:labels:edit'
new Labels()
when 'projects:labels:index'
@@ -133,14 +137,13 @@ class Dispatcher
new Project()
new ProjectAvatar()
switch path[1]
- when 'compare'
- shortcut_handler = new ShortcutsNavigation()
when 'edit'
shortcut_handler = new ShortcutsNavigation()
new ProjectNew()
when 'new'
new ProjectNew()
when 'show'
+ new ProjectNew()
new ProjectShow()
new NotificationsDropdown()
when 'wikis'
@@ -151,9 +154,9 @@ class Dispatcher
when 'snippets'
shortcut_handler = new ShortcutsNavigation()
new ZenMode() if path[2] == 'show'
- when 'labels', 'graphs'
- shortcut_handler = new ShortcutsNavigation()
- when 'project_members', 'deploy_keys', 'hooks', 'services', 'protected_branches'
+ when 'labels', 'graphs', 'compare', 'pipelines', 'forks', \
+ 'milestones', 'project_members', 'deploy_keys', 'builds', \
+ 'hooks', 'services', 'protected_branches'
shortcut_handler = new ShortcutsNavigation()
# If we haven't installed a custom shortcut handler, install the default one
diff --git a/app/assets/javascripts/due_date_select.js.coffee b/app/assets/javascripts/due_date_select.js.coffee
index 3d009a96d05..d65c018dad5 100644
--- a/app/assets/javascripts/due_date_select.js.coffee
+++ b/app/assets/javascripts/due_date_select.js.coffee
@@ -1,5 +1,21 @@
class @DueDateSelect
constructor: ->
+ # Milestone edit/new form
+ $datePicker = $('.datepicker')
+
+ if $datePicker.length
+ $dueDate = $('#milestone_due_date')
+ $datePicker.datepicker
+ dateFormat: 'yy-mm-dd'
+ onSelect: (dateText, inst) ->
+ $dueDate.val(dateText)
+ .datepicker('setDate', $.datepicker.parseDate('yy-mm-dd', $dueDate.val()))
+
+ $('.js-clear-due-date').on 'click', (e) ->
+ e.preventDefault()
+ $.datepicker._clearDate($datePicker)
+
+ # Issuable sidebar
$loading = $('.js-issuable-update .due_date')
.find('.block-loading')
.hide()
@@ -32,7 +48,7 @@ class @DueDateSelect
date = new Date value.replace(new RegExp('-', 'g'), ',')
mediumDate = $.datepicker.formatDate 'M d, yy', date
else
- mediumDate = 'None'
+ mediumDate = 'No due date'
data = {}
data[abilityName] = {}
@@ -50,7 +66,8 @@ class @DueDateSelect
$selectbox.hide()
$value.css('display', '')
- $valueContent.html(mediumDate)
+ cssClass = if Date.parse(mediumDate) then 'bold' else 'no-value'
+ $valueContent.html("<span class='#{cssClass}'>#{mediumDate}</span>")
$sidebarValue.html(mediumDate)
if value isnt ''
diff --git a/app/assets/javascripts/gfm_auto_complete.js.coffee b/app/assets/javascripts/gfm_auto_complete.js.coffee
index 76c3083232b..190bb38504c 100644
--- a/app/assets/javascripts/gfm_auto_complete.js.coffee
+++ b/app/assets/javascripts/gfm_auto_complete.js.coffee
@@ -15,6 +15,9 @@ GitLab.GfmAutoComplete =
Members:
template: '<li>${username} <small>${title}</small></li>'
+ Labels:
+ template: '<li><span class="dropdown-label-box" style="background: ${color}"></span> ${title}</li>'
+
# Issues and MergeRequests
Issues:
template: '<li><small>${id}</small> ${title}</li>'
@@ -176,6 +179,25 @@ GitLab.GfmAutoComplete =
title: sanitize(m.title)
search: "#{m.iid} #{m.title}"
+ @input.atwho
+ at: '~'
+ alias: 'labels'
+ searchKey: 'search'
+ displayTpl: @Labels.template
+ insertTpl: '${atwho-at}${title}'
+ callbacks:
+ beforeSave: (merges) ->
+ sanitizeLabelTitle = (title)->
+ if /\w+\s+\w+/g.test(title)
+ "\"#{sanitize(title)}\""
+ else
+ sanitize(title)
+
+ $.map merges, (m) ->
+ title: sanitizeLabelTitle(m.title)
+ color: m.color
+ search: "#{m.title}"
+
destroyAtWho: ->
@input.atwho('destroy')
@@ -195,6 +217,8 @@ GitLab.GfmAutoComplete =
@input.atwho 'load', 'mergerequests', data.mergerequests
# load emojis
@input.atwho 'load', ':', data.emojis
+ # load labels
+ @input.atwho 'load', '~', data.labels
# This trigger at.js again
# otherwise we would be stuck with loading until the user types
diff --git a/app/assets/javascripts/gl_dropdown.js.coffee b/app/assets/javascripts/gl_dropdown.js.coffee
index b49bd4565a7..2a7bf0bc306 100644
--- a/app/assets/javascripts/gl_dropdown.js.coffee
+++ b/app/assets/javascripts/gl_dropdown.js.coffee
@@ -58,7 +58,7 @@ class GitLabDropdownFilter
filter: (search_text) ->
data = @options.data()
- if data?
+ if data? and not @options.filterByText
results = data
if search_text isnt ''
@@ -102,10 +102,11 @@ class GitLabDropdownFilter
$el = $(@)
matches = fuzzaldrinPlus.match($el.text().trim(), search_text)
- if matches.length
- $el.show()
- else
- $el.hide()
+ unless $el.is('.dropdown-header')
+ if matches.length
+ $el.show()
+ else
+ $el.hide()
else
elements.show()
@@ -191,6 +192,7 @@ class GitLabDropdown
if @options.filterable
@filter = new GitLabDropdownFilter @filterInput,
filterInputBlur: @filterInputBlur
+ filterByText: @options.filterByText
remote: @options.filterRemote
query: @options.data
keys: searchFields
@@ -302,6 +304,9 @@ class GitLabDropdown
if @options.setIndeterminateIds
@options.setIndeterminateIds.call(@)
+ if @options.setActiveIds
+ @options.setActiveIds.call(@)
+
# Makes indeterminate items effective
if @fullData and @dropdown.find('.dropdown-menu-toggle').hasClass('js-filter-bulk-update')
@parseData @fullData
diff --git a/app/assets/javascripts/gl_form.js.coffee b/app/assets/javascripts/gl_form.js.coffee
index d540cc4dc46..77512d187c9 100644
--- a/app/assets/javascripts/gl_form.js.coffee
+++ b/app/assets/javascripts/gl_form.js.coffee
@@ -34,6 +34,8 @@ class @GLForm
# form and textarea event listeners
@addEventListeners()
+ gl.text.init(@form)
+
# hide discard button
@form.find('.js-note-discard').hide()
@@ -42,6 +44,7 @@ class @GLForm
clearEventListeners: ->
@textarea.off 'focus'
@textarea.off 'blur'
+ gl.text.removeListeners(@form)
addEventListeners: ->
@textarea.on 'focus', ->
diff --git a/app/assets/javascripts/graphs/stat_graph_contributors_graph.js.coffee b/app/assets/javascripts/graphs/stat_graph_contributors_graph.js.coffee
index 584d281a510..834a81af459 100644
--- a/app/assets/javascripts/graphs/stat_graph_contributors_graph.js.coffee
+++ b/app/assets/javascripts/graphs/stat_graph_contributors_graph.js.coffee
@@ -121,7 +121,11 @@ class @ContributorsMasterGraph extends ContributorsGraph
class @ContributorsAuthorGraph extends ContributorsGraph
constructor: (@data) ->
- @width = $('.content').width()/2 - 100
+ # Don't split graph size in half for mobile devices.
+ if $(window).width() < 768
+ @width = $('.content').width() - 80
+ else
+ @width = ($('.content').width() / 2) - 100
@height = 200
@x = null
@y = null
diff --git a/app/assets/javascripts/issuable.js.coffee b/app/assets/javascripts/issuable.js.coffee
index c2447120033..d0901be1509 100644
--- a/app/assets/javascripts/issuable.js.coffee
+++ b/app/assets/javascripts/issuable.js.coffee
@@ -56,13 +56,6 @@ issuable_created = false
Issuable.filterResults $('.filter-form')
$('.js-label-select').trigger('update.label')
- toggleLabelFilters: ->
- $filteredLabels = $('.filtered-labels')
- if $filteredLabels.find('.label-row').length > 0
- $filteredLabels.removeClass('hidden')
- else
- $filteredLabels.addClass('hidden')
-
filterResults: (form) =>
formData = form.serialize()
@@ -71,58 +64,16 @@ issuable_created = false
issuesUrl = formAction
issuesUrl += ("#{if formAction.indexOf('?') < 0 then '?' else '&'}")
issuesUrl += formData
- $.ajax
- type: 'GET'
- url: formAction
- data: formData
- complete: ->
- $('.issues-holder, .merge-requests-holder').css('opacity', '1.0')
- success: (data) ->
- $('.issues-holder, .merge-requests-holder').html(data.html)
- # Change url so if user reload a page - search results are saved
- history.replaceState {page: issuesUrl}, document.title, issuesUrl
- Issuable.reload()
- Issuable.updateStateFilters()
- $filteredLabels = $('.filtered-labels')
-
- if typeof Issuable.labelRow is 'function'
- $filteredLabels.html(Issuable.labelRow(data))
- Issuable.toggleLabelFilters()
-
- dataType: "json"
-
- reload: ->
- if Issuable.created
- Issuable.initChecks()
-
- $('#filter_issue_search').val($('#issue_search').val())
+ Turbolinks.visit(issuesUrl);
initChecks: ->
- $('.check_all_issues').on 'click', ->
+ $('.check_all_issues').off('click').on('click', ->
$('.selected_issue').prop('checked', @checked)
Issuable.checkChanged()
+ )
- $('.selected_issue').on 'change', Issuable.checkChanged
-
- updateStateFilters: ->
- stateFilters = $('.issues-state-filters, .dropdown-menu-sort')
- newParams = {}
- paramKeys = ['author_id', 'milestone_title', 'assignee_id', 'issue_search', 'issue_search']
-
- for paramKey in paramKeys
- newParams[paramKey] = gl.utils.getParameterValues(paramKey)[0] or ''
-
- if stateFilters.length
- stateFilters.find('a').each ->
- initialUrl = gl.utils.removeParamQueryString($(this).attr('href'), 'label_name[]')
- labelNameValues = gl.utils.getParameterValues('label_name[]')
- if labelNameValues
- labelNameQueryString = ("label_name[]=#{value}" for value in labelNameValues).join('&')
- newUrl = "#{gl.utils.mergeUrlParams(newParams, initialUrl)}&#{labelNameQueryString}"
- else
- newUrl = gl.utils.mergeUrlParams(newParams, initialUrl)
- $(this).attr 'href', newUrl
+ $('.selected_issue').off('change').on('change', Issuable.checkChanged)
checkChanged: ->
checked_issues = $('.selected_issue:checked')
diff --git a/app/assets/javascripts/issuable_form.js.coffee b/app/assets/javascripts/issuable_form.js.coffee
index 898506fde32..5b7a4831dfc 100644
--- a/app/assets/javascripts/issuable_form.js.coffee
+++ b/app/assets/javascripts/issuable_form.js.coffee
@@ -102,6 +102,10 @@ class @IssuableForm
return {
results: data
}
+ data: (query) ->
+ {
+ search: query
+ }
formatResult: (project) ->
project.name_with_namespace
formatSelection: (project) ->
diff --git a/app/assets/javascripts/issues-bulk-assignment.js.coffee b/app/assets/javascripts/issues-bulk-assignment.js.coffee
index 9dc3529a17f..b454f9389dd 100644
--- a/app/assets/javascripts/issues-bulk-assignment.js.coffee
+++ b/app/assets/javascripts/issues-bulk-assignment.js.coffee
@@ -9,6 +9,9 @@ class @IssuableBulkActions
@bindEvents()
+ # Fixes bulk-assign not working when navigating through pages
+ Issuable.initChecks();
+
getElement: (selector) ->
@container.find selector
diff --git a/app/assets/javascripts/labels_select.js.coffee b/app/assets/javascripts/labels_select.js.coffee
index 9ca88f1226e..6a10db10eb1 100644
--- a/app/assets/javascripts/labels_select.js.coffee
+++ b/app/assets/javascripts/labels_select.js.coffee
@@ -39,7 +39,7 @@ class @LabelsSelect
</a>
<% }); %>'
)
- labelNoneHTMLTemplate = _.template('<div class="light">None</div>')
+ labelNoneHTMLTemplate = '<span class="no-value">None</span>'
if newLabelField.length
@@ -145,7 +145,7 @@ class @LabelsSelect
template = labelHTMLTemplate(data)
labelCount = data.labels.length
else
- template = labelNoneHTMLTemplate()
+ template = labelNoneHTMLTemplate
$value
.removeAttr('style')
.html(template)
@@ -210,9 +210,21 @@ class @LabelsSelect
if $dropdown.hasClass('js-filter-bulk-update')
indeterminate = instance.indeterminateIds
+ active = instance.activeIds
+
if indeterminate.indexOf(label.id) isnt -1
selectedClass.push 'is-indeterminate'
+ if active.indexOf(label.id) isnt -1
+ # Remove is-indeterminate class if the item will be marked as active
+ i = selectedClass.indexOf 'is-indeterminate'
+ selectedClass.splice i, 1 unless i is -1
+
+ selectedClass.push 'is-active'
+
+ # Add input manually
+ instance.addInput @fieldName, label.id
+
if $form.find("input[type='hidden']\
[name='#{$dropdown.data('fieldName')}']\
[value='#{this.id(label)}']").length
@@ -328,6 +340,10 @@ class @LabelsSelect
setIndeterminateIds: ->
if @dropdown.find('.dropdown-menu-toggle').hasClass('js-filter-bulk-update')
@indeterminateIds = _this.getIndeterminateIds()
+
+ setActiveIds: ->
+ if @dropdown.find('.dropdown-menu-toggle').hasClass('js-filter-bulk-update')
+ @activeIds = _this.getActiveIds()
)
@bindEvents()
@@ -352,3 +368,12 @@ class @LabelsSelect
label_ids.push $("#issue_#{issue_id}").data('labels')
_.flatten(label_ids)
+
+ getActiveIds: ->
+ label_ids = []
+
+ $('.selected_issue:checked').each (i, el) ->
+ issue_id = $(el).data('id')
+ label_ids.push $("#issue_#{issue_id}").data('labels')
+
+ _.intersection.apply _, label_ids
diff --git a/app/assets/javascripts/layout_nav.js.coffee b/app/assets/javascripts/layout_nav.js.coffee
index 6adac6dac97..f8f0aea427e 100644
--- a/app/assets/javascripts/layout_nav.js.coffee
+++ b/app/assets/javascripts/layout_nav.js.coffee
@@ -1,14 +1,25 @@
-class @LayoutNav
- $ ->
- $('.fade-left').addClass('end-scroll')
- $('.scrolling-tabs').on 'scroll', (event) ->
- $this = $(this)
- $el = $(event.target)
- currentPosition = $this.scrollLeft()
- size = bp.getBreakpointSize()
- controlBtnWidth = $('.controls').width()
- maxPosition = $this.get(0).scrollWidth - $this.parent().width()
- maxPosition += controlBtnWidth if size isnt 'xs' and $('.nav-control').length
-
- $el.find('.fade-left').toggleClass('end-scroll', currentPosition is 0)
- $el.find('.fade-right').toggleClass('end-scroll', currentPosition is maxPosition)
+hideEndFade = ($scrollingTabs) ->
+ $scrollingTabs.each ->
+ $this = $(@)
+
+ $this
+ .find('.fade-right')
+ .toggleClass('end-scroll', $this.width() is $this.prop('scrollWidth'))
+
+$ ->
+ $('.fade-left').addClass('end-scroll')
+
+ hideEndFade($('.scrolling-tabs'))
+
+ $(window)
+ .off 'resize.nav'
+ .on 'resize.nav', ->
+ hideEndFade($('.scrolling-tabs'))
+
+ $('.scrolling-tabs').on 'scroll', (event) ->
+ $this = $(this)
+ currentPosition = $this.scrollLeft()
+ maxPosition = $this.prop('scrollWidth') - $this.outerWidth()
+
+ $this.find('.fade-left').toggleClass('end-scroll', currentPosition is 0)
+ $this.find('.fade-right').toggleClass('end-scroll', currentPosition is maxPosition)
diff --git a/app/assets/javascripts/lib/common_utils.js.coffee b/app/assets/javascripts/lib/common_utils.js.coffee
index 0000e99a650..e39dcb2daa9 100644
--- a/app/assets/javascripts/lib/common_utils.js.coffee
+++ b/app/assets/javascripts/lib/common_utils.js.coffee
@@ -1,5 +1,46 @@
((w) ->
+ w.gl or= {}
+ w.gl.utils or= {}
+
+ w.gl.utils.isInGroupsPage = ->
+
+ return $('body').data('page').split(':')[0] is 'groups'
+
+
+ w.gl.utils.isInProjectPage = ->
+
+ return $('body').data('page').split(':')[0] is 'projects'
+
+
+ w.gl.utils.getProjectSlug = ->
+
+ return if @isInProjectPage() then $('body').data 'project' else null
+
+
+ w.gl.utils.getGroupSlug = ->
+
+ return if @isInGroupsPage() then $('body').data 'group' else null
+
+
+
+ gl.utils.updateTooltipTitle = ($tooltipEl, newTitle) ->
+
+ $tooltipEl
+ .tooltip 'destroy'
+ .attr 'title', newTitle
+ .tooltip 'fixTitle'
+
+
+ gl.utils.preventDisabledButtons = ->
+
+ $('.btn').click (e) ->
+ if $(this).hasClass 'disabled'
+ e.preventDefault()
+ e.stopImmediatePropagation()
+ return false
+
+
jQuery.timefor = (time, suffix, expiredLabel) ->
return '' unless time
diff --git a/app/assets/javascripts/lib/text_utility.js.coffee b/app/assets/javascripts/lib/text_utility.js.coffee
new file mode 100644
index 00000000000..bb2772dfed2
--- /dev/null
+++ b/app/assets/javascripts/lib/text_utility.js.coffee
@@ -0,0 +1,79 @@
+((w) ->
+ w.gl ?= {}
+ w.gl.text ?= {}
+
+ gl.text.randomString = -> Math.random().toString(36).substring(7)
+
+ gl.text.replaceRange = (s, start, end, substitute) ->
+ s.substring(0, start) + substitute + s.substring(end);
+
+ gl.text.selectedText = (text, textarea) ->
+ text.substring(textarea.selectionStart, textarea.selectionEnd)
+
+ gl.text.insertText = (textArea, text, tag, selected, wrap) ->
+ selectedSplit = selected.split('\n')
+ startChar = if not wrap and textArea.selectionStart > 0 then '\n' else ''
+
+ if selectedSplit.length > 1 and not wrap
+ insertText = selectedSplit.map((val) ->
+ if val.indexOf(tag) is 0
+ "#{val.replace(tag, '')}"
+ else
+ "#{tag}#{val}"
+ ).join('\n')
+ else
+ insertText = "#{startChar}#{tag}#{selected}#{if wrap then tag else ' '}"
+
+ if document.queryCommandSupported('insertText')
+ document.execCommand 'insertText', false, insertText
+ else
+ try
+ document.execCommand("ms-beginUndoUnit")
+
+ textArea.value = @replaceRange(
+ text,
+ textArea.selectionStart,
+ textArea.selectionEnd,
+ insertText)
+ try
+ document.execCommand("ms-endUndoUnit")
+
+ @moveCursor(textArea, tag, wrap)
+
+ gl.text.moveCursor = (textArea, tag, wrapped) ->
+ return unless textArea.setSelectionRange
+
+ if textArea.selectionStart is textArea.selectionEnd
+ if wrapped
+ pos = textArea.selectionStart - tag.length
+ else
+ pos = textArea.selectionStart
+
+ textArea.setSelectionRange pos, pos
+
+ gl.text.updateText = (textArea, tag, wrap) ->
+ $textArea = $(textArea)
+ oldVal = $textArea.val()
+ textArea = $textArea.get(0)
+ text = $textArea.val()
+ selected = @selectedText(text, textArea)
+ $textArea.focus()
+
+ @insertText(textArea, text, tag, selected, wrap)
+
+ gl.text.init = (form) ->
+ self = @
+ $('.js-md', form)
+ .off 'click'
+ .on 'click', ->
+ $this = $(@)
+ self.updateText(
+ $this.closest('.md-area').find('textarea'),
+ $this.data('md-tag'),
+ not $this.data('md-prepend')
+ )
+
+ gl.text.removeListeners = (form) ->
+ $('.js-md', form).off()
+
+) window
diff --git a/app/assets/javascripts/logo.js.coffee b/app/assets/javascripts/logo.js.coffee
index 9fdc27a9787..dc2590a0355 100644
--- a/app/assets/javascripts/logo.js.coffee
+++ b/app/assets/javascripts/logo.js.coffee
@@ -42,9 +42,3 @@ work = ->
$(document).on('page:fetch', start)
$(document).on('page:change', stop)
-
-$ ->
- # Make logo clickable as part of a workaround for Safari visited
- # link behaviour (See !2690).
- $('#logo').on 'click', ->
- Turbolinks.visit('/')
diff --git a/app/assets/javascripts/merge_request.js.coffee b/app/assets/javascripts/merge_request.js.coffee
index 1f46e331427..dabfd91cf14 100644
--- a/app/assets/javascripts/merge_request.js.coffee
+++ b/app/assets/javascripts/merge_request.js.coffee
@@ -9,7 +9,7 @@ class @MergeRequest
# Options:
# action - String, current controller action
#
- constructor: (@opts) ->
+ constructor: (@opts = {}) ->
this.$el = $('.merge-request')
this.$('.show-all-commits').on 'click', =>
diff --git a/app/assets/javascripts/merge_request_tabs.js.coffee b/app/assets/javascripts/merge_request_tabs.js.coffee
index 49a4727205a..894f80586f1 100644
--- a/app/assets/javascripts/merge_request_tabs.js.coffee
+++ b/app/assets/javascripts/merge_request_tabs.js.coffee
@@ -88,7 +88,7 @@ class @MergeRequestTabs
scrollToElement: (container) ->
if window.location.hash
- navBarHeight = $('.navbar-gitlab').outerHeight()
+ navBarHeight = $('.navbar-gitlab').outerHeight() + $('.layout-nav').outerHeight()
$el = $("#{container} #{window.location.hash}:not(.match)")
$.scrollTo("#{container} #{window.location.hash}:not(.match)", offset: -navBarHeight) if $el.length
diff --git a/app/assets/javascripts/merged_buttons.js.coffee b/app/assets/javascripts/merged_buttons.js.coffee
new file mode 100644
index 00000000000..4929295c10b
--- /dev/null
+++ b/app/assets/javascripts/merged_buttons.js.coffee
@@ -0,0 +1,30 @@
+class @MergedButtons
+ constructor: ->
+ @$removeBranchWidget = $('.remove_source_branch_widget')
+ @$removeBranchProgress = $('.remove_source_branch_in_progress')
+ @$removeBranchFailed = $('.remove_source_branch_widget.failed')
+
+ @cleanEventListeners()
+ @initEventListeners()
+
+ cleanEventListeners: ->
+ $(document).off 'click', '.remove_source_branch'
+ $(document).off 'ajax:success', '.remove_source_branch'
+ $(document).off 'ajax:error', '.remove_source_branch'
+
+ initEventListeners: ->
+ $(document).on 'click', '.remove_source_branch', @removeSourceBranch
+ $(document).on 'ajax:success', '.remove_source_branch', @removeBranchSuccess
+ $(document).on 'ajax:error', '.remove_source_branch', @removeBranchError
+
+ removeSourceBranch: =>
+ @$removeBranchWidget.hide()
+ @$removeBranchProgress.show()
+
+ removeBranchSuccess: ->
+ location.reload()
+
+ removeBranchError: ->
+ @$removeBranchWidget.hide()
+ @$removeBranchProgress.hide()
+ @$removeBranchFailed.show()
diff --git a/app/assets/javascripts/milestone_select.js.coffee b/app/assets/javascripts/milestone_select.js.coffee
index 648e1f3bde0..02480f3a025 100644
--- a/app/assets/javascripts/milestone_select.js.coffee
+++ b/app/assets/javascripts/milestone_select.js.coffee
@@ -24,14 +24,10 @@ class @MilestoneSelect
if issueUpdateURL
milestoneLinkTemplate = _.template(
- '<a href="/<%= namespace %>/<%= path %>/milestones/<%= iid %>">
- <span class="has-tooltip" data-container="body" title="<%= remaining %>">
- <%= _.escape(title) %>
- </span>
- </a>'
+ '<a href="/<%= namespace %>/<%= path %>/milestones/<%= iid %>" class="bold has-tooltip" data-container="body" title="<%= remaining %>"><%= _.escape(title) %></a>'
)
- milestoneLinkNoneTemplate = '<div class="light">None</div>'
+ milestoneLinkNoneTemplate = '<span class="no-value">None</span>'
collapsedSidebarLabelTemplate = _.template(
'<span class="has-tooltip" data-container="body" title="<%= remaining %>" data-placement="left">
@@ -116,7 +112,7 @@ class @MilestoneSelect
.val()
data = {}
data[abilityName] = {}
- data[abilityName].milestone_id = selected
+ data[abilityName].milestone_id = if selected? then selected else null
$loading
.fadeIn()
$dropdown.trigger('loading.gl.dropdown')
diff --git a/app/assets/javascripts/network/application.js.coffee b/app/assets/javascripts/network/application.js.coffee
new file mode 100644
index 00000000000..cb9eead855b
--- /dev/null
+++ b/app/assets/javascripts/network/application.js.coffee
@@ -0,0 +1,20 @@
+# This is a manifest file that'll be compiled into including all the files listed below.
+# Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
+# be included in the compiled file accessible from http://example.com/assets/application.js
+# It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
+# the compiled file.
+#
+#= require raphael
+#= require g.raphael
+#= require g.bar
+#= require_tree .
+
+$ ->
+ network_graph = new Network({
+ url: $(".network-graph").attr('data-url'),
+ commit_url: $(".network-graph").attr('data-commit-url'),
+ ref: $(".network-graph").attr('data-ref'),
+ commit_id: $(".network-graph").attr('data-commit-id')
+ })
+
+ new ShortcutsNetwork(network_graph.branch_graph)
diff --git a/app/assets/javascripts/branch-graph.js.coffee b/app/assets/javascripts/network/branch-graph.js.coffee
index f2fd2a775a4..f2fd2a775a4 100644
--- a/app/assets/javascripts/branch-graph.js.coffee
+++ b/app/assets/javascripts/network/branch-graph.js.coffee
diff --git a/app/assets/javascripts/network.js.coffee b/app/assets/javascripts/network/network.js.coffee
index f4ef07a50a7..f4ef07a50a7 100644
--- a/app/assets/javascripts/network.js.coffee
+++ b/app/assets/javascripts/network/network.js.coffee
diff --git a/app/assets/javascripts/notes.js.coffee b/app/assets/javascripts/notes.js.coffee
index ad216910c8d..17f7e180127 100644
--- a/app/assets/javascripts/notes.js.coffee
+++ b/app/assets/javascripts/notes.js.coffee
@@ -102,12 +102,15 @@ class @Notes
keydownNoteText: (e) ->
$this = $(this)
- if $this.val() is '' and e.which is 38 #aka the up key
+ if $this.val() is '' and e.which is 38 and not isMetaKey e
myLastNote = $("li.note[data-author-id='#{gon.current_user_id}'][data-editable]:last")
if myLastNote.length
myLastNoteEditBtn = myLastNote.find('.js-note-edit')
myLastNoteEditBtn.trigger('click', [true, myLastNote])
+ isMetaKey = (e) ->
+ (e.metaKey or e.ctrlKey or e.altKey or e.shiftKey)
+
initRefresh: ->
clearInterval(Notes.interval)
Notes.interval = setInterval =>
@@ -115,12 +118,14 @@ class @Notes
, @pollingInterval
refresh: =>
- return if @refreshing is true
- @refreshing = true
if not document.hidden and document.URL.indexOf(@noteable_url) is 0
@getContent()
getContent: ->
+ return if @refreshing
+
+ @refreshing = true
+
$.ajax
url: @notes_url
data: "last_fetched_at=" + @last_fetched_at
diff --git a/app/assets/javascripts/notifications_dropdown.js.coffee b/app/assets/javascripts/notifications_dropdown.js.coffee
index 15daf027c0a..0bbd082c156 100644
--- a/app/assets/javascripts/notifications_dropdown.js.coffee
+++ b/app/assets/javascripts/notifications_dropdown.js.coffee
@@ -1,21 +1,25 @@
class @NotificationsDropdown
- $ ->
+ constructor: ->
$(document)
.off 'click', '.update-notification'
.on 'click', '.update-notification', (e) ->
e.preventDefault()
+
+ return if $(this).is('.is-active') and $(this).data('notification-level') is 'custom'
+
notificationLevel = $(@).data 'notification-level'
label = $(@).data 'notification-title'
- form = $(this).parents('form:first')
+ form = $(this).parents('.notification-form:first')
form.find('.js-notification-loading').toggleClass 'fa-bell fa-spin fa-spinner'
form.find('#notification_setting_level').val(notificationLevel)
- form.submit();
+ form.submit()
$(document)
- .off 'ajax:success', '#notification-form'
- .on 'ajax:success', '#notification-form', (e, data) ->
+ .off 'ajax:success', '.notification-form'
+ .on 'ajax:success', '.notification-form', (e, data) ->
if data.saved
- new Flash('Notification settings saved', 'notice')
- $(e.currentTarget).closest('.notification-dropdown').replaceWith(data.html)
+ $(e.currentTarget)
+ .closest('.notification-dropdown')
+ .replaceWith(data.html)
else
new Flash('Failed to save new settings', 'alert')
diff --git a/app/assets/javascripts/notifications_form.js.coffee b/app/assets/javascripts/notifications_form.js.coffee
index 51faa5fcace..3432428702a 100644
--- a/app/assets/javascripts/notifications_form.js.coffee
+++ b/app/assets/javascripts/notifications_form.js.coffee
@@ -12,7 +12,6 @@ class @NotificationsForm
toggleCheckbox: (e) =>
$checkbox = $(e.currentTarget)
$parent = $checkbox.closest('.checkbox')
- console.log($parent)
@saveEvent($checkbox, $parent)
showCheckboxLoadingSpinner: ($parent) ->
@@ -25,13 +24,13 @@ class @NotificationsForm
saveEvent: ($checkbox, $parent) ->
form = $parent.parents('form:first')
- console.log(form)
$.ajax(
url: form.attr('action')
method: form.attr('method')
dataType: 'json'
data: form.serialize()
+
beforeSend: =>
@showCheckboxLoadingSpinner($parent)
).done (data) ->
diff --git a/app/assets/javascripts/project.js.coffee b/app/assets/javascripts/project.js.coffee
index d12bad97a05..96e10dd7e8a 100644
--- a/app/assets/javascripts/project.js.coffee
+++ b/app/assets/javascripts/project.js.coffee
@@ -19,6 +19,7 @@ class @Project
$('.clone').text(url)
# Ref switcher
+ @initRefSwitcher()
$('.project-refs-select').on 'change', ->
$(@).parents('form').submit()
@@ -34,7 +35,6 @@ class @Project
$(@).parents('.no-password-message').remove()
e.preventDefault()
-
@projectSelectDropdown()
projectSelectDropdown: ->
@@ -50,3 +50,39 @@ class @Project
changeProject: (url) ->
window.location = url
+
+ initRefSwitcher: ->
+ $('.js-project-refs-dropdown').each ->
+ $dropdown = $(@)
+ selected = $dropdown.data('selected')
+
+ $dropdown.glDropdown(
+ data: (term, callback) ->
+ $.ajax(
+ url: $dropdown.data('refs-url')
+ data:
+ ref: $dropdown.data('ref')
+ ).done (refs) ->
+ callback(refs)
+ selectable: true
+ filterable: true
+ filterByText: true
+ fieldName: 'ref'
+ renderRow: (ref) ->
+ if ref.header?
+ "<li class='dropdown-header'>#{ref.header}</li>"
+ else
+ isActiveClass = if ref is selected then 'is-active' else ''
+
+ "<li>
+ <a href='#' data-ref='#{escape(ref)}' class='#{isActiveClass}'>
+ #{ref}
+ </a>
+ </li>"
+ id: (obj, $el) ->
+ $el.data('ref')
+ toggleLabel: (obj, $el) ->
+ $el.text().trim()
+ clicked: (e) ->
+ $dropdown.closest('form').submit()
+ )
diff --git a/app/assets/javascripts/right_sidebar.js.coffee b/app/assets/javascripts/right_sidebar.js.coffee
index c9cb0f4bb32..12340bbce54 100644
--- a/app/assets/javascripts/right_sidebar.js.coffee
+++ b/app/assets/javascripts/right_sidebar.js.coffee
@@ -43,6 +43,59 @@ class @Sidebar
$('.right-sidebar')
.hasClass('right-sidebar-collapsed'), { path: '/' })
+ $(document)
+ .off 'click', '.js-issuable-todo'
+ .on 'click', '.js-issuable-todo', @toggleTodo
+
+ toggleTodo: (e) =>
+ $this = $(e.currentTarget)
+ $todoLoading = $('.js-issuable-todo-loading')
+ $btnText = $('.js-issuable-todo-text', $this)
+ ajaxType = if $this.attr('data-delete-path') then 'DELETE' else 'POST'
+
+ if $this.attr('data-delete-path')
+ url = "#{$this.attr('data-delete-path')}"
+ else
+ url = "#{$this.data('url')}"
+
+ $.ajax(
+ url: url
+ type: ajaxType
+ dataType: 'json'
+ data:
+ issuable_id: $this.data('issuable-id')
+ issuable_type: $this.data('issuable-type')
+ beforeSend: =>
+ @beforeTodoSend($this, $todoLoading)
+ ).done (data) =>
+ @todoUpdateDone(data, $this, $btnText, $todoLoading)
+
+ beforeTodoSend: ($btn, $todoLoading) ->
+ $btn.disable()
+ $todoLoading.removeClass 'hidden'
+
+ todoUpdateDone: (data, $btn, $btnText, $todoLoading) ->
+ $todoPendingCount = $('.todos-pending-count')
+ $todoPendingCount.text data.count
+
+ $btn.enable()
+ $todoLoading.addClass 'hidden'
+
+ if data.count is 0
+ $todoPendingCount.addClass 'hidden'
+ else
+ $todoPendingCount.removeClass 'hidden'
+
+ if data.delete_path?
+ $btn
+ .attr 'aria-label', $btn.data('mark-text')
+ .attr 'data-delete-path', data.delete_path
+ $btnText.text $btn.data('mark-text')
+ else
+ $btn
+ .attr 'aria-label', $btn.data('todo-text')
+ .removeAttr 'data-delete-path'
+ $btnText.text $btn.data('todo-text')
sidebarDropdownLoading: (e) ->
$sidebarCollapsedIcon = $(@).closest('.block').find('.sidebar-collapsed-icon')
@@ -117,5 +170,3 @@ class @Sidebar
getBlock: (name) ->
@sidebar.find(".block.#{name}")
-
-
diff --git a/app/assets/javascripts/search_autocomplete.js.coffee b/app/assets/javascripts/search_autocomplete.js.coffee
index 5eb915a51ea..421328554b8 100644
--- a/app/assets/javascripts/search_autocomplete.js.coffee
+++ b/app/assets/javascripts/search_autocomplete.js.coffee
@@ -67,8 +67,12 @@ class @SearchAutocomplete
getData: (term, callback) ->
_this = @
- # Do not trigger request if input is empty
- return if @searchInput.val() is ''
+ unless term
+ if contents = @getCategoryContents()
+ @searchInput.data('glDropdown').filter.options.callback contents
+ @enableAutocomplete()
+
+ return
# Prevent multiple ajax calls
return if @loadingSuggestions
@@ -122,6 +126,37 @@ class @SearchAutocomplete
).always ->
_this.loadingSuggestions = false
+
+ getCategoryContents: ->
+
+ userId = gon.current_user_id
+ { utils, projectOptions, groupOptions, dashboardOptions } = gl
+
+ if utils.isInGroupsPage() and groupOptions
+ options = groupOptions[utils.getGroupSlug()]
+
+ else if utils.isInProjectPage() and projectOptions
+ options = projectOptions[utils.getProjectSlug()]
+
+ else if dashboardOptions
+ options = dashboardOptions
+
+ { issuesPath, mrPath, name } = options
+
+ items = [
+ { header: "#{name}" }
+ { text: 'Issues assigned to me', url: "#{issuesPath}/?assignee_id=#{userId}" }
+ { text: "Issues I've created", url: "#{issuesPath}/?author_id=#{userId}" }
+ 'separator'
+ { text: 'Merge requests assigned to me', url: "#{mrPath}/?assignee_id=#{userId}" }
+ { text: "Merge requests I've created", url: "#{mrPath}/?author_id=#{userId}" }
+ ]
+
+ items.splice 0, 1 unless name
+
+ return items
+
+
serializeState: ->
{
# Search Criteria
@@ -209,6 +244,12 @@ class @SearchAutocomplete
@isFocused = true
@wrap.addClass('search-active')
+ @getData() if @getValue() is ''
+
+
+ getValue: -> return @searchInput.val()
+
+
onClearInputClick: (e) =>
e.preventDefault()
@searchInput.val('').focus()
@@ -229,6 +270,10 @@ class @SearchAutocomplete
@locationBadgeEl.text(badgeText).show()
@wrap.addClass('has-location-badge')
+
+ hasLocationBadge: -> return @wrap.is '.has-location-badge'
+
+
restoreOriginalState: ->
inputs = Object.keys @originalState
@@ -257,13 +302,14 @@ class @SearchAutocomplete
@getElement("##{input}").val('')
+
removeLocationBadge: ->
- @locationBadgeEl.hide()
- # Reset state
+ @locationBadgeEl.hide()
@resetSearchState()
-
@wrap.removeClass('has-location-badge')
+ @disableAutocomplete()
+
disableAutocomplete: ->
@searchInput.addClass('disabled')
diff --git a/app/assets/javascripts/shortcuts.js.coffee b/app/assets/javascripts/shortcuts.js.coffee
index f3d66004138..c03877e9b06 100644
--- a/app/assets/javascripts/shortcuts.js.coffee
+++ b/app/assets/javascripts/shortcuts.js.coffee
@@ -1,7 +1,7 @@
class @Shortcuts
- constructor: ->
+ constructor: (skipResetBindings) ->
@enabledHelp = []
- Mousetrap.reset()
+ Mousetrap.reset() if not skipResetBindings
Mousetrap.bind('?', @onToggleHelp)
Mousetrap.bind('s', Shortcuts.focusSearch)
Mousetrap.bind(['ctrl+shift+p', 'command+shift+p'], @toggleMarkdownPreview)
diff --git a/app/assets/javascripts/shortcuts_blob.coffee b/app/assets/javascripts/shortcuts_blob.coffee
new file mode 100644
index 00000000000..6d21e5d1150
--- /dev/null
+++ b/app/assets/javascripts/shortcuts_blob.coffee
@@ -0,0 +1,10 @@
+#= require shortcuts
+
+class @ShortcutsBlob extends Shortcuts
+ constructor: (skipResetBindings) ->
+ super skipResetBindings
+ Mousetrap.bind('y', ShortcutsBlob.copyToClipboard)
+
+ @copyToClipboard: ->
+ clipboardButton = $('.btn-clipboard')
+ clipboardButton.click() if clipboardButton
diff --git a/app/assets/javascripts/sidebar.js.coffee b/app/assets/javascripts/sidebar.js.coffee
index 2ce63c16428..68009e58645 100644
--- a/app/assets/javascripts/sidebar.js.coffee
+++ b/app/assets/javascripts/sidebar.js.coffee
@@ -3,13 +3,33 @@ expanded = 'page-sidebar-expanded'
toggleSidebar = ->
$('.page-with-sidebar').toggleClass("#{collapsed} #{expanded}")
- $('header').toggleClass("header-collapsed header-expanded")
+ $('.navbar-fixed-top').toggleClass("header-collapsed header-expanded")
+
+ if $.cookie('pin_nav') is 'true'
+ $('.navbar-fixed-top').toggleClass('header-pinned-nav')
+ $('.page-with-sidebar').toggleClass('page-sidebar-pinned')
setTimeout ( ->
- niceScrollBars = $('.nicescroll').niceScroll();
+ niceScrollBars = $('.nav-sidebar').niceScroll();
niceScrollBars.updateScrollBar();
), 300
+$(document)
+ .off 'click', 'body'
+ .on 'click', 'body', (e) ->
+ unless $.cookie('pin_nav') is 'true'
+ $target = $(e.target)
+ $nav = $target.closest('.sidebar-wrapper')
+ pageExpanded = $('.page-with-sidebar').hasClass('page-sidebar-expanded')
+ $toggle = $target.closest('.toggle-nav-collapse, .side-nav-toggle')
+
+ if $nav.length is 0 and pageExpanded and $toggle.length is 0
+ $('.page-with-sidebar')
+ .toggleClass('page-sidebar-collapsed page-sidebar-expanded')
+
+ $('.navbar-fixed-top')
+ .toggleClass('header-collapsed header-expanded')
+
$(document).on("click", '.toggle-nav-collapse, .side-nav-toggle', (e) ->
e.preventDefault()
diff --git a/app/assets/javascripts/star.js.coffee b/app/assets/javascripts/star.js.coffee
index f27780dda93..01b28171f72 100644
--- a/app/assets/javascripts/star.js.coffee
+++ b/app/assets/javascripts/star.js.coffee
@@ -9,9 +9,11 @@ class @Star
$this.parent().find('.star-count').text data.star_count
if isStarred
$starSpan.removeClass('starred').text 'Star'
+ gl.utils.updateTooltipTitle $this, 'Star project'
$starIcon.removeClass('fa-star').addClass 'fa-star-o'
else
$starSpan.addClass('starred').text 'Unstar'
+ gl.utils.updateTooltipTitle $this, 'Unstar project'
$starIcon.removeClass('fa-star-o').addClass 'fa-star'
return
diff --git a/app/assets/javascripts/users/calendar.js.coffee b/app/assets/javascripts/users/calendar.js.coffee
index 26a26061539..c081f023b04 100644
--- a/app/assets/javascripts/users/calendar.js.coffee
+++ b/app/assets/javascripts/users/calendar.js.coffee
@@ -6,12 +6,6 @@ class @Calendar
@daySizeWithSpace = @daySize + (@daySpace * 2)
@monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
@months = []
- @highestValue = 0
-
- # Get the highest value from the timestampes
- _.each timestamps, (count) =>
- if count > @highestValue
- @highestValue = count
# Loop through the timestamps to create a group of objects
# The group of objects will be grouped based on the day of the week they are
@@ -39,8 +33,8 @@ class @Calendar
i++
# Init color functions
- @color = @initColor()
@colorKey = @initColorKey()
+ @color = @initColor()
# Init the svg element
@renderSvg(group)
@@ -104,7 +98,7 @@ class @Calendar
.attr 'class', 'user-contrib-cell js-tooltip'
.attr 'fill', (stamp) =>
if stamp.count isnt 0
- @color(stamp.count)
+ @color(Math.min(stamp.count, 40))
else
'#ededed'
.attr 'data-container', 'body'
@@ -164,10 +158,11 @@ class @Calendar
color
initColor: ->
+ colorRange = ['#ededed', @colorKey(0), @colorKey(1), @colorKey(2), @colorKey(3)]
d3.scale
- .linear()
- .range(['#acd5f2', '#254e77'])
- .domain([0, @highestValue])
+ .threshold()
+ .domain([0, 10, 20, 30])
+ .range(colorRange)
initColorKey: ->
d3.scale
diff --git a/app/assets/javascripts/users_select.js.coffee b/app/assets/javascripts/users_select.js.coffee
index 88246b0feb8..2548efb2186 100644
--- a/app/assets/javascripts/users_select.js.coffee
+++ b/app/assets/javascripts/users_select.js.coffee
@@ -31,7 +31,7 @@ class @UsersSelect
assignTo = (selected) ->
data = {}
data[abilityName] = {}
- data[abilityName].assignee_id = selected
+ data[abilityName].assignee_id = if selected? then selected else null
$loading
.fadeIn()
$dropdown.trigger('loading.gl.dropdown')
@@ -72,7 +72,7 @@ class @UsersSelect
assigneeTemplate = _.template(
'<% if (username) { %>
- <a class="author_link " href="/u/<%= username %>">
+ <a class="author_link bold" href="/u/<%= username %>">
<% if( avatar ) { %>
<img width="32" class="avatar avatar-inline s32" alt="" src="<%= avatar %>">
<% } %>
@@ -82,7 +82,7 @@ class @UsersSelect
</span>
</a>
<% } else { %>
- <span class="assign-yourself">
+ <span class="no-value assign-yourself">
No assignee -
<a href="#" class="js-assign-yourself">
assign yourself
diff --git a/app/assets/stylesheets/framework.scss b/app/assets/stylesheets/framework.scss
index 3cbddc59f11..a306b8f3f29 100644
--- a/app/assets/stylesheets/framework.scss
+++ b/app/assets/stylesheets/framework.scss
@@ -37,3 +37,4 @@
@import "framework/timeline.scss";
@import "framework/typography.scss";
@import "framework/zen.scss";
+@import "framework/blank";
diff --git a/app/assets/stylesheets/framework/blank.scss b/app/assets/stylesheets/framework/blank.scss
new file mode 100644
index 00000000000..40b5171a8c6
--- /dev/null
+++ b/app/assets/stylesheets/framework/blank.scss
@@ -0,0 +1,23 @@
+.blank-state {
+ padding-top: 20px;
+ padding-bottom: 20px;
+ text-align: center;
+}
+
+.blank-state-no-icon {
+ padding-top: 40px;
+ padding-bottom: 40px;
+}
+
+.blank-state-title {
+ margin-top: 0;
+ margin-bottom: 5px;
+ font-size: 19px;
+ font-weight: normal;
+}
+
+.blank-state-text {
+ margin-top: 0;
+ margin-bottom: $gl-padding;
+ font-size: 15px;
+}
diff --git a/app/assets/stylesheets/framework/blocks.scss b/app/assets/stylesheets/framework/blocks.scss
index fab96404a6c..38023818709 100644
--- a/app/assets/stylesheets/framework/blocks.scss
+++ b/app/assets/stylesheets/framework/blocks.scss
@@ -91,6 +91,26 @@
background-color: $white-light;
border-top: none;
}
+
+ &.top-block .container-fluid {
+ background-color: inherit;
+ }
+}
+
+.sub-header-block {
+ background-color: $white-light;
+ border-bottom: 1px solid $white-dark;
+ padding: 11px 0;
+ margin-bottom: 11px;
+
+ .oneline {
+ line-height: 35px;
+ }
+
+ &.no-bottom-space {
+ border-bottom: 0;
+ margin-bottom: 0;
+ }
}
.cover-block {
diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss
index d4d579a083d..00111dfa706 100644
--- a/app/assets/stylesheets/framework/dropdowns.scss
+++ b/app/assets/stylesheets/framework/dropdowns.scss
@@ -461,10 +461,12 @@
}
}
- .ui-state-active,
- .ui-state-hover {
- color: $md-link-color;
- background-color: $calendar-hover-bg;
+ .ui-datepicker-calendar {
+ .ui-state-hover,
+ .ui-state-active {
+ color: #fff;
+ border: 0;
+ }
}
.ui-datepicker-prev,
diff --git a/app/assets/stylesheets/framework/gitlab-theme.scss b/app/assets/stylesheets/framework/gitlab-theme.scss
index 408d4a68e1e..0a8603b6702 100644
--- a/app/assets/stylesheets/framework/gitlab-theme.scss
+++ b/app/assets/stylesheets/framework/gitlab-theme.scss
@@ -8,8 +8,8 @@
*/
@mixin gitlab-theme($color-light, $color, $color-darker, $color-dark) {
.page-with-sidebar {
-
- .collapse-nav a {
+ .toggle-nav-collapse,
+ .pin-nav-btn {
color: $color-light;
background: $color;
diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss
index 63996ea44f6..a7bcb456560 100644
--- a/app/assets/stylesheets/framework/header.scss
+++ b/app/assets/stylesheets/framework/header.scss
@@ -2,8 +2,19 @@
* Application Header
*
*/
+@mixin tanuki-logo-colors($path-color) {
+ fill: $path-color;
+ transition: all 0.8s;
+
+ &:hover,
+ &.highlight {
+ fill: lighten($path-color, 25%);
+ transition: all 0.1s;
+ }
+}
+
header {
- transition-duration: .3s;
+ transition: padding $sidebar-transition-duration;
&.navbar-empty {
height: $header-height;
@@ -79,14 +90,9 @@ header {
&.header-collapsed {
padding: 0 16px;
-
- .side-nav-toggle {
- display: block;
- }
}
.side-nav-toggle {
- display: none;
position: absolute;
left: -10px;
margin: 6px 0;
@@ -108,9 +114,7 @@ header {
.header-content {
position: relative;
height: $header-height;
- padding-right: 40px;
padding-left: 30px;
- transition-duration: .3s;
@media (min-width: $screen-sm-min) {
padding-right: 0;
@@ -198,25 +202,24 @@ header {
}
}
-.header-collapsed {
- margin-left: 0;
+#tanuki-logo {
- .header-content {
-
- @media (min-width: $screen-sm-max) {
- padding-left: 30px;
- transition-duration: .3s;
- }
+ #tanuki-left-ear,
+ #tanuki-right-ear,
+ #tanuki-nose {
+ @include tanuki-logo-colors($tanuki-red);
}
-}
-.tanuki-shape {
- transition: all 0.8s;
+ #tanuki-left-eye,
+ #tanuki-right-eye {
+ @include tanuki-logo-colors($tanuki-orange);
+ }
- &:hover, &.highlight {
- fill: rgb(255, 255, 255);
- transition: all 0.1s;
+ #tanuki-left-cheek,
+ #tanuki-right-cheek {
+ @include tanuki-logo-colors($tanuki-yellow);
}
+
}
@media (max-width: $screen-xs-max) {
diff --git a/app/assets/stylesheets/framework/lists.scss b/app/assets/stylesheets/framework/lists.scss
index b34ec16cdba..a12c0bba44a 100644
--- a/app/assets/stylesheets/framework/lists.scss
+++ b/app/assets/stylesheets/framework/lists.scss
@@ -159,7 +159,7 @@ ul.content-list {
background-color: $gray-light;
border: dotted 1px $gray-dark;
margin: 1px 0;
- min-height: 30px;
+ min-height: 52px;
}
}
}
diff --git a/app/assets/stylesheets/framework/markdown_area.scss b/app/assets/stylesheets/framework/markdown_area.scss
index fd885b38680..fd8eaa8a691 100644
--- a/app/assets/stylesheets/framework/markdown_area.scss
+++ b/app/assets/stylesheets/framework/markdown_area.scss
@@ -65,6 +65,11 @@
a {
padding-top: 0;
line-height: 1;
+ border-bottom: 1px solid $border-color;
+
+ &.btn.btn-xs {
+ padding: 2px 5px;
+ }
}
}
}
@@ -97,5 +102,30 @@
white-space: pre-wrap;
word-break: keep-all;
}
+
+ @include bulleted-list;
+ }
+}
+
+.toolbar-group {
+ float: left;
+ margin-right: -5px;
+ margin-left: $gl-padding;
+
+ &:first-child {
+ margin-left: 0;
+ }
+}
+
+.toolbar-btn {
+ float: left;
+ padding: 0 5px;
+ color: #959494;
+ background: transparent;
+ border: 0;
+ outline: 0;
+
+ &:hover {
+ color: $gl-link-color;
}
}
diff --git a/app/assets/stylesheets/framework/mixins.scss b/app/assets/stylesheets/framework/mixins.scss
index 828e7224231..5ec5a96a597 100644
--- a/app/assets/stylesheets/framework/mixins.scss
+++ b/app/assets/stylesheets/framework/mixins.scss
@@ -110,3 +110,17 @@
font-size: 16px;
line-height: 24px;
}
+
+@mixin bulleted-list {
+ > ul {
+ list-style-type: disc;
+
+ ul {
+ list-style-type: circle;
+
+ ul {
+ list-style-type: square;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/app/assets/stylesheets/framework/mobile.scss b/app/assets/stylesheets/framework/mobile.scss
index d4e5cc819a4..c74682dfef4 100644
--- a/app/assets/stylesheets/framework/mobile.scss
+++ b/app/assets/stylesheets/framework/mobile.scss
@@ -52,6 +52,19 @@
.git-clone-holder {
display: none;
}
+
+ // Display Star and Fork buttons without counters on mobile.
+ .project-action-buttons {
+ display: block;
+
+ .count-buttons .btn {
+ margin: 0 10px;
+ }
+
+ .count-buttons .count-with-arrow {
+ display: none;
+ }
+ }
}
.project-stats {
diff --git a/app/assets/stylesheets/framework/nav.scss b/app/assets/stylesheets/framework/nav.scss
index 4de89daeb36..0281b06d3ba 100644
--- a/app/assets/stylesheets/framework/nav.scss
+++ b/app/assets/stylesheets/framework/nav.scss
@@ -18,6 +18,13 @@
opacity: 0;
transition-duration: .3s;
}
+
+ .fa {
+ position: relative;
+ top: 3px;
+ font-size: 13px;
+ color: $btn-placeholder-gray;
+ }
}
@mixin scrolling-links() {
@@ -74,6 +81,7 @@
.container-fluid {
background-color: $background-color;
+ margin-bottom: 0;
}
li {
@@ -103,10 +111,6 @@
width: 50%;
line-height: 28px;
- &.wiki-page {
- padding: 16px 10px 11px;
- }
-
/* Small devices (phones, tablets, 768px and lower) */
@media (max-width: $screen-sm-min) {
width: 100%;
@@ -135,7 +139,7 @@
}
/* Small devices (phones, tablets, 768px and lower) */
- @media (max-width: $screen-sm-max) {
+ @media (max-width: $screen-xs-max) {
width: 100%;
}
}
@@ -219,6 +223,7 @@
form {
display: block;
height: auto;
+ margin-bottom: 14px;
input {
width: 100%;
@@ -241,6 +246,12 @@
}
}
}
+
+ &.adjust {
+ .nav-text, .nav-controls {
+ width: auto;
+ }
+ }
}
.layout-nav {
@@ -250,7 +261,7 @@
z-index: 11;
background: $background-color;
border-bottom: 1px solid $border-color;
- transition-duration: .3s;
+ transition: padding $sidebar-transition-duration;
text-align: center;
.container-fluid {
@@ -280,11 +291,10 @@
}
.dropdown {
- margin-left: 7px;
-
- @media (max-width: $screen-xs-min) {
- margin-left: 0;
- }
+ position: absolute;
+ top: 7px;
+ right: 15px;
+ z-index: 2;
li.active {
font-weight: bold;
@@ -313,11 +323,19 @@
.fade-right {
@include fade(left, rgba(250, 250, 250, 0.4), $background-color);
right: 0;
+
+ .fa {
+ right: -7px;
+ }
}
.fade-left {
@include fade(right, rgba(250, 250, 250, 0.4), $background-color);
left: 0;
+
+ .fa {
+ left: -7px;
+ }
}
li {
@@ -347,6 +365,12 @@
.badge {
color: $gl-icon-color;
}
+
+ &:hover {
+ a, i {
+ color: $black;
+ }
+ }
}
}
diff --git a/app/assets/stylesheets/framework/panels.scss b/app/assets/stylesheets/framework/panels.scss
index ae7bdf14c40..874416e1007 100644
--- a/app/assets/stylesheets/framework/panels.scss
+++ b/app/assets/stylesheets/framework/panels.scss
@@ -9,6 +9,10 @@
margin-top: -2px;
float: right;
}
+
+ .dropdown-menu-toggle {
+ line-height: 20px;
+ }
}
.panel-body {
diff --git a/app/assets/stylesheets/framework/selects.scss b/app/assets/stylesheets/framework/selects.scss
index f242706ebe4..21d87cc9d34 100644
--- a/app/assets/stylesheets/framework/selects.scss
+++ b/app/assets/stylesheets/framework/selects.scss
@@ -165,11 +165,6 @@
background-size: 16px 16px !important;
}
-/** Branch/tag selector **/
-.project-refs-form .select2-container {
- width: 160px !important;
-}
-
.select2-results .select2-no-results,
.select2-results .select2-searching,
.select2-results .select2-ajax-error,
diff --git a/app/assets/stylesheets/framework/sidebar.scss b/app/assets/stylesheets/framework/sidebar.scss
index b7ec3f70bfb..98f917ce69b 100644
--- a/app/assets/stylesheets/framework/sidebar.scss
+++ b/app/assets/stylesheets/framework/sidebar.scss
@@ -1,26 +1,31 @@
.page-with-sidebar {
padding-top: $header-height;
- transition-duration: .3s;
+ transition: padding $sidebar-transition-duration;
.sidebar-wrapper {
position: fixed;
top: 0;
bottom: 0;
- overflow-y: auto;
- overflow-x: hidden;
left: 0;
height: 100%;
- transition-duration: .3s;
+ overflow: hidden;
+ transition: width $sidebar-transition-duration;
}
}
.sidebar-wrapper {
z-index: 1000;
background: $background-color;
+
+ .nicescroll-rails-hr {
+ // TODO: Figure out why nicescroll doesn't hide horizontal bar
+ display: none!important;
+ }
}
.content-wrapper {
width: 100%;
+ transition: padding $sidebar-transition-duration;
.container-fluid {
background: #fff;
@@ -34,58 +39,52 @@
}
}
-.sidebar-wrapper {
-
- .sidebar-user {
- padding: 15px 22px;
- position: fixed;
- bottom: 0;
- width: $sidebar_width;
- overflow: hidden;
- transition-duration: .3s;
+.sidebar-user {
+ padding: 15px;
+ position: absolute;
+ left: 0;
+ bottom: 0;
+ width: $sidebar_width;
+ overflow: hidden;
+ font-size: 16px;
+ line-height: 36px;
+ transition: width $sidebar-transition-duration, padding $sidebar-transition-duration;
- .username {
- margin-left: 10px;
- width: $sidebar_width - 2 * 10px;
- font-size: 16px;
- line-height: 34px;
- }
+ @media (min-width: $sidebar-breakpoint) {
+ bottom: 50px;
}
}
+.nav-sidebar {
+ position: absolute;
+ top: 50px;
+ bottom: 65px;
+ width: $sidebar_width;
+ overflow-y: auto;
+ overflow-x: hidden;
-.tanuki-shape {
- transition: all 0.8s;
-
- &:hover, &.highlight {
- fill: rgb(255, 255, 255);
- transition: all 0.1s;
+ @media (min-width: $sidebar-breakpoint) {
+ bottom: 115px;
}
-}
-
-
-.nav-sidebar {
- margin-top: 22 + $header-height;
- margin-bottom: 116px;
- transition-duration: .3s;
- list-style: none;
- overflow: hidden;
&.navbar-collapse {
padding: 0 !important;
}
li {
- width: $sidebar_width;
-
&.separate-item {
padding-top: 10px;
margin-top: 10px;
}
+ .icon-container {
+ width: 34px;
+ display: inline-block;
+ text-align: center;
+ }
+
a {
- width: $sidebar_width;
- padding: 7px 15px 7px 23px;
+ padding: 7px 15px 7px 12px;
font-size: $gl-font-size;
line-height: 24px;
display: block;
@@ -93,11 +92,9 @@
font-weight: normal;
outline: none;
- &:hover {
- text-decoration: none;
- }
-
- &:active, &:focus {
+ &:hover,
+ &:active,
+ &:focus {
text-decoration: none;
}
@@ -109,10 +106,6 @@
svg {
margin-right: 13px;
}
-
- &.back-link i {
- transition-duration: .3s;
- }
}
}
@@ -123,37 +116,50 @@
}
}
-.sidebar-subnav {
- margin-left: 0;
- padding-left: 0;
-
- li {
- list-style: none;
- }
-}
-
-.collapse-nav a {
+.toggle-nav-collapse {
width: $sidebar_width;
- position: fixed;
+ position: absolute;
top: 0;
left: 0;
+ min-height: 50px;
padding: 5px 0;
font-size: 18px;
- background: transparent;
- height: 50px;
- text-align: center;
- line-height: 40px;
+ line-height: 30px;
+}
+
+.nav-header-btn {
+ padding: 10px 5px;
+ color: inherit;
transition-duration: .3s;
- outline: none;
- &:hover {
+ &:hover,
+ &:focus {
+ color: $white-light;
text-decoration: none;
}
}
-.sidebar-wrapper {
- &.hidden-nav {
- width: 0;
+.pin-nav-btn {
+ display: none;
+ position: absolute;
+ left: 0;
+ bottom: 0;
+ height: 50px;
+ width: $sidebar_width;
+ line-height: 30px;
+
+ @media (min-width: $sidebar-breakpoint) {
+ display: block;
+ }
+
+ .fa {
+ transition: transform .15s;
+ }
+
+ &.is-active {
+ .fa {
+ transform: rotate(90deg);
+ }
}
}
@@ -162,62 +168,34 @@
.sidebar-wrapper {
width: 0;
-
- .nav-sidebar {
- width: 0;
-
- li {
- width: auto;
-
- a {
- span {
- display: none;
- }
- }
- }
- }
-
- .collapse-nav a {
- width: 0;
-
- i {
- display: none;
- }
- }
-
- .sidebar-user {
- width: 0;
- padding-left: 0;
- padding-right: 0;
-
- .username {
- display: none;
- }
- }
}
}
.page-sidebar-expanded {
-
- @media (max-width: $screen-sm-max) {
- padding-left: 0;
- }
-
.sidebar-wrapper {
width: $sidebar_width;
+ }
+}
- .nav-sidebar {
- width: $sidebar_width;
+.page-sidebar-pinned {
+ .content-wrapper,
+ .layout-nav {
+ @media (min-width: $sidebar-breakpoint) {
+ padding-left: $sidebar_width;
}
+ }
+}
- .nav-sidebar li a {
- width: $sidebar_width;
+header.header-pinned-nav {
+ @media (min-width: $sidebar-breakpoint) {
+ padding-left: ($sidebar_width + $gl-padding);
- &.back-link {
- i {
- opacity: 0;
- }
- }
+ .side-nav-toggle {
+ display: none;
+ }
+
+ .header-content {
+ padding-left: 0;
}
}
}
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index 752d8ec8788..c37574ca7a1 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -6,6 +6,8 @@ $sidebar_width: 220px;
$gutter_collapsed_width: 62px;
$gutter_width: 290px;
$gutter_inner_width: 258px;
+$sidebar-transition-duration: .15s;
+$sidebar-breakpoint: 1440px;
/*
* UI elements
@@ -154,6 +156,11 @@ $warning-message-border: #f0e2bb;
/* header */
$light-grey-header: #faf9f9;
+/* tanuki logo colors */
+$tanuki-red: #e24329;
+$tanuki-orange: #fc6d26;
+$tanuki-yellow: #fca326;
+
/*
* State colors:
*/
@@ -261,5 +268,10 @@ $calendar-hover-bg: #ecf3fe;
$calendar-border-color: rgba(#000, .1);
$calendar-unselectable-bg: #faf9f9;
+/*
+ * Personal Access Tokens
+ */
+$personal-access-tokens-disabled-label-color: #bbb;
+
$ci-output-bg: #1d1f21;
$ci-text-color: #c5c8c6;
diff --git a/app/assets/stylesheets/mailers/devise.scss b/app/assets/stylesheets/mailers/devise.scss
index 28611a5ec81..9495c5b3f37 100644
--- a/app/assets/stylesheets/mailers/devise.scss
+++ b/app/assets/stylesheets/mailers/devise.scss
@@ -38,6 +38,10 @@ table {
margin: 0 auto;
text-align: left;
width: 600px;
+
+ & > td {
+ text-align: center;
+ }
}
&#body {
diff --git a/app/assets/stylesheets/pages/commit.scss b/app/assets/stylesheets/pages/commit.scss
index fc3f214aba5..35ab28b3fea 100644
--- a/app/assets/stylesheets/pages/commit.scss
+++ b/app/assets/stylesheets/pages/commit.scss
@@ -26,6 +26,8 @@
.commit-info-row {
margin-bottom: 10px;
+ line-height: 24px;
+ padding-top: 6px;
&.commit-info-row-header {
line-height: 34px;
diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss
index c8c6bbde084..de534d28421 100644
--- a/app/assets/stylesheets/pages/commits.scss
+++ b/app/assets/stylesheets/pages/commits.scss
@@ -7,84 +7,119 @@
margin-right: 9px;
}
-.lists-separator {
- margin: 10px 0;
- border-color: #ddd;
+.commit-header {
+ padding: 5px 10px;
+ background-color: $background-color;
+ border-top: 1px solid #eee;
+ border-bottom: 1px solid #eee;
+ font-size: 14px;
+
+ &:first-child {
+ border-top-width: 0;
+ }
}
-.commits-row {
- ul {
- margin: 0;
+.commit-row-title {
+ line-height: 1;
+ margin-bottom: 7px;
- li.commit {
- padding: 8px 0;
- }
+ .notes_count {
+ float: right;
+ margin-right: 10px;
+ }
+
+ .str-truncated {
+ max-width: 70%;
}
- .commits-row-date {
- font-size: 15px;
- line-height: 20px;
- margin-bottom: 5px;
+ .commit-row-message {
+ color: $gl-dark-link-color;
+ }
+
+ .text-expander {
+ display: inline-block;
+ background: $gray-light;
+ color: $gl-placeholder-color;
+ padding: 0 5px;
+ cursor: pointer;
+ border: 1px solid $border-gray-dark;
+ border-radius: $border-radius-default;
+ margin-left: 5px;
+
+ &:hover {
+ background-color: darken($gray-light, 10%);
+ text-decoration: none;
+ }
}
}
-li.commit {
- list-style: none;
+.commit-actions {
+ @media (min-width: $screen-sm-min) {
+ float: right;
+ margin-left: $gl-padding;
+ margin-top: 2px;
+ font-size: 0;
+ }
- .commit-row-title {
- font-size: $list-font-size;
- line-height: 20px;
- margin-bottom: 2px;
+ .btn-transparent {
+ padding-left: 0;
+ padding-right: 0;
+ }
- .btn-clipboard {
- margin-top: -1px;
+ .btn {
+ &:not(:first-child) {
+ margin-left: $gl-padding;
}
+ }
+}
- .notes_count {
- float: right;
- margin-right: 10px;
- }
+.commit-short-id {
+ font-family: $monospace_font;
+ font-weight: 600;
+}
- .commit_short_id {
- min-width: 65px;
- color: $gl-dark-link-color;
- font-family: $monospace_font;
- }
+.commit {
+ padding: 10px 0;
+ position: relative;
- .str-truncated {
- max-width: 70%;
+ @media (min-width: $screen-sm-min) {
+ padding-left: 20px;
+
+ .commit-info-block {
+ padding-left: 44px;
}
+ }
- .commit-row-message {
- color: $gl-dark-link-color;
+ &:not(:last-child) {
+ border-bottom: 1px solid #eee;
+ }
- &:hover {
- text-decoration: underline;
- }
- }
+ a,
+ button {
+ color: $gl-dark-link-color;
+ vertical-align: baseline;
+ }
- .text-expander {
- background: #eee;
- color: #555;
- padding: 0 5px;
- cursor: pointer;
- margin-left: 4px;
- &:hover {
- background-color: #ddd;
- }
- }
+
+ .avatar {
+ position: absolute;
+ top: 10px;
+ left: 16px;
}
.item-title {
display: inline-block;
- max-width: 70%;
+
+ @media (min-width: $screen-sm-min) {
+ max-width: 70%;
+ }
}
.commit-row-description {
font-size: 14px;
border-left: 1px solid #eee;
padding: 10px 15px;
- margin: 5px 0 10px 5px;
+ margin: 10px 0;
background: #f9f9f9;
display: none;
@@ -93,6 +128,7 @@ li.commit {
background: inherit;
padding: 0;
margin: 0;
+ white-space: pre-wrap;
}
a {
@@ -102,7 +138,7 @@ li.commit {
.commit-row-info {
color: $gl-gray;
- line-height: 24px;
+ line-height: 1;
a {
color: $gl-gray;
@@ -111,10 +147,6 @@ li.commit {
.avatar {
margin-right: 8px;
}
-
- .committed_ago {
- display: inline-block;
- }
}
&.inline-commit {
diff --git a/app/assets/stylesheets/pages/diff.scss b/app/assets/stylesheets/pages/diff.scss
index 1a7d5f9666e..5286b73cc50 100644
--- a/app/assets/stylesheets/pages/diff.scss
+++ b/app/assets/stylesheets/pages/diff.scss
@@ -4,6 +4,11 @@
margin-bottom: $gl-padding;
border-radius: 3px;
+ .commit-short-id {
+ font-family: $regular_font;
+ font-weight: 400;
+ }
+
.diff-header {
position: relative;
background: $background-color;
diff --git a/app/assets/stylesheets/pages/editor.scss b/app/assets/stylesheets/pages/editor.scss
index 22679c764dc..1aa4e06d975 100644
--- a/app/assets/stylesheets/pages/editor.scss
+++ b/app/assets/stylesheets/pages/editor.scss
@@ -60,14 +60,14 @@
.encoding-selector,
.license-selector,
- .gitignore-selector {
+ .gitignore-selector,
+ .gitlab-ci-yml-selector {
display: inline-block;
vertical-align: top;
font-family: $regular_font;
}
- .gitignore-selector {
-
+ .gitignore-selector, .license-selector, .gitlab-ci-yml-selector {
.dropdown {
line-height: 21px;
}
@@ -77,4 +77,10 @@
width: 220px;
}
}
+
+ .gitlab-ci-yml-selector {
+ .dropdown-menu-toggle {
+ width: 250px;
+ }
+ }
}
diff --git a/app/assets/stylesheets/pages/environments.scss b/app/assets/stylesheets/pages/environments.scss
new file mode 100644
index 00000000000..e160d676e35
--- /dev/null
+++ b/app/assets/stylesheets/pages/environments.scss
@@ -0,0 +1,5 @@
+.environments {
+ .commit-title {
+ margin: 0;
+ }
+}
diff --git a/app/assets/stylesheets/pages/events.scss b/app/assets/stylesheets/pages/events.scss
index 6fe57c737b3..a2145956eb5 100644
--- a/app/assets/stylesheets/pages/events.scss
+++ b/app/assets/stylesheets/pages/events.scss
@@ -54,6 +54,10 @@
}
}
+ code {
+ white-space: pre-wrap;
+ }
+
pre {
border: none;
background: #f9f9f9;
@@ -136,9 +140,10 @@
.event-last-push {
overflow: auto;
width: 100%;
+
.event-last-push-text {
@include str-truncated(100%);
- padding: 5px 0;
+ padding: 4px 0;
font-size: 13px;
float: left;
margin-right: -150px;
diff --git a/app/assets/stylesheets/pages/groups.scss b/app/assets/stylesheets/pages/groups.scss
index ec6c099df5b..ac7721cbe15 100644
--- a/app/assets/stylesheets/pages/groups.scss
+++ b/app/assets/stylesheets/pages/groups.scss
@@ -39,3 +39,20 @@
}
}
}
+
+.groups-cover-block {
+
+ .container-fluid {
+ position: relative;
+ }
+
+ .access-request-button {
+ @include btn-gray;
+ position: absolute;
+ right: 16px;
+ bottom: 32px;
+ padding: 3px 10px;
+ text-transform: none;
+ background-color: $background-color;
+ }
+}
diff --git a/app/assets/stylesheets/pages/help.scss b/app/assets/stylesheets/pages/help.scss
index 4a95b7b852e..0b710ef168b 100644
--- a/app/assets/stylesheets/pages/help.scss
+++ b/app/assets/stylesheets/pages/help.scss
@@ -57,4 +57,11 @@
.documentation {
padding: 7px;
+
+ // Border around images in the help pages.
+ img:not(.emoji) {
+ border: 1px solid $table-border-gray;
+ padding: 5px;
+ margin: 5px;
+ }
}
diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss
index ea453ce356a..21ff6ab71f0 100644
--- a/app/assets/stylesheets/pages/issuable.scss
+++ b/app/assets/stylesheets/pages/issuable.scss
@@ -4,6 +4,13 @@
margin-right: 1px;
}
}
+
+ // Border around images in issue and MR descriptions.
+ .description img:not(.emoji) {
+ border: 1px solid $table-border-gray;
+ padding: 5px;
+ margin: 5px;
+ }
}
.issuable-filter-count {
@@ -34,6 +41,10 @@
color: inherit;
}
+ .issuable-header-text {
+ margin-top: 7px;
+ }
+
.block {
@include clearfix;
padding: $gl-padding 0;
@@ -60,10 +71,6 @@
margin-top: 0;
}
- .issuable-count {
- margin-top: 7px;
- }
-
.gutter-toggle {
margin-left: 20px;
padding-left: 10px;
@@ -145,7 +152,6 @@
.assign-yourself {
margin-top: 10px;
- font-weight: normal;
display: block;
}
}
@@ -158,6 +164,10 @@
font-weight: normal;
}
+ .no-value {
+ color: $gl-placeholder-color;
+ }
+
.sidebar-collapsed-icon {
display: none;
}
@@ -248,11 +258,16 @@
padding-bottom: 0;
margin-bottom: 10px;
}
+
+ .issuable-header-btn {
+ display: none;
+ }
}
- .issuable-pager {
+ .issuable-header-btn {
background: $gray-normal;
border: 1px solid $border-gray-normal;
+
&:hover {
background: $gray-dark;
border: 1px solid $border-gray-dark;
@@ -263,7 +278,7 @@
}
}
- a:not(.issuable-pager) {
+ a {
&:hover {
color: $md-link-color;
text-decoration: none;
@@ -322,7 +337,7 @@
margin-left: 5px;
a {
- color: #8c8c8c;
+ color: $gl-placeholder-color;
}
}
diff --git a/app/assets/stylesheets/pages/labels.scss b/app/assets/stylesheets/pages/labels.scss
index bc65404a741..f5f67e2cd84 100644
--- a/app/assets/stylesheets/pages/labels.scss
+++ b/app/assets/stylesheets/pages/labels.scss
@@ -50,11 +50,10 @@
.label-row {
.label-name {
- display: block;
+ display: inline-block;
margin-bottom: 10px;
@media (min-width: $screen-sm-min) {
- display: inline-block;
width: 200px;
margin-bottom: 0;
}
@@ -63,6 +62,7 @@
.label-description {
display: block;
margin-bottom: 10px;
+ margin-left: 50px;
@media (min-width: $screen-sm-min) {
display: inline-block;
@@ -115,6 +115,13 @@
}
}
+.draggable-handler {
+ display: inline-block;
+ opacity: 0;
+ transition: opacity .3s;
+ color: $gray-darkest;
+}
+
.prioritized-labels {
margin-bottom: 30px;
@@ -122,6 +129,13 @@
display: none;
color: $gray-light;
}
+
+ li:hover {
+ .draggable-handler {
+ display: inline-block;
+ opacity: 1;
+ }
+ }
}
.other-labels {
diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss
index a47f2580aa3..aca82f7f7bf 100644
--- a/app/assets/stylesheets/pages/merge_requests.scss
+++ b/app/assets/stylesheets/pages/merge_requests.scss
@@ -119,7 +119,12 @@
margin-bottom: 0;
}
- @media (max-width: $screen-sm-max) {
+ .btn-grouped {
+ margin-left: 0;
+ margin-right: 7px;
+ }
+
+ @media (max-width: $screen-xs-max) {
h4 {
font-size: 15px;
}
@@ -131,10 +136,14 @@
.btn,
.btn-group,
.accept-action {
- width: 100%;
margin-bottom: 4px;
}
+ .accept-action {
+ width: 100%;
+ text-align: center;
+ }
+
.accept-control {
width: 100%;
text-align: center;
@@ -244,6 +253,10 @@
.panel-footer {
padding: 5px 10px;
+
+ .btn {
+ min-width: auto;
+ }
}
.commit {
@@ -252,9 +265,7 @@
}
.avatar {
- width: 20px;
- height: 20px;
- margin-right: 5px;
+ margin-left: 0;
}
.commit-row-info {
@@ -282,7 +293,7 @@
margin-bottom: 0;
}
- @media (min-width: $screen-sm-min) {
+ @media (min-width: $screen-xs-min) {
float: left;
width: 50%;
margin-bottom: 0;
@@ -313,3 +324,13 @@
}
}
}
+
+.merged-buttons {
+ .btn {
+ float: left;
+
+ &:not(:last-child) {
+ margin-right: 10px;
+ }
+ }
+}
diff --git a/app/assets/stylesheets/pages/note_form.scss b/app/assets/stylesheets/pages/note_form.scss
index 577dddae741..3784010348a 100644
--- a/app/assets/stylesheets/pages/note_form.scss
+++ b/app/assets/stylesheets/pages/note_form.scss
@@ -179,6 +179,10 @@
border-top: 1px solid $border-color;
}
+.md-helper {
+ padding-top: 10px;
+}
+
.toolbar-button {
padding: 0;
background: none;
@@ -219,3 +223,16 @@
float: left;
}
}
+
+.note-form-actions {
+ @media (max-width: $screen-xs-max) {
+ .btn {
+ float: none;
+ width: 100%;
+
+ &:not(:last-child) {
+ margin-bottom: 10px;
+ }
+ }
+ }
+}
diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss
index 0c084118753..ffba3dc5bc6 100644
--- a/app/assets/stylesheets/pages/notes.scss
+++ b/app/assets/stylesheets/pages/notes.scss
@@ -84,24 +84,14 @@ ul.notes {
word-wrap: break-word;
@include md-typography;
+ // Reset ul style types since we're nested inside a ul already
+ @include bulleted-list;
+
// On diffs code should wrap nicely and not overflow
code {
white-space: pre-wrap;
}
- // Reset ul style types since we're nested inside a ul already
- & > ul {
- list-style-type: disc;
-
- ul {
- list-style-type: circle;
-
- ul {
- list-style-type: square;
- }
- }
- }
-
ul.task-list {
ul:not(.task-list) {
padding-left: 1.3em;
@@ -117,6 +107,13 @@ ul.notes {
code {
word-break: keep-all;
}
+
+ // Border around images in issue and MR comments.
+ img:not(.emoji) {
+ border: 1px solid $table-border-gray;
+ padding: 5px;
+ margin: 5px 0;
+ }
}
}
@@ -139,6 +136,12 @@ ul.notes {
@media (min-width: $screen-sm-min) {
padding-right: 0;
}
+
+ @media (max-width: $screen-xs-min) {
+ .inline {
+ display: block;
+ }
+ }
}
.note-emoji-button {
@@ -258,7 +261,11 @@ ul.notes {
position: absolute;
right: 0;
top: 0;
-
+
+ .note-action-button {
+ margin-left: 10px;
+ }
+
@media (min-width: $screen-sm-min) {
position: relative;
}
diff --git a/app/assets/stylesheets/pages/profile.scss b/app/assets/stylesheets/pages/profile.scss
index 167ab40d881..46371ec6871 100644
--- a/app/assets/stylesheets/pages/profile.scss
+++ b/app/assets/stylesheets/pages/profile.scss
@@ -192,6 +192,25 @@
}
}
+.personal-access-tokens-never-expires-label {
+ color: $personal-access-tokens-disabled-label-color;
+}
+
+.datepicker.personal-access-tokens-expires-at .ui-state-disabled span {
+ text-align: center;
+}
+
+.created-personal-access-token-container {
+ #created-personal-access-token {
+ width: 90%;
+ display: inline;
+ }
+
+ .btn-clipboard {
+ margin-left: 5px;
+ }
+}
+
.user-profile {
@media (max-width: $screen-xs-max) {
.cover-block {
diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss
index ea708872cc8..d3e59d7fdb9 100644
--- a/app/assets/stylesheets/pages/projects.scss
+++ b/app/assets/stylesheets/pages/projects.scss
@@ -5,10 +5,12 @@
font-weight: normal;
}
}
+
.no-ssh-key-message, .project-limit-message {
background-color: #f28d35;
margin-bottom: 0;
}
+
.new_project,
.edit-project {
fieldset.features {
@@ -18,13 +20,6 @@
}
}
-.project-name-holder {
- .help-inline {
- vertical-align: top;
- padding: 7px;
- }
-}
-
.project-home-panel {
background: $white-light;
text-align: left;
@@ -33,7 +28,7 @@
.container-fluid {
position: relative;
- @media (min-width: $screen-md-max) {
+ @media (min-width: $screen-lg-min) {
.row {
display: flex;
-ms-flex-align: center;
@@ -106,7 +101,8 @@
.notifications-btn {
- .fa-bell {
+ .fa-bell,
+ .fa-spinner {
margin-right: 6px;
}
@@ -224,13 +220,20 @@
right: 16px;
bottom: 0;
- .btn {
- padding: 3px 10px;
- background-color: $background-color;
+ @media (max-width: $screen-md-max) {
+ top: 0;
}
- @media (max-width: 1304px) {
- top: 0;
+ .access-request-button {
+ position: absolute;
+ right: 0;
+ bottom: 61px;
+
+ @media (max-width: $screen-md-max) {
+ position: relative;
+ bottom: 0;
+ margin-right: 10px;
+ }
}
}
@@ -281,10 +284,6 @@
color: #555;
}
-.project_member_row form {
- margin: 0;
-}
-
.transfer-project .select2-container {
min-width: 200px;
}
@@ -368,13 +367,14 @@ a.deploy-project-label {
.project-import .btn {
float: left;
+ margin-bottom: 10px;
margin-right: 10px;
}
.project-stats {
margin-top: $gl-padding;
margin-bottom: 0;
- padding: 16px 0;
+ padding: 0;
background-color: $white-light;
font-size: 0;
@@ -383,13 +383,14 @@ a.deploy-project-label {
}
.nav li {
- display: inline;
+ display: inline-block;
+ margin: 16px 0;
+ margin-right: 16px;
}
.nav > li > a {
background-color: transparent;
- margin-right: 12px;
- padding: 0 10px;
+ padding: 5px 10px;
font-size: 15px;
color: $notes-light-color;
}
@@ -403,12 +404,17 @@ a.deploy-project-label {
font-size: 17px;
}
- li.missing a {
- color: #5a6069;
- border: 1px dashed #dce0e5;
+ li.missing {
+ border: 1px dashed $border-gray-light;
+ border-radius: $border-radius-default;
+
+ a {
+ color: $notes-light-color;
+ display: block;
+ }
&:hover {
- background-color: #f0f2f5;
+ background-color: $gray-normal;
}
}
@@ -495,7 +501,8 @@ pre.light-well {
.activity-filter-block {
.controls {
- padding-bottom: 10px;
+ padding-bottom: 7px;
+ margin-top: 8px;
border-bottom: 1px solid $border-color;
}
}
@@ -616,3 +623,9 @@ pre.light-well {
color: $gl-text-green;
}
}
+
+.project-refs-form {
+ .dropdown-menu {
+ width: 300px;
+ }
+}
diff --git a/app/assets/stylesheets/pages/stat_graph.scss b/app/assets/stylesheets/pages/stat_graph.scss
index 85a0304196c..69288b31cc4 100644
--- a/app/assets/stylesheets/pages/stat_graph.scss
+++ b/app/assets/stylesheets/pages/stat_graph.scss
@@ -14,24 +14,38 @@
font-size: 10px;
}
+#contributors-master {
+ @include make-md-column(12);
+
+ svg {
+ width: 100%;
+ }
+}
+
#contributors {
.contributors-list {
margin: 0 0 10px;
list-style: none;
padding: 0;
+
+ svg {
+ width: 100%;
+ }
}
.person {
- &:nth-child(even) {
- float: right;
- }
- float: left;
+ @include make-md-column(6);
margin-top: 10px;
+
+ @media (max-width: $screen-sm-min) {
+ width: 100%;
+ }
}
.person .spark {
display: block;
background: #f3f3f3;
+ width: 100%;
}
.person .area-contributor {
diff --git a/app/assets/stylesheets/pages/todos.scss b/app/assets/stylesheets/pages/todos.scss
index afc00a68572..cf16d070cfe 100644
--- a/app/assets/stylesheets/pages/todos.scss
+++ b/app/assets/stylesheets/pages/todos.scss
@@ -62,6 +62,10 @@
}
}
+ code {
+ white-space: pre-wrap;
+ }
+
pre {
border: none;
background: #f9f9f9;
diff --git a/app/assets/stylesheets/pages/tree.scss b/app/assets/stylesheets/pages/tree.scss
index f16fc7f388f..99c9e81ddb9 100644
--- a/app/assets/stylesheets/pages/tree.scss
+++ b/app/assets/stylesheets/pages/tree.scss
@@ -101,7 +101,7 @@
margin: 0;
.commit {
- padding: 0;
+ padding: 0 0 0 55px;
.commit-row-title {
.commit-row-message {
@@ -129,4 +129,6 @@
.tree-controls {
float: right;
margin-top: 11px;
+ position: relative;
+ z-index: 2;
}