summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG16
-rw-r--r--app/assets/javascripts/activities.js.coffee5
-rw-r--r--app/assets/javascripts/application.js.coffee6
-rw-r--r--app/assets/javascripts/awards_handler.coffee16
-rw-r--r--app/assets/javascripts/dispatcher.js.coffee2
-rw-r--r--app/assets/javascripts/gfm_auto_complete.js.coffee5
-rw-r--r--app/assets/javascripts/graphs/application.js.coffee1
-rw-r--r--app/assets/javascripts/lib/common_utils.js.coffee24
-rw-r--r--app/assets/javascripts/lib/datetime_utility.js.coffee9
-rw-r--r--app/assets/javascripts/milestone_select.js.coffee15
-rw-r--r--app/assets/javascripts/pager.js.coffee3
-rw-r--r--app/assets/javascripts/subscription.js.coffee5
-rw-r--r--app/assets/javascripts/user_tabs.js.coffee3
-rw-r--r--app/assets/stylesheets/framework/buttons.scss42
-rw-r--r--app/assets/stylesheets/framework/forms.scss1
-rw-r--r--app/assets/stylesheets/framework/jquery.scss43
-rw-r--r--app/assets/stylesheets/framework/lists.scss12
-rw-r--r--app/assets/stylesheets/framework/nav.scss13
-rw-r--r--app/assets/stylesheets/framework/selects.scss2
-rw-r--r--app/assets/stylesheets/framework/tw_bootstrap.scss5
-rw-r--r--app/assets/stylesheets/framework/variables.scss5
-rw-r--r--app/assets/stylesheets/pages/labels.scss108
-rw-r--r--app/assets/stylesheets/pages/merge_requests.scss5
-rw-r--r--app/assets/stylesheets/pages/note_form.scss13
-rw-r--r--app/helpers/labels_helper.rb6
-rw-r--r--app/helpers/milestones_helper.rb2
-rw-r--r--app/services/todo_service.rb11
-rw-r--r--app/views/award_emoji/_awards_block.html.haml3
-rw-r--r--app/views/devise/sessions/two_factor.html.haml3
-rw-r--r--app/views/groups/group_members/_group_member.html.haml2
-rw-r--r--app/views/groups/milestones/new.html.haml3
-rw-r--r--app/views/projects/branches/index.html.haml43
-rw-r--r--app/views/projects/builds/index.html.haml1
-rw-r--r--app/views/projects/issues/index.html.haml2
-rw-r--r--app/views/projects/labels/_label.html.haml62
-rw-r--r--app/views/projects/merge_requests/widget/open/_conflicts.html.haml4
-rw-r--r--app/views/projects/milestones/_form.html.haml3
-rw-r--r--app/views/projects/milestones/index.html.haml1
-rw-r--r--app/views/projects/milestones/show.html.haml4
-rw-r--r--app/views/projects/pipelines/index.html.haml2
-rw-r--r--app/views/projects/project_members/_project_member.html.haml2
-rw-r--r--app/views/projects/tags/_download.html.haml7
-rw-r--r--app/views/projects/tags/_tag.html.haml4
-rw-r--r--app/views/projects/tags/index.html.haml10
-rw-r--r--app/views/projects/wikis/_main_links.html.haml6
-rw-r--r--app/views/projects/wikis/_nav.html.haml1
-rw-r--r--app/views/shared/_label_row.html.haml5
-rw-r--r--app/views/shared/groups/_group.html.haml6
-rw-r--r--app/views/shared/issuable/_form.html.haml4
-rw-r--r--app/views/shared/issuable/_sidebar.html.haml6
-rw-r--r--app/views/shared/milestones/_milestone.html.haml8
-rw-r--r--app/views/users/show.html.haml4
-rw-r--r--features/steps/project/issues/labels.rb2
-rw-r--r--features/steps/project/labels.rb2
-rw-r--r--lib/gitlab/gon_helper.rb1
-rw-r--r--lib/tasks/gitlab/db.rake2
-rw-r--r--spec/features/dashboard/datetime_on_tooltips_spec.rb46
-rw-r--r--spec/features/issues_spec.rb12
-rw-r--r--spec/javascripts/awards_handler_spec.js.coffee13
-rw-r--r--spec/lib/disable_email_interceptor_spec.rb4
-rw-r--r--spec/services/todo_service_spec.rb30
61 files changed, 426 insertions, 260 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 4b75030db92..b00c149a753 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -12,6 +12,7 @@ v 8.9.0 (unreleased)
- Allow customisable text on the 'nearly there' page after a user signs up
- Bump recaptcha gem to 3.0.0 to remove deprecated stoken support
- Allow forking projects with restricted visibility level
+ - Added descriptions to notification settings dropdown
- Improve note validation to prevent errors when creating invalid note via API
- Reduce number of fog gem dependencies
- Remove project notification settings associated with deleted projects
@@ -22,6 +23,7 @@ v 8.9.0 (unreleased)
- `git clone https://host/namespace/project` now works, in addition to using the `.git` suffix
- Bump nokogiri to 1.6.8
- Use gitlab-shell v3.0.0
+ - Upgrade to jQuery 2
- Use Knapsack to evenly distribute tests across multiple nodes
- Add `sha` parameter to MR merge API, to ensure only reviewed changes are merged
- Don't allow MRs to be merged when commits were added since the last review / page load
@@ -45,6 +47,7 @@ v 8.9.0 (unreleased)
- Cache assigned issue and merge request counts in sidebar nav
- Use Knapsack only in CI environment
- Cache project build count in sidebar nav
+ - Add milestone expire date to the right sidebar
- Fix markdown_spec to use before instead of before(:all) to properly cleanup database after testing
- Reduce number of queries needed to render issue labels in the sidebar
- Improve error handling importing projects
@@ -55,19 +58,21 @@ v 8.9.0 (unreleased)
- RepositoryCheck::SingleRepositoryWorker public and private methods are now instrumented
- Improve issuables APIs performance when accessing notes !4471
- External links now open in a new tab
+ - Markdown editor now correctly resets the input value on edit cancellation !4175
+ - Toggling a task list item in a issue/mr description does not creates a Todo for mentions
+ - Improved UX of date pickers on issue & milestone forms
-v 8.8.4 (unreleased)
+v 8.8.5 (unreleased)
- Ensure branch cleanup regardless of whether the GitHub import process succeeds
- Fix issue with arrow keys not working in search autocomplete dropdown
- Fix todos page throwing errors when you have a project pending deletion
- Reduce number of SQL queries when rendering user references
- - Upgrade to jQuery 2
- - Remove prev/next buttons on issues and merge requests
- Import GitHub repositories respecting the API rate limit
- Fix importer for GitHub comments on diff
- Disable Webhooks before proceeding with the GitHub import
- - Added descriptions to notification settings dropdown
- - Markdown editor now correctly resets the input value on edit cancellation !4175
+
+v 8.8.4
+ - Fix LDAP-based login for users with 2FA enabled. !4493
v 8.8.3
- Fix 404 page when viewing TODOs that contain milestones or labels in different projects. !4312
@@ -179,6 +184,7 @@ v 8.8.0
- Fixed advice on invalid permissions on upload path !2948 (Ludovic Perrine)
- Allows MR authors to have the source branch removed when merging the MR. !2801 (Jeroen Jacobs)
- When creating a .gitignore file a dropdown with templates will be provided
+ - Shows the issue/MR list search/filter form and corrects the mobile styling for guest users. #17562
v 8.7.7
- Fix import by `Any Git URL` broken if the URL contains a space
diff --git a/app/assets/javascripts/activities.js.coffee b/app/assets/javascripts/activities.js.coffee
index 5092e824e65..ed5a5d0260c 100644
--- a/app/assets/javascripts/activities.js.coffee
+++ b/app/assets/javascripts/activities.js.coffee
@@ -1,11 +1,14 @@
class @Activities
constructor: ->
- Pager.init 20, true
+ Pager.init 20, true, false, @updateTooltips
$(".event-filter-link").on "click", (event) =>
event.preventDefault()
@toggleFilter($(event.currentTarget))
@reloadActivities()
+ updateTooltips: ->
+ gl.utils.localTimeAgo($('.js-timeago', '#activity'))
+
reloadActivities: ->
$(".content_list").html ''
Pager.init 20, true
diff --git a/app/assets/javascripts/application.js.coffee b/app/assets/javascripts/application.js.coffee
index ebf425550e9..b28327ce12d 100644
--- a/app/assets/javascripts/application.js.coffee
+++ b/app/assets/javascripts/application.js.coffee
@@ -35,7 +35,6 @@
#= require raphael
#= require g.raphael
#= require g.bar
-#= require Chart
#= require branch-graph
#= require ace/ace
#= require ace/ext-searchbox
@@ -226,6 +225,10 @@ $ ->
form = btn.closest("form")
new ConfirmDangerModal(form, text)
+
+ $(document).on 'click', 'button', ->
+ $(this).blur()
+
$('input[type="search"]').each ->
$this = $(this)
$this.attr 'value', $this.val()
@@ -268,5 +271,6 @@ $ ->
.on "resize", (e) ->
fitSidebarForSize()
+ gl.awardsHandler = new AwardsHandler()
checkInitialSidebarSize()
new Aside()
diff --git a/app/assets/javascripts/awards_handler.coffee b/app/assets/javascripts/awards_handler.coffee
index efa8f6cd010..136db8ee14d 100644
--- a/app/assets/javascripts/awards_handler.coffee
+++ b/app/assets/javascripts/awards_handler.coffee
@@ -65,7 +65,7 @@ class @AwardsHandler
$addBtn.removeClass 'is-loading'
$menu = $('.emoji-menu')
@positionMenu($menu, $addBtn)
- @renderFrequentlyUsedBlock()
+ @renderFrequentlyUsedBlock() unless @frequentEmojiBlockRendered
setTimeout =>
$menu.addClass 'is-visible'
@@ -100,7 +100,7 @@ class @AwardsHandler
$menu.css(css)
- addAward: (votesBlock, awardUrl, emoji, checkMutuality = yes, callback) ->
+ addAward: (votesBlock, awardUrl, emoji, checkMutuality = true, callback) ->
emoji = @normilizeEmojiName emoji
@@ -111,7 +111,7 @@ class @AwardsHandler
$('.emoji-menu').removeClass 'is-visible'
- addAwardToEmojiBar: (votesBlock, emoji, checkForMutuality = yes) ->
+ addAwardToEmojiBar: (votesBlock, emoji, checkForMutuality = true) ->
@checkMutuality votesBlock, emoji if checkForMutuality
@addEmojiToFrequentlyUsedList emoji
@@ -153,7 +153,7 @@ class @AwardsHandler
if isAlreadyVoted
@showEmojiLoader $emojiButton
- @addAward votesBlock, awardUrl, mutualVote, no, ->
+ @addAward votesBlock, awardUrl, mutualVote, false, ->
$emojiButton.removeClass 'is-loading'
@@ -282,7 +282,7 @@ class @AwardsHandler
@createEmojiMenu @getAwardMenuUrl(), => @createEmoji_ votesBlock, emoji
- getAwardMenuUrl: -> return gl.awardMenuUrl
+ getAwardMenuUrl: -> return gon.award_menu_url
resolveNameToCssClass: (emoji) ->
@@ -336,13 +336,15 @@ class @AwardsHandler
if $.cookie 'frequently_used_emojis'
frequentlyUsedEmojis = @getFrequentlyUsedEmojis()
- ul = $("<ul class='clearfix emoji-menu-list'>")
+ ul = $("<ul class='clearfix emoji-menu-list frequent-emojis'>")
for emoji in frequentlyUsedEmojis
$(".emoji-menu-content [data-emoji='#{emoji}']").closest('li').clone().appendTo(ul)
$('input.emoji-search').after(ul).after($('<h5>').text('Frequently used'))
+ @frequentEmojiBlockRendered = true
+
setupSearch: ->
@@ -365,4 +367,4 @@ class @AwardsHandler
searchEmojis: (term) ->
- $(".emoji-menu-content [data-emoji*='#{term}']").closest('li').clone()
+ $(".emoji-menu-list:not(.frequent-emojis) [data-emoji*='#{term}']").closest('li').clone()
diff --git a/app/assets/javascripts/dispatcher.js.coffee b/app/assets/javascripts/dispatcher.js.coffee
index 5d6ac6e757e..29ac0f70b30 100644
--- a/app/assets/javascripts/dispatcher.js.coffee
+++ b/app/assets/javascripts/dispatcher.js.coffee
@@ -23,7 +23,6 @@ class Dispatcher
new Issue()
shortcut_handler = new ShortcutsIssuable()
new ZenMode()
- gl.awardsHandler = new AwardsHandler()
when 'projects:milestones:show', 'groups:milestones:show', 'dashboard:milestones:show'
new Milestone()
when 'dashboard:todos:index'
@@ -54,7 +53,6 @@ class Dispatcher
new Diff()
shortcut_handler = new ShortcutsIssuable(true)
new ZenMode()
- gl.awardsHandler = new AwardsHandler()
when "projects:merge_requests:diffs"
new Diff()
new ZenMode()
diff --git a/app/assets/javascripts/gfm_auto_complete.js.coffee b/app/assets/javascripts/gfm_auto_complete.js.coffee
index b13a431a52f..76c3083232b 100644
--- a/app/assets/javascripts/gfm_auto_complete.js.coffee
+++ b/app/assets/javascripts/gfm_auto_complete.js.coffee
@@ -3,6 +3,7 @@
window.GitLab ?= {}
GitLab.GfmAutoComplete =
dataLoading: false
+ dataLoaded: false
dataSource: ''
@@ -35,7 +36,7 @@ GitLab.GfmAutoComplete =
$.fn.atwho.default.callbacks.filter(query, data, searchKey)
beforeInsert: (value) ->
- if value.indexOf('undefined')
+ if not GitLab.GfmAutoComplete.dataLoaded
@at
else
value
@@ -182,6 +183,8 @@ GitLab.GfmAutoComplete =
$.getJSON(dataSource)
loadData: (data) ->
+ @dataLoaded = true
+
# load members
@input.atwho 'load', '@', data.members
# load issues
diff --git a/app/assets/javascripts/graphs/application.js.coffee b/app/assets/javascripts/graphs/application.js.coffee
index e0f681acf0b..91f81a5d249 100644
--- a/app/assets/javascripts/graphs/application.js.coffee
+++ b/app/assets/javascripts/graphs/application.js.coffee
@@ -4,4 +4,5 @@
# 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 Chart
#= require_tree .
diff --git a/app/assets/javascripts/lib/common_utils.js.coffee b/app/assets/javascripts/lib/common_utils.js.coffee
new file mode 100644
index 00000000000..0000e99a650
--- /dev/null
+++ b/app/assets/javascripts/lib/common_utils.js.coffee
@@ -0,0 +1,24 @@
+((w) ->
+
+ jQuery.timefor = (time, suffix, expiredLabel) ->
+
+ return '' unless time
+
+ suffix or= 'remaining'
+ expiredLabel or= 'Past due'
+
+ jQuery.timeago.settings.allowFuture = yes
+
+ { suffixFromNow } = jQuery.timeago.settings.strings
+ jQuery.timeago.settings.strings.suffixFromNow = suffix
+
+ timefor = $.timeago time
+
+ if timefor.indexOf('ago') > -1
+ timefor = expiredLabel
+
+ jQuery.timeago.settings.strings.suffixFromNow = suffixFromNow
+
+ return timefor
+
+) window
diff --git a/app/assets/javascripts/lib/datetime_utility.js.coffee b/app/assets/javascripts/lib/datetime_utility.js.coffee
index ad1d1c70481..948d6dbf07e 100644
--- a/app/assets/javascripts/lib/datetime_utility.js.coffee
+++ b/app/assets/javascripts/lib/datetime_utility.js.coffee
@@ -12,6 +12,13 @@
$el.attr('title', gl.utils.formatDate($el.attr('datetime')))
)
- $timeagoEls.timeago() if setTimeago
+ if setTimeago
+ $timeagoEls.timeago()
+ $timeagoEls.tooltip('destroy')
+
+ # Recreate with custom template
+ $timeagoEls.tooltip(
+ template: '<div class="tooltip local-timeago" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'
+ )
) window
diff --git a/app/assets/javascripts/milestone_select.js.coffee b/app/assets/javascripts/milestone_select.js.coffee
index 1d061d5edb7..648e1f3bde0 100644
--- a/app/assets/javascripts/milestone_select.js.coffee
+++ b/app/assets/javascripts/milestone_select.js.coffee
@@ -24,11 +24,21 @@ class @MilestoneSelect
if issueUpdateURL
milestoneLinkTemplate = _.template(
- '<a href="/<%= namespace %>/<%= path %>/milestones/<%= iid %>"><%= _.escape(title) %></a>'
+ '<a href="/<%= namespace %>/<%= path %>/milestones/<%= iid %>">
+ <span class="has-tooltip" data-container="body" title="<%= remaining %>">
+ <%= _.escape(title) %>
+ </span>
+ </a>'
)
milestoneLinkNoneTemplate = '<div class="light">None</div>'
+ collapsedSidebarLabelTemplate = _.template(
+ '<span class="has-tooltip" data-container="body" title="<%= remaining %>" data-placement="left">
+ <%= _.escape(title) %>
+ </span>'
+ )
+
$dropdown.glDropdown(
data: (term, callback) ->
$.ajax(
@@ -122,8 +132,9 @@ class @MilestoneSelect
if data.milestone?
data.milestone.namespace = _this.currentProject.namespace
data.milestone.path = _this.currentProject.path
+ data.milestone.remaining = $.timefor data.milestone.due_date
$value.html(milestoneLinkTemplate(data.milestone))
- $sidebarCollapsedValue.find('span').text(data.milestone.title)
+ $sidebarCollapsedValue.find('span').html(collapsedSidebarLabelTemplate(data.milestone))
else
$value.html(milestoneLinkNoneTemplate)
$sidebarCollapsedValue.find('span').text('No')
diff --git a/app/assets/javascripts/pager.js.coffee b/app/assets/javascripts/pager.js.coffee
index 0ff83b7f0c8..8049c5c30e2 100644
--- a/app/assets/javascripts/pager.js.coffee
+++ b/app/assets/javascripts/pager.js.coffee
@@ -1,5 +1,5 @@
@Pager =
- init: (@limit = 0, preload, @disable = false) ->
+ init: (@limit = 0, preload, @disable = false, @callback = $.noop) ->
@loading = $('.loading').first()
if preload
@@ -19,6 +19,7 @@
@loading.hide()
success: (data) ->
Pager.append(data.count, data.html)
+ Pager.callback()
dataType: "json"
append: (count, html) ->
diff --git a/app/assets/javascripts/subscription.js.coffee b/app/assets/javascripts/subscription.js.coffee
index 1a430f3aa47..08d494aba9f 100644
--- a/app/assets/javascripts/subscription.js.coffee
+++ b/app/assets/javascripts/subscription.js.coffee
@@ -19,3 +19,8 @@ class @Subscription
action = if status == 'subscribed' then 'Unsubscribe' else 'Subscribe'
btn.find('span').text(action)
@subscription_status.find('>div').toggleClass('hidden')
+
+ if btn.attr('data-original-title')
+ btn.tooltip('hide')
+ .attr('data-original-title', action)
+ .tooltip('fixTitle')
diff --git a/app/assets/javascripts/user_tabs.js.coffee b/app/assets/javascripts/user_tabs.js.coffee
index 70614396a4e..29dad21faed 100644
--- a/app/assets/javascripts/user_tabs.js.coffee
+++ b/app/assets/javascripts/user_tabs.js.coffee
@@ -122,6 +122,9 @@ class @UserTabs
@parentEl.find(tabSelector).html(data.html)
@loaded[action] = true
+ # Fix tooltips
+ gl.utils.localTimeAgo($('.js-timeago', tabSelector))
+
loadActivities: (source) ->
return if @loaded['activity'] is true
diff --git a/app/assets/stylesheets/framework/buttons.scss b/app/assets/stylesheets/framework/buttons.scss
index 625200cbcad..1e3083cce55 100644
--- a/app/assets/stylesheets/framework/buttons.scss
+++ b/app/assets/stylesheets/framework/buttons.scss
@@ -79,6 +79,23 @@
@include btn-color($white-light, $border-color, $white-normal, $border-white-normal, $white-dark, $border-white-dark, $btn-white-active);
}
+@mixin btn-with-margin {
+ margin-left: $btn-side-margin;
+ float: left;
+
+ &.inline {
+ float: none;
+ }
+
+ &.btn-sm {
+ margin-left: $btn-sm-side-margin;
+ }
+
+ &.btn-xs {
+ margin-left: $btn-xs-side-margin;
+ }
+}
+
.btn {
@include btn-default;
@include btn-white;
@@ -142,24 +159,7 @@
}
&.btn-grouped {
- margin-right: $btn-side-margin;
- float: left;
-
- &.inline {
- float: none;
- }
-
- &:last-child {
- margin-right: 0;
- }
-
- &.btn-sm {
- margin-right: $btn-sm-side-margin;
- }
-
- &.btn-xs {
- margin-right: $btn-xs-side-margin;
- }
+ @include btn-with-margin;
}
&.disabled {
@@ -203,11 +203,7 @@
.btn-group {
&.btn-grouped {
- margin-right: 7px;
- float: left;
- &:last-child {
- margin-right: 0;
- }
+ @include btn-with-margin;
}
}
diff --git a/app/assets/stylesheets/framework/forms.scss b/app/assets/stylesheets/framework/forms.scss
index 46acc3b772f..43d55661541 100644
--- a/app/assets/stylesheets/framework/forms.scss
+++ b/app/assets/stylesheets/framework/forms.scss
@@ -76,6 +76,7 @@ label {
.form-control {
@include box-shadow(none);
border-radius: 3px;
+ padding: $gl-vert-padding $gl-input-padding;
}
.select-wrapper {
diff --git a/app/assets/stylesheets/framework/jquery.scss b/app/assets/stylesheets/framework/jquery.scss
index 525ed81b059..30a5b837d69 100644
--- a/app/assets/stylesheets/framework/jquery.scss
+++ b/app/assets/stylesheets/framework/jquery.scss
@@ -2,6 +2,7 @@
font-family: $regular_font;
font-size: $font-size-base;
+ &.ui-datepicker,
&.ui-datepicker-inline {
border: 1px solid #ddd;
padding: 10px;
@@ -10,6 +11,25 @@
.ui-datepicker-header {
background: #fff;
border-color: #ddd;
+
+ .ui-datepicker-prev,
+ .ui-datepicker-next {
+ top: 4px;
+ }
+
+ .ui-datepicker-prev {
+ left: 2px;
+ }
+
+ .ui-datepicker-next {
+ right: 2px;
+ }
+
+ .ui-state-hover {
+ background: transparent;
+ border: 0;
+ cursor: pointer;
+ }
}
.ui-datepicker-calendar td a {
@@ -36,21 +56,18 @@
}
.ui-state-highlight {
- border: 1px solid #eee;
- background: #eee;
+ border: 0;
+ background: transparent;
}
- .ui-state-active {
- border: 1px solid $gl-primary;
- background: $gl-primary;
- color: #fff;
- }
-
- .ui-state-hover,
- .ui-state-focus {
- border: 1px solid $row-hover;
- background: $row-hover;
- color: #333;
+ .ui-datepicker-calendar {
+ .ui-state-active,
+ .ui-state-hover,
+ .ui-state-focus {
+ border: 1px solid $gl-primary;
+ background: $gl-primary;
+ color: #fff;
+ }
}
}
diff --git a/app/assets/stylesheets/framework/lists.scss b/app/assets/stylesheets/framework/lists.scss
index 96e7aa4fb15..b34ec16cdba 100644
--- a/app/assets/stylesheets/framework/lists.scss
+++ b/app/assets/stylesheets/framework/lists.scss
@@ -137,8 +137,16 @@ ul.content-list {
padding-top: 1px;
float: right;
- .btn {
- padding: 10px 14px;
+ > .btn,
+ > .btn-group {
+ margin-right: $gl-padding-top;
+ display: inline-block;
+ margin-top: 4px;
+ margin-bottom: 4px;
+
+ &:last-child {
+ margin-right: 0;
+ }
}
}
diff --git a/app/assets/stylesheets/framework/nav.scss b/app/assets/stylesheets/framework/nav.scss
index 0918f673607..a036799e15a 100644
--- a/app/assets/stylesheets/framework/nav.scss
+++ b/app/assets/stylesheets/framework/nav.scss
@@ -171,6 +171,7 @@
> form {
display: inline-block;
margin-top: -1px;
+ margin-bottom: 12px;
}
.icon-label {
@@ -207,7 +208,7 @@
@media (max-width: $screen-xs-max) {
padding-bottom: 0;
-
+ width: 100%;
.btn, form, .dropdown, .dropdown-menu-toggle, .form-control {
margin: 0 0 10px;
display: block;
@@ -238,16 +239,6 @@
margin: 0;
}
}
-
- /* Small devices (tablets, 768px and lower) */
- @media (max-width: $screen-sm-max) {
- width: 100%;
- text-align: left;
-
- input {
- width: 300px;
- }
- }
}
}
diff --git a/app/assets/stylesheets/framework/selects.scss b/app/assets/stylesheets/framework/selects.scss
index 6efc6ec1e4b..f242706ebe4 100644
--- a/app/assets/stylesheets/framework/selects.scss
+++ b/app/assets/stylesheets/framework/selects.scss
@@ -8,7 +8,7 @@
background: #fff;
border-color: $input-border;
height: 35px;
- padding: $gl-vert-padding $gl-btn-padding;
+ padding: $gl-vert-padding $gl-input-padding;
font-size: $gl-font-size;
line-height: 1.42857143;
border-radius: $border-radius-base;
diff --git a/app/assets/stylesheets/framework/tw_bootstrap.scss b/app/assets/stylesheets/framework/tw_bootstrap.scss
index 6a45c34ccbb..e3154657c54 100644
--- a/app/assets/stylesheets/framework/tw_bootstrap.scss
+++ b/app/assets/stylesheets/framework/tw_bootstrap.scss
@@ -192,3 +192,8 @@
.text-info:hover {
color: $brand-info;
}
+
+// Prevent datetimes on tooltips to break into two lines
+.local-timeago {
+ white-space: nowrap;
+}
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index d8ea07559ab..99e3df119ed 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -57,6 +57,7 @@ $code_line_height: 1.5;
*/
$gl-padding: 16px;
$gl-btn-padding: 10px;
+$gl-input-padding: 10px;
$gl-vert-padding: 6px;
$gl-padding-top: 10px;
@@ -79,8 +80,8 @@ $provider-btn-not-active-color: #4688f1;
$link-underline-blue: #4a8bee;
$layout-link-gray: #7e7c7c;
$todo-alert-blue: #428bca;
-$btn-side-margin: 7px;
-$btn-sm-side-margin: 5px;
+$btn-side-margin: 10px;
+$btn-sm-side-margin: 7px;
$btn-xs-side-margin: 5px;
/*
diff --git a/app/assets/stylesheets/pages/labels.scss b/app/assets/stylesheets/pages/labels.scss
index 26128fcea85..bc65404a741 100644
--- a/app/assets/stylesheets/pages/labels.scss
+++ b/app/assets/stylesheets/pages/labels.scss
@@ -50,11 +50,26 @@
.label-row {
.label-name {
- display: inline-block;
- width: 170px;
+ display: block;
+ margin-bottom: 10px;
- @media (max-width: $screen-xs-min) {
- display: block;
+ @media (min-width: $screen-sm-min) {
+ display: inline-block;
+ width: 200px;
+ margin-bottom: 0;
+ }
+ }
+
+ .label-description {
+ display: block;
+ margin-bottom: 10px;
+
+ @media (min-width: $screen-sm-min) {
+ display: inline-block;
+ width: 40%;
+ margin-left: 10px;
+ margin-bottom: 0;
+ vertical-align: middle;
}
}
@@ -68,10 +83,6 @@
padding: 3px 4px;
}
-.label-subscription {
- display: inline-block;
-}
-
.dropdown-labels-error {
padding: 5px 10px;
margin-bottom: 10px;
@@ -79,62 +90,27 @@
color: $white-light;
}
-@mixin labels-mobile {
- @media (max-width: $screen-xs-min) {
- display: block;
- width: 100%;
- margin-left: 0;
- padding: 10px 0;
- }
-}
-
-
.manage-labels-list {
+ .btn-action {
+ color: $gl-dark-link-color;
- .prepend-left-10, .prepend-description-left {
- display: inline-block;
- width: 40%;
- vertical-align: middle;
-
- @include labels-mobile;
- }
-
- .prepend-description-left {
- width: 57%;
-
- @include labels-mobile;
- }
-
- .pull-info-right {
- float: right;
-
- @media (max-width: $screen-xs-min) {
- float: none;
+ .fa {
+ font-size: 18px;
+ vertical-align: middle;
}
- .action-buttons {
- border-color: transparent;
- padding: 6px;
- color: $gl-text-color;
+ &:hover {
+ color: $gl-link-color;
- &.label-subscribe-button {
- padding-left: 0;
+ &.remove-row {
+ color: $gl-danger;
}
}
+ }
- i {
- color: $gl-text-color;
- }
-
- .append-right-20 {
- a {
- color: $gl-text-color;
- }
-
- @media (max-width: $screen-xs-min) {
- display: block;
- margin-bottom: 10px;
- }
+ .dropdown {
+ @media (min-width: $screen-sm-min) {
+ float: right;
}
}
}
@@ -186,3 +162,23 @@
color: inherit;
}
}
+
+.label-options-toggle {
+ width: 100%;
+}
+
+.label-subscribe-button {
+ .label-subscribe-button-loading {
+ display: none;
+ }
+
+ &.disabled {
+ .label-subscribe-button-icon {
+ display: none;
+ }
+
+ .label-subscribe-button-loading {
+ display: block;
+ }
+ }
+}
diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss
index bf7334a8942..a47f2580aa3 100644
--- a/app/assets/stylesheets/pages/merge_requests.scss
+++ b/app/assets/stylesheets/pages/merge_requests.scss
@@ -108,6 +108,11 @@
font-size: 17px;
margin: 5px 0;
color: $gl-gray-dark;
+
+ &.has-conflicts .fa-exclamation-triangle {
+ color: $gl-warning;
+ }
+
}
p:last-child {
diff --git a/app/assets/stylesheets/pages/note_form.scss b/app/assets/stylesheets/pages/note_form.scss
index a6765fbc7c7..577dddae741 100644
--- a/app/assets/stylesheets/pages/note_form.scss
+++ b/app/assets/stylesheets/pages/note_form.scss
@@ -129,17 +129,8 @@
display: none;
font-size: 15px;
- .form-actions {
- padding-left: 20px;
-
- .btn-save {
- float: left;
- }
-
- .note-form-option {
- float: left;
- padding: 2px 0 0 25px;
- }
+ .md-area {
+ background-color: #fff;
}
}
diff --git a/app/helpers/labels_helper.rb b/app/helpers/labels_helper.rb
index c99b137cdaa..5074e645769 100644
--- a/app/helpers/labels_helper.rb
+++ b/app/helpers/labels_helper.rb
@@ -32,7 +32,7 @@ module LabelsHelper
# link_to_label(label) { "My Custom Label Text" }
#
# Returns a String
- def link_to_label(label, project: nil, type: :issue, tooltip: true, &block)
+ def link_to_label(label, project: nil, type: :issue, tooltip: true, css_class: nil, &block)
project ||= @project || label.project
link = send("namespace_project_#{type.to_s.pluralize}_path",
project.namespace,
@@ -40,9 +40,9 @@ module LabelsHelper
label_name: [label.name])
if block_given?
- link_to link, &block
+ link_to link, class: css_class, &block
else
- link_to render_colored_label(label, tooltip: tooltip), link
+ link_to render_colored_label(label, tooltip: tooltip), link, class: css_class
end
end
diff --git a/app/helpers/milestones_helper.rb b/app/helpers/milestones_helper.rb
index 87fc2db6901..b3e6e468ecd 100644
--- a/app/helpers/milestones_helper.rb
+++ b/app/helpers/milestones_helper.rb
@@ -56,7 +56,7 @@ module MilestonesHelper
def milestone_remaining_days(milestone)
if milestone.expired?
- content_tag(:strong, 'expired')
+ content_tag(:strong, 'Past due')
elsif milestone.due_date
days = milestone.remaining_days
content = content_tag(:strong, days)
diff --git a/app/services/todo_service.rb b/app/services/todo_service.rb
index d8365124175..8e03ff8ddde 100644
--- a/app/services/todo_service.rb
+++ b/app/services/todo_service.rb
@@ -20,7 +20,7 @@ class TodoService
# * mark all pending todos related to the issue for the current user as done
#
def update_issue(issue, current_user)
- create_mention_todos(issue.project, issue, current_user)
+ update_issuable(issue, current_user)
end
# When close an issue we should:
@@ -53,7 +53,7 @@ class TodoService
# * create a todo for each mentioned user on merge request
#
def update_merge_request(merge_request, current_user)
- create_mention_todos(merge_request.project, merge_request, current_user)
+ update_issuable(merge_request, current_user)
end
# When close a merge request we should:
@@ -153,6 +153,13 @@ class TodoService
create_mention_todos(issuable.project, issuable, author)
end
+ def update_issuable(issuable, author)
+ # Skip toggling a task list item in a description
+ return if issuable.tasks? && issuable.updated_tasks.any?
+
+ create_mention_todos(issuable.project, issuable, author)
+ end
+
def handle_note(note, author)
# Skip system notes, and notes on project snippet
return if note.system? || note.for_snippet?
diff --git a/app/views/award_emoji/_awards_block.html.haml b/app/views/award_emoji/_awards_block.html.haml
index 84fd146a26b..02efcecc889 100644
--- a/app/views/award_emoji/_awards_block.html.haml
+++ b/app/views/award_emoji/_awards_block.html.haml
@@ -7,9 +7,6 @@
= awards.count
- if current_user
- :javascript
- gl.awardMenuUrl = "#{emojis_path}"
-
.award-menu-holder.js-award-holder
%button.btn.award-control.js-add-award{ type: "button" }
= icon('smile-o', class: "award-control-icon award-control-icon-normal")
diff --git a/app/views/devise/sessions/two_factor.html.haml b/app/views/devise/sessions/two_factor.html.haml
index 9d04db2c45e..a373f61bd3c 100644
--- a/app/views/devise/sessions/two_factor.html.haml
+++ b/app/views/devise/sessions/two_factor.html.haml
@@ -6,7 +6,8 @@
- if @user.two_factor_otp_enabled?
%h5 Authenticate via Two-Factor App
= form_for(resource, as: resource_name, url: session_path(resource_name), method: :post) do |f|
- = f.hidden_field :remember_me, value: params[resource_name][:remember_me]
+ - resource_params = params[resource_name].presence || params
+ = f.hidden_field :remember_me, value: resource_params.fetch(:remember_me, 0)
= f.text_field :otp_attempt, class: 'form-control', placeholder: 'Two-Factor Authentication code', required: true, autofocus: true, autocomplete: 'off'
%p.help-block.hint Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes.
.prepend-top-20
diff --git a/app/views/groups/group_members/_group_member.html.haml b/app/views/groups/group_members/_group_member.html.haml
index 271700e6db4..6bb542e658d 100644
--- a/app/views/groups/group_members/_group_member.html.haml
+++ b/app/views/groups/group_members/_group_member.html.haml
@@ -34,7 +34,7 @@
%strong.member-access-level= member.human_access
- if show_controls
- if can?(current_user, :update_group_member, member)
- = button_tag class: "btn-xs btn js-toggle-button",
+ = button_tag class: "btn-xs btn btn-grouped inline js-toggle-button",
title: 'Edit access level', type: 'button' do
= icon('pencil')
diff --git a/app/views/groups/milestones/new.html.haml b/app/views/groups/milestones/new.html.haml
index 7d9d27ae1fc..ca6c4326d1c 100644
--- a/app/views/groups/milestones/new.html.haml
+++ b/app/views/groups/milestones/new.html.haml
@@ -39,9 +39,8 @@
.col-md-6
.form-group
= f.label :due_date, "Due Date", class: "control-label"
- .col-sm-10= f.hidden_field :due_date
.col-sm-10
- .datepicker
+ = f.text_field :due_date, class: "datepicker form-control", placeholder: "Select due date"
.form-actions
= f.submit 'Create Milestone', class: "btn-create btn"
diff --git a/app/views/projects/branches/index.html.haml b/app/views/projects/branches/index.html.haml
index 0d59c3884cd..e0367c40272 100644
--- a/app/views/projects/branches/index.html.haml
+++ b/app/views/projects/branches/index.html.haml
@@ -3,31 +3,30 @@
= render "projects/commits/head"
%div{ class: (container_class) }
- .row-content-block.second-block.content-component-block
- .pull-right
- - if can? current_user, :push_code, @project
+ .top-area
+ .nav-text
+ Protected branches can be managed in project settings
+
+ - if can? current_user, :push_code, @project
+ .nav-controls
= link_to new_namespace_project_branch_path(@project.namespace, @project), class: 'btn btn-create' do
- = icon('plus')
New branch
- &nbsp;
- .dropdown.inline
- %button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'}
- %span.light
- - if @sort.present?
- = @sort.humanize
- - else
- Name
- %b.caret
- %ul.dropdown-menu.dropdown-menu-align-right
- %li
- = link_to namespace_project_branches_path(sort: nil) do
+ .dropdown.inline
+ %button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'}
+ %span.light
+ - if @sort.present?
+ = @sort.humanize
+ - else
Name
- = link_to namespace_project_branches_path(sort: 'recently_updated') do
- = sort_title_recently_updated
- = link_to namespace_project_branches_path(sort: 'last_updated') do
- = sort_title_oldest_updated
- .oneline
- Protected branches can be managed in project settings
+ %b.caret
+ %ul.dropdown-menu.dropdown-menu-align-right
+ %li
+ = link_to namespace_project_branches_path(sort: nil) do
+ Name
+ = link_to namespace_project_branches_path(sort: 'recently_updated') do
+ = sort_title_recently_updated
+ = link_to namespace_project_branches_path(sort: 'last_updated') do
+ = sort_title_oldest_updated
- unless @branches.empty?
%ul.content-list.all-branches
- @branches.each do |branch|
diff --git a/app/views/projects/builds/index.html.haml b/app/views/projects/builds/index.html.haml
index 55d2ac89ebc..181547316aa 100644
--- a/app/views/projects/builds/index.html.haml
+++ b/app/views/projects/builds/index.html.haml
@@ -34,7 +34,6 @@
= link_to 'Get started with Builds', help_page_path('ci/quick_start', 'README'), class: 'btn btn-info'
= link_to ci_lint_path, class: 'btn btn-default' do
- = icon('wrench')
%span CI Lint
%ul.content-list
diff --git a/app/views/projects/issues/index.html.haml b/app/views/projects/issues/index.html.haml
index 2a4027a6ecb..7c1457553d9 100644
--- a/app/views/projects/issues/index.html.haml
+++ b/app/views/projects/issues/index.html.haml
@@ -12,7 +12,7 @@
= icon('rss')
%span.icon-label
Subscribe
- = render 'shared/issuable/search_form', path: namespace_project_issues_path(@project.namespace, @project)
+ = render 'shared/issuable/search_form', path: namespace_project_issues_path(@project.namespace, @project)
- if can? current_user, :create_issue, @project
= link_to new_namespace_project_issue_path(@project.namespace, @project, issue: { assignee_id: @issuable_finder.assignee.try(:id), milestone_id: @issuable_finder.milestones.try(:first).try(:id) }), class: "btn btn-new", title: "New Issue", id: "new_issue_link" do
New Issue
diff --git a/app/views/projects/labels/_label.html.haml b/app/views/projects/labels/_label.html.haml
index 1c51ea676c7..73c6f2a046c 100644
--- a/app/views/projects/labels/_label.html.haml
+++ b/app/views/projects/labels/_label.html.haml
@@ -1,28 +1,50 @@
- label_css_id = dom_id(label)
%li{id: label_css_id, data: { id: label.id } }
= render "shared/label_row", label: label
- .pull-info-right
- %span.append-right-20
- = link_to_label(label, type: :merge_request) do
- = pluralize label.open_merge_requests_count, 'merge request'
- %span.append-right-20
- = link_to_label(label) do
- = pluralize label.open_issues_count(current_user), 'open issue'
+ .visible-xs.visible-sm-inline-block.visible-md-inline-block.dropdown
+ %button.btn.btn-default.label-options-toggle{ data: { toggle: "dropdown" } }
+ Options
+ %span.caret
+ .dropdown-menu.dropdown-menu-align-right
+ %ul
+ %li
+ = link_to_label(label, type: :merge_request) do
+ = pluralize label.open_merge_requests_count, 'merge request'
+ %li
+ = link_to_label(label) do
+ = pluralize label.open_issues_count(current_user), 'open issue'
+ - if current_user
+ %li.label-subscription{ data: { url: toggle_subscription_namespace_project_label_path(@project.namespace, @project, label) } }
+ %a.js-subscribe-button.label-subscribe-button.subscription-status{ role: "button", href: "#", data: { toggle: "tooltip", status: label_subscription_status(label) } }
+ %span= label_subscription_toggle_button_text(label)
+ - if can? current_user, :admin_label, @project
+ %li
+ = link_to "Edit", edit_namespace_project_label_path(@project.namespace, @project, label)
+ %li
+ = link_to "Delete", namespace_project_label_path(@project.namespace, @project, label), title: "Delete", method: :delete, remote: true, data: {confirm: "Remove this label? Are you sure?"}
- - if current_user
- .label-subscription{ data: { url: toggle_subscription_namespace_project_label_path(@project.namespace, @project, label) } }
- .subscription-status{ data: { status: label_subscription_status(label) } }
+ .pull-right.hidden-xs.hidden-sm.hidden-md
+ = link_to_label(label, type: :merge_request, css_class: 'btn btn-transparent btn-action') do
+ = pluralize label.open_merge_requests_count, 'merge request'
+ = link_to_label(label, css_class: 'btn btn-transparent btn-action') do
+ = pluralize label.open_issues_count(current_user), 'open issue'
- %button.js-subscribe-button.label-subscribe-button.btn.action-buttons{ type: "button", data: { toggle: "tooltip" } }
- %span= label_subscription_toggle_button_text(label)
+ - if current_user
+ .label-subscription.inline{ data: { url: toggle_subscription_namespace_project_label_path(@project.namespace, @project, label) } }
+ %button.js-subscribe-button.label-subscribe-button.btn.btn-transparent.btn-action.subscription-status{ type: "button", title: label_subscription_toggle_button_text(label), data: { toggle: "tooltip", status: label_subscription_status(label) } }
+ %span.sr-only= label_subscription_toggle_button_text(label)
+ = icon('eye', class: 'label-subscribe-button-icon')
+ = icon('spinner spin', class: 'label-subscribe-button-loading')
- - if can?(current_user, :admin_label, @project)
- = link_to edit_namespace_project_label_path(@project.namespace, @project, label), title: "Edit", class: 'btn action-buttons', data: { toggle: 'tooltip' } do
- %i.fa.fa-pencil-square-o
- = link_to namespace_project_label_path(@project.namespace, @project, label), title: "Delete", class: 'btn action-buttons remove-row', method: :delete, remote: true, data: { confirm: 'Remove this label? Are you sure?', toggle: 'tooltip' } do
- %i.fa.fa-trash-o
+ - if can? current_user, :admin_label, @project
+ = link_to edit_namespace_project_label_path(@project.namespace, @project, label), title: "Edit", class: 'btn btn-transparent btn-action', data: {toggle: "tooltip"} do
+ %span.sr-only Edit
+ = icon('pencil-square-o')
+ = link_to namespace_project_label_path(@project.namespace, @project, label), title: "Delete", class: 'btn btn-transparent btn-action remove-row', method: :delete, remote: true, data: {confirm: "Remove this label? Are you sure?", toggle: "tooltip"} do
+ %span.sr-only Delete
+ = icon('trash-o')
-- if current_user
- :javascript
- new Subscription('##{label_css_id} .label-subscription');
+ - if current_user
+ :javascript
+ new Subscription('##{dom_id(label)} .label-subscription');
diff --git a/app/views/projects/merge_requests/widget/open/_conflicts.html.haml b/app/views/projects/merge_requests/widget/open/_conflicts.html.haml
index e6c089fefb2..06ab0a3fa00 100644
--- a/app/views/projects/merge_requests/widget/open/_conflicts.html.haml
+++ b/app/views/projects/merge_requests/widget/open/_conflicts.html.haml
@@ -1,9 +1,9 @@
-%h4
+%h4.has-conflicts
= icon("exclamation-triangle")
This merge request contains merge conflicts
%p
- Please resolve these conflicts or
+ Please resolve these conflicts or
- if @merge_request.can_be_merged_by?(current_user)
#{link_to "merge this request manually", "#modal_merge_info", class: "how_to_merge_link vlink", "data-toggle" => "modal"}.
- else
diff --git a/app/views/projects/milestones/_form.html.haml b/app/views/projects/milestones/_form.html.haml
index 687222fa92f..f5e2b927da8 100644
--- a/app/views/projects/milestones/_form.html.haml
+++ b/app/views/projects/milestones/_form.html.haml
@@ -17,9 +17,8 @@
.col-md-6
.form-group
= f.label :due_date, "Due Date", class: "control-label"
- .col-sm-10= f.hidden_field :due_date
.col-sm-10
- .datepicker
+ = f.text_field :due_date, class: "datepicker form-control", placeholder: "Select due date"
.form-actions
- if @milestone.new_record?
diff --git a/app/views/projects/milestones/index.html.haml b/app/views/projects/milestones/index.html.haml
index e6133b22f96..60a5b83434e 100644
--- a/app/views/projects/milestones/index.html.haml
+++ b/app/views/projects/milestones/index.html.haml
@@ -6,7 +6,6 @@
.nav-controls
- if can?(current_user, :admin_milestone, @project)
= link_to new_namespace_project_milestone_path(@project.namespace, @project), class: "btn btn-new", title: "New Milestone" do
- = icon('plus')
New Milestone
.milestones
diff --git a/app/views/projects/milestones/show.html.haml b/app/views/projects/milestones/show.html.haml
index 19944e3e023..73772cc0e32 100644
--- a/app/views/projects/milestones/show.html.haml
+++ b/app/views/projects/milestones/show.html.haml
@@ -6,7 +6,7 @@
- if @milestone.closed?
Closed
- elsif @milestone.expired?
- Expired
+ Past due
- else
Open
%span.identifier
@@ -23,11 +23,9 @@
= link_to 'Reopen Milestone', namespace_project_milestone_path(@project.namespace, @project, @milestone, milestone: {state_event: :activate }), method: :put, class: "btn btn-reopen btn-nr btn-grouped"
= link_to edit_namespace_project_milestone_path(@project.namespace, @project, @milestone), class: "btn btn-grouped btn-nr" do
- = icon('pencil-square-o')
Edit
= link_to namespace_project_milestone_path(@project.namespace, @project, @milestone), data: { confirm: 'Are you sure?' }, method: :delete, class: "btn btn-grouped btn-danger" do
- = icon('trash-o')
Delete
.detail-page-description.milestone-detail
diff --git a/app/views/projects/pipelines/index.html.haml b/app/views/projects/pipelines/index.html.haml
index a78450e09d4..b70693eeb62 100644
--- a/app/views/projects/pipelines/index.html.haml
+++ b/app/views/projects/pipelines/index.html.haml
@@ -28,14 +28,12 @@
.nav-controls
- if can? current_user, :create_pipeline, @project
= link_to new_namespace_project_pipeline_path(@project.namespace, @project), class: 'btn btn-create' do
- = icon('plus')
New pipeline
- unless @repository.gitlab_ci_yml
= link_to 'Get started with Pipelines', help_page_path('ci/quick_start', 'README'), class: 'btn btn-info'
= link_to ci_lint_path, class: 'btn btn-default' do
- = icon('wrench')
%span CI Lint
%ul.content-list.pipelines
diff --git a/app/views/projects/project_members/_project_member.html.haml b/app/views/projects/project_members/_project_member.html.haml
index 1e53b8e37da..268f140d7db 100644
--- a/app/views/projects/project_members/_project_member.html.haml
+++ b/app/views/projects/project_members/_project_member.html.haml
@@ -32,7 +32,7 @@
.pull-right
%strong= member.human_access
- if can?(current_user, :update_project_member, member)
- = button_tag class: "btn-xs btn js-toggle-button",
+ = button_tag class: "btn-xs btn-grouped inline btn js-toggle-button",
title: 'Edit access level', type: 'button' do
= icon('pencil')
diff --git a/app/views/projects/tags/_download.html.haml b/app/views/projects/tags/_download.html.haml
index 093d1d1bb0f..8a11dbfa9f4 100644
--- a/app/views/projects/tags/_download.html.haml
+++ b/app/views/projects/tags/_download.html.haml
@@ -1,7 +1,6 @@
-%span.btn-group.btn-grouped
+%span.btn-group
= link_to archive_namespace_project_repository_path(project.namespace, project, ref: ref, format: 'zip'), class: 'btn btn-default', rel: 'nofollow' do
- %i.fa.fa-download
- %span source code
+ %span Source code
%a.btn.btn-default.dropdown-toggle{ 'data-toggle' => 'dropdown' }
%span.caret
%span.sr-only
@@ -9,9 +8,7 @@
%ul.dropdown-menu.dropdown-menu-align-right{ role: 'menu' }
%li
= link_to archive_namespace_project_repository_path(project.namespace, project, ref: ref, format: 'zip'), rel: 'nofollow' do
- %i.fa.fa-download
%span Download zip
%li
= link_to archive_namespace_project_repository_path(project.namespace, project, ref: ref, format: 'tar.gz'), rel: 'nofollow' do
- %i.fa.fa-download
%span Download tar.gz
diff --git a/app/views/projects/tags/_tag.html.haml b/app/views/projects/tags/_tag.html.haml
index dbc35c16feb..844e1055810 100644
--- a/app/views/projects/tags/_tag.html.haml
+++ b/app/views/projects/tags/_tag.html.haml
@@ -15,11 +15,11 @@
= render 'projects/tags/download', ref: tag.name, project: @project
- if can?(current_user, :push_code, @project)
- = link_to edit_namespace_project_tag_release_path(@project.namespace, @project, tag.name), class: 'btn-grouped btn has-tooltip', title: "Edit release notes" do
+ = link_to edit_namespace_project_tag_release_path(@project.namespace, @project, tag.name), class: 'btn has-tooltip', title: "Edit release notes" do
= icon("pencil")
- if can?(current_user, :admin_project, @project)
- = link_to namespace_project_tag_path(@project.namespace, @project, tag.name), class: 'btn btn-grouped btn-xs btn-remove remove-row has-tooltip', title: "Delete tag", method: :delete, data: { confirm: "Deleting the '#{tag.name}' tag cannot be undone. Are you sure?", container: 'body' }, remote: true do
+ = link_to namespace_project_tag_path(@project.namespace, @project, tag.name), class: 'btn btn-remove remove-row has-tooltip', title: "Delete tag", method: :delete, data: { confirm: "Deleting the '#{tag.name}' tag cannot be undone. Are you sure?", container: 'body' }, remote: true do
= icon("trash-o")
- if commit
diff --git a/app/views/projects/tags/index.html.haml b/app/views/projects/tags/index.html.haml
index 9ff805a8989..2779084fe38 100644
--- a/app/views/projects/tags/index.html.haml
+++ b/app/views/projects/tags/index.html.haml
@@ -3,14 +3,14 @@
= render "projects/commits/head"
%div{ class: (container_class) }
- .row-content-block.second-block.content-component-block
+ .top-area
+ .nav-text
+ Tags give the ability to mark specific points in history as being important
+
- if can? current_user, :push_code, @project
- .pull-right
+ .nav-controls
= link_to new_namespace_project_tag_path(@project.namespace, @project), class: 'btn btn-create new-tag-btn' do
- = icon('plus')
New tag
- .oneline
- Tags give the ability to mark specific points in history as being important
.tags
- unless @tags.empty?
diff --git a/app/views/projects/wikis/_main_links.html.haml b/app/views/projects/wikis/_main_links.html.haml
index 2b91b7e8f65..4faa547769b 100644
--- a/app/views/projects/wikis/_main_links.html.haml
+++ b/app/views/projects/wikis/_main_links.html.haml
@@ -1,11 +1,9 @@
- if (@page && @page.persisted?)
- = link_to namespace_project_wiki_history_path(@project.namespace, @project, @page), class: "btn btn-grouped" do
+ = link_to namespace_project_wiki_history_path(@project.namespace, @project, @page), class: "btn" do
Page History
- if can?(current_user, :create_wiki, @project)
- = link_to namespace_project_wiki_edit_path(@project.namespace, @project, @page), class: "btn btn-grouped" do
- %i.fa.fa-pencil-square-o
+ = link_to namespace_project_wiki_edit_path(@project.namespace, @project, @page), class: "btn" do
Edit
- if can?(current_user, :admin_wiki, @project)
= link_to namespace_project_wiki_path(@project.namespace, @project, @page), data: { confirm: "Are you sure you want to delete this page?"}, method: :delete, class: "btn btn-remove" do
- = icon('trash')
Delete
diff --git a/app/views/projects/wikis/_nav.html.haml b/app/views/projects/wikis/_nav.html.haml
index a722fbc5352..988fe024e28 100644
--- a/app/views/projects/wikis/_nav.html.haml
+++ b/app/views/projects/wikis/_nav.html.haml
@@ -13,7 +13,6 @@
.nav-controls
- if can?(current_user, :create_wiki, @project)
= link_to '#modal-new-wiki', class: "add-new-wiki btn btn-new", "data-toggle" => "modal" do
- = icon('plus')
New Page
= render 'projects/wikis/new'
diff --git a/app/views/shared/_label_row.html.haml b/app/views/shared/_label_row.html.haml
index d315a3fe93b..478c04318c6 100644
--- a/app/views/shared/_label_row.html.haml
+++ b/app/views/shared/_label_row.html.haml
@@ -8,5 +8,6 @@
= icon('star')
%span.label-name
= link_to_label(label, tooltip: false)
- %span.prepend-left-10
- = markdown(label.description, pipeline: :single_line)
+ - if label.description
+ %span.label-description
+ = markdown(label.description, pipeline: :single_line)
diff --git a/app/views/shared/groups/_group.html.haml b/app/views/shared/groups/_group.html.haml
index 40c6eb9be45..a25365a94f2 100644
--- a/app/views/shared/groups/_group.html.haml
+++ b/app/views/shared/groups/_group.html.haml
@@ -6,10 +6,10 @@
- if group_member
.controls.hidden-xs
- if can?(current_user, :admin_group, group)
- = link_to edit_group_path(group), class: "btn-sm btn btn-grouped" do
- %i.fa.fa-cogs
+ = link_to edit_group_path(group), class: "btn" do
+ = icon('cogs')
- = link_to leave_group_group_members_path(group), data: { confirm: leave_group_message(group.name) }, method: :delete, class: "btn-sm btn btn-grouped", title: 'Leave this group' do
+ = link_to leave_group_group_members_path(group), data: { confirm: leave_group_message(group.name) }, method: :delete, class: "btn", title: 'Leave this group' do
= icon('sign-out')
.stats
diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml
index b430251dbf6..17e2a7e9290 100644
--- a/app/views/shared/issuable/_form.html.haml
+++ b/app/views/shared/issuable/_form.html.haml
@@ -88,9 +88,9 @@
.col-lg-6
.form-group
= f.label :due_date, "Due date", class: "control-label"
- = f.hidden_field :due_date, id: "issuable-due-date"
.col-sm-10
- .datepicker
+ .issuable-form-select-holder
+ = f.text_field :due_date, id: "issuable-due-date", class: "datepicker form-control", placeholder: "Select due date"
- if issuable.can_move?(current_user)
%hr
diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml
index c7991d53a09..fb906de829a 100644
--- a/app/views/shared/issuable/_sidebar.html.haml
+++ b/app/views/shared/issuable/_sidebar.html.haml
@@ -41,7 +41,8 @@
= icon('clock-o')
%span
- if issuable.milestone
- = issuable.milestone.title
+ %span.has-tooltip{title: milestone_remaining_days(issuable.milestone), data: {container: 'body', html: 1, placement: 'left'}}
+ = issuable.milestone.title
- else
None
.title.hide-collapsed
@@ -52,7 +53,8 @@
.value.bold.hide-collapsed
- if issuable.milestone
= link_to namespace_project_milestone_path(@project.namespace, @project, issuable.milestone) do
- = issuable.milestone.title
+ %span.has-tooltip{title: milestone_remaining_days(issuable.milestone), data: {container: 'body', html: 1}}
+ = issuable.milestone.title
- else
.light None
diff --git a/app/views/shared/milestones/_milestone.html.haml b/app/views/shared/milestones/_milestone.html.haml
index 6b25745c554..acc3ccf4dcf 100644
--- a/app/views/shared/milestones/_milestone.html.haml
+++ b/app/views/shared/milestones/_milestone.html.haml
@@ -35,11 +35,9 @@
.col-sm-6= render('shared/milestone_expired', milestone: milestone)
.col-sm-6
- if can?(current_user, :admin_milestone, milestone.project) and milestone.active?
- = link_to edit_namespace_project_milestone_path(milestone.project.namespace, milestone.project, milestone), class: "btn btn-xs" do
- = icon('pencil-square-o')
+ = link_to edit_namespace_project_milestone_path(milestone.project.namespace, milestone.project, milestone), class: "btn btn-xs btn-grouped" do
Edit
\
- = link_to 'Close Milestone', namespace_project_milestone_path(@project.namespace, @project, milestone, milestone: {state_event: :close }), method: :put, remote: true, class: "btn btn-xs btn-close"
- = link_to namespace_project_milestone_path(milestone.project.namespace, milestone.project, milestone), data: { confirm: 'Are you sure?' }, method: :delete, class: "btn btn-xs btn-remove" do
- = icon('trash-o')
+ = link_to 'Close Milestone', namespace_project_milestone_path(@project.namespace, @project, milestone, milestone: {state_event: :close }), method: :put, remote: true, class: "btn btn-xs btn-close btn-grouped"
+ = link_to namespace_project_milestone_path(milestone.project.namespace, milestone.project, milestone), data: { confirm: 'Are you sure?' }, method: :delete, class: "btn btn-xs btn-remove btn-grouped" do
Delete
diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml
index 8268380dafc..92305594a81 100644
--- a/app/views/users/show.html.haml
+++ b/app/views/users/show.html.haml
@@ -79,10 +79,10 @@
%li.js-contributed-tab
= link_to user_contributed_projects_path, data: {target: 'div#contributed', action: 'contributed', toggle: 'tab'} do
Contributed projects
- %li.projects-tab
+ %li.js-projects-tab
= link_to user_projects_path, data: {target: 'div#projects', action: 'projects', toggle: 'tab'} do
Personal projects
- %li.snippets-tab
+ %li.js-snippets-tab
= link_to user_snippets_path, data: {target: 'div#snippets', action: 'snippets', toggle: 'tab'} do
Snippets
diff --git a/features/steps/project/issues/labels.rb b/features/steps/project/issues/labels.rb
index e02b57bbf84..2937d5d7ca8 100644
--- a/features/steps/project/issues/labels.rb
+++ b/features/steps/project/issues/labels.rb
@@ -9,7 +9,7 @@ class Spinach::Features::ProjectIssuesLabels < Spinach::FeatureSteps
step 'I remove label \'bug\'' do
page.within "#label_#{bug_label.id}" do
- click_link 'Delete'
+ first(:link, 'Delete').click
end
end
diff --git a/features/steps/project/labels.rb b/features/steps/project/labels.rb
index 5bb02189021..118ffef4774 100644
--- a/features/steps/project/labels.rb
+++ b/features/steps/project/labels.rb
@@ -29,6 +29,6 @@ class Spinach::Features::Labels < Spinach::FeatureSteps
private
def subscribe_button
- first('.label-subscribe-button span')
+ first('.js-subscribe-button', visible: true)
end
end
diff --git a/lib/gitlab/gon_helper.rb b/lib/gitlab/gon_helper.rb
index ab900b641c4..f751a3a12fd 100644
--- a/lib/gitlab/gon_helper.rb
+++ b/lib/gitlab/gon_helper.rb
@@ -8,6 +8,7 @@ module Gitlab
gon.relative_url_root = Gitlab.config.gitlab.relative_url_root
gon.shortcuts_path = help_shortcuts_path
gon.user_color_scheme = Gitlab::ColorSchemes.for_user(current_user).css_class
+ gon.award_menu_url = emojis_path
if current_user
gon.current_user_id = current_user.id
diff --git a/lib/tasks/gitlab/db.rake b/lib/tasks/gitlab/db.rake
index 86584e91093..7230b9485be 100644
--- a/lib/tasks/gitlab/db.rake
+++ b/lib/tasks/gitlab/db.rake
@@ -34,7 +34,7 @@ namespace :gitlab do
# PG: http://www.postgresql.org/docs/current/static/ddl-depend.html
# MySQL: http://dev.mysql.com/doc/refman/5.7/en/drop-table.html
# Add `IF EXISTS` because cascade could have already deleted a table.
- tables.each { |t| connection.execute("DROP TABLE IF EXISTS #{t} CASCADE") }
+ tables.each { |t| connection.execute("DROP TABLE IF EXISTS #{connection.quote_table_name(t)} CASCADE") }
end
desc 'Configures the database by running migrate, or by loading the schema and seeding if needed'
diff --git a/spec/features/dashboard/datetime_on_tooltips_spec.rb b/spec/features/dashboard/datetime_on_tooltips_spec.rb
new file mode 100644
index 00000000000..365cb445df1
--- /dev/null
+++ b/spec/features/dashboard/datetime_on_tooltips_spec.rb
@@ -0,0 +1,46 @@
+require 'spec_helper'
+
+feature 'Tooltips on .timeago dates', feature: true, js: true do
+ include WaitForAjax
+
+ let(:user) { create(:user) }
+ let(:project) { create(:project, name: 'test', namespace: user.namespace) }
+ let(:created_date) { Date.yesterday.to_time }
+ let(:expected_format) { created_date.strftime('%b %-d, %Y %l:%M%P UTC') }
+
+ context 'on the activity tab' do
+ before do
+ project.team << [user, :master]
+
+ Event.create( project: project, author_id: user.id, action: Event::JOINED,
+ updated_at: created_date, created_at: created_date)
+
+ login_as user
+ visit user_path(user)
+ wait_for_ajax()
+
+ page.find('.js-timeago').hover
+ end
+
+ it 'has the datetime formated correctly' do
+ expect(page).to have_selector('.local-timeago', text: expected_format)
+ end
+ end
+
+ context 'on the snippets tab' do
+ before do
+ project.team << [user, :master]
+ create(:snippet, author: user, updated_at: created_date, created_at: created_date)
+
+ login_as user
+ visit user_snippets_path(user)
+ wait_for_ajax()
+
+ page.find('.js-timeago').hover
+ end
+
+ it 'has the datetime formated correctly' do
+ expect(page).to have_selector('.local-timeago', text: expected_format)
+ end
+ end
+end
diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb
index 460d7f82b36..f6fb6a72d22 100644
--- a/spec/features/issues_spec.rb
+++ b/spec/features/issues_spec.rb
@@ -75,12 +75,13 @@ describe 'Issues', feature: true do
fill_in 'issue_title', with: 'bug 345'
fill_in 'issue_description', with: 'bug description'
+ find('#issuable-due-date').click
- page.within '.datepicker' do
+ page.within '.ui-datepicker' do
click_link date.day
end
- expect(find('#issuable-due-date', visible: false).value).to eq date.to_s
+ expect(find('#issuable-due-date').value).to eq date.to_s
click_button 'Submit issue'
@@ -100,18 +101,19 @@ describe 'Issues', feature: true do
it 'should save with due date' do
date = Date.today.at_beginning_of_month
- expect(find('#issuable-due-date', visible: false).value).to eq date.to_s
+ expect(find('#issuable-due-date').value).to eq date.to_s
date = date.tomorrow
fill_in 'issue_title', with: 'bug 345'
fill_in 'issue_description', with: 'bug description'
+ find('#issuable-due-date').click
- page.within '.datepicker' do
+ page.within '.ui-datepicker' do
click_link date.day
end
- expect(find('#issuable-due-date', visible: false).value).to eq date.to_s
+ expect(find('#issuable-due-date').value).to eq date.to_s
click_button 'Save changes'
diff --git a/spec/javascripts/awards_handler_spec.js.coffee b/spec/javascripts/awards_handler_spec.js.coffee
index 0bd6d696387..ba191199dc7 100644
--- a/spec/javascripts/awards_handler_spec.js.coffee
+++ b/spec/javascripts/awards_handler_spec.js.coffee
@@ -3,10 +3,11 @@
#= require jquery.cookie
#= require ./fixtures/emoji_menu
-awardsHandler = null
-window.gl or= {}
-gl.emojiAliases = -> return { '+1': 'thumbsup', '-1': 'thumbsdown' }
-gl.awardMenuUrl = '/emojis'
+awardsHandler = null
+window.gl or= {}
+window.gon or= {}
+gl.emojiAliases = -> return { '+1': 'thumbsup', '-1': 'thumbsdown' }
+gon.award_menu_url = '/emojis'
lazyAssert = (done, assertFn) ->
@@ -25,9 +26,7 @@ describe 'AwardsHandler', ->
fixture.load 'awards_handler.html'
awardsHandler = new AwardsHandler
spyOn(awardsHandler, 'postEmoji').and.callFake (url, emoji, cb) => cb()
- spyOn(jQuery, 'get').and.callFake (req, cb) ->
- expect(req).toBe '/emojis'
- cb window.emojiMenu
+ spyOn(jQuery, 'get').and.callFake (req, cb) -> cb window.emojiMenu
describe '::showEmojiMenu', ->
diff --git a/spec/lib/disable_email_interceptor_spec.rb b/spec/lib/disable_email_interceptor_spec.rb
index c2a7b20b84d..309a88151cf 100644
--- a/spec/lib/disable_email_interceptor_spec.rb
+++ b/spec/lib/disable_email_interceptor_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe DisableEmailInterceptor, lib: true do
before do
- ActionMailer::Base.register_interceptor(DisableEmailInterceptor)
+ Mail.register_interceptor(DisableEmailInterceptor)
end
it 'should not send emails' do
@@ -14,7 +14,7 @@ describe DisableEmailInterceptor, lib: true do
# Removing interceptor from the list because unregister_interceptor is
# implemented in later version of mail gem
# See: https://github.com/mikel/mail/pull/705
- Mail.class_variable_set(:@@delivery_interceptors, [])
+ Mail.unregister_interceptor(DisableEmailInterceptor)
end
def deliver_mail
diff --git a/spec/services/todo_service_spec.rb b/spec/services/todo_service_spec.rb
index 6e7ecbd39ba..489c920f19f 100644
--- a/spec/services/todo_service_spec.rb
+++ b/spec/services/todo_service_spec.rb
@@ -18,7 +18,7 @@ describe TodoService, services: true do
end
describe 'Issues' do
- let(:issue) { create(:issue, project: project, assignee: john_doe, author: author, description: mentions) }
+ let(:issue) { create(:issue, project: project, assignee: john_doe, author: author, description: "- [ ] Task 1\n- [ ] Task 2 #{mentions}") }
let(:unassigned_issue) { create(:issue, project: project, assignee: nil) }
let(:confidential_issue) { create(:issue, :confidential, project: project, author: author, assignee: assignee, description: mentions) }
@@ -101,6 +101,19 @@ describe TodoService, services: true do
should_create_todo(user: admin, target: confidential_issue, author: john_doe, action: Todo::MENTIONED)
should_not_create_todo(user: john_doe, target: confidential_issue, author: john_doe, action: Todo::MENTIONED)
end
+
+ it 'does not create todo when when tasks are marked as completed' do
+ issue.update(description: "- [x] Task 1\n- [X] Task 2 #{mentions}")
+
+ service.update_issue(issue, author)
+
+ should_not_create_todo(user: admin, target: issue, action: Todo::MENTIONED)
+ should_not_create_todo(user: assignee, target: issue, action: Todo::MENTIONED)
+ should_not_create_todo(user: author, target: issue, action: Todo::MENTIONED)
+ should_not_create_todo(user: john_doe, target: issue, action: Todo::MENTIONED)
+ should_not_create_todo(user: member, target: issue, action: Todo::MENTIONED)
+ should_not_create_todo(user: non_member, target: issue, action: Todo::MENTIONED)
+ end
end
describe '#close_issue' do
@@ -210,7 +223,7 @@ describe TodoService, services: true do
end
describe 'Merge Requests' do
- let(:mr_assigned) { create(:merge_request, source_project: project, author: author, assignee: john_doe, description: mentions) }
+ let(:mr_assigned) { create(:merge_request, source_project: project, author: author, assignee: john_doe, description: "- [ ] Task 1\n- [ ] Task 2 #{mentions}") }
let(:mr_unassigned) { create(:merge_request, source_project: project, author: author, assignee: nil) }
describe '#new_merge_request' do
@@ -253,6 +266,19 @@ describe TodoService, services: true do
expect { service.update_merge_request(mr_assigned, author) }.not_to change(member.todos, :count)
end
+
+ it 'does not create todo when when tasks are marked as completed' do
+ mr_assigned.update(description: "- [x] Task 1\n- [X] Task 2 #{mentions}")
+
+ service.update_merge_request(mr_assigned, author)
+
+ should_not_create_todo(user: admin, target: mr_assigned, action: Todo::MENTIONED)
+ should_not_create_todo(user: assignee, target: mr_assigned, action: Todo::MENTIONED)
+ should_not_create_todo(user: author, target: mr_assigned, action: Todo::MENTIONED)
+ should_not_create_todo(user: john_doe, target: mr_assigned, action: Todo::MENTIONED)
+ should_not_create_todo(user: member, target: mr_assigned, action: Todo::MENTIONED)
+ should_not_create_todo(user: non_member, target: mr_assigned, action: Todo::MENTIONED)
+ end
end
describe '#close_merge_request' do