diff options
author | James Lopez <james@jameslopez.es> | 2016-06-16 12:59:07 +0200 |
---|---|---|
committer | James Lopez <james@jameslopez.es> | 2016-06-16 12:59:07 +0200 |
commit | 452c076a34cc11cc97f4b1c3113e86ce4367e055 (patch) | |
tree | a503b33dc6dd181e2cf56d5965fc1eb822b4d9f9 /app | |
parent | 13e37a3ee5c943525a99481b855d654e97e8597c (diff) | |
download | gitlab-ce-452c076a34cc11cc97f4b1c3113e86ce4367e055.tar.gz |
Revert "squashed merge and fixed conflicts"
This reverts commit 13e37a3ee5c943525a99481b855d654e97e8597c.
Diffstat (limited to 'app')
225 files changed, 1860 insertions, 2819 deletions
diff --git a/app/assets/javascripts/LabelManager.js.coffee b/app/assets/javascripts/LabelManager.js.coffee index b06bcf0fcbf..365a062bb81 100644 --- a/app/assets/javascripts/LabelManager.js.coffee +++ b/app/assets/javascripts/LabelManager.js.coffee @@ -42,10 +42,10 @@ class @LabelManager $from = @prioritizedLabels if $from.find('li').length is 1 - $from.find('.empty-message').removeClass('hidden') + $from.find('.empty-message').show() if not $target.find('li').length - $target.find('.empty-message').addClass('hidden') + $target.find('.empty-message').hide() $label.detach().appendTo($target) @@ -54,9 +54,6 @@ 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/application.js.coffee b/app/assets/javascripts/application.js.coffee index 2f9f6c3ef5b..69d4c4f5dd3 100644 --- a/app/assets/javascripts/application.js.coffee +++ b/app/assets/javascripts/application.js.coffee @@ -32,6 +32,10 @@ #= 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 @@ -121,10 +125,9 @@ window.onload = -> setTimeout shiftWindow, 100 $ -> - gl.utils.preventDisabledButtons() bootstrapBreakpoint = bp.getBreakpointSize() - $(".nav-sidebar").niceScroll(cursoropacitymax: '0.4', cursorcolor: '#FFF', cursorborder: "1px solid #FFF") + $(".nicescroll").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", -> @@ -254,31 +257,3 @@ $ -> gl.awardsHandler = new AwardsHandler() checkInitialSidebarSize() new Aside() - - # Sidenav pinning - if $(window).width() < 1440 and $.cookie('pin_nav') is 'true' - $.cookie('pin_nav', 'false') - $('.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() - - $(this).toggleClass 'is-active' - - if $.cookie('pin_nav') is 'true' - $.cookie 'pin_nav', 'false' - $('.page-with-sidebar') - .removeClass('page-sidebar-pinned') - .toggleClass('page-sidebar-collapsed page-sidebar-expanded') - $('.navbar-fixed-top') - .removeClass('header-pinned-nav') - .toggleClass('header-collapsed header-expanded') - else - $.cookie 'pin_nav', 'true' - $('.page-with-sidebar').addClass('page-sidebar-pinned') - $('.navbar-fixed-top').addClass('header-pinned-nav') diff --git a/app/assets/javascripts/awards_handler.coffee b/app/assets/javascripts/awards_handler.coffee index 030f1564862..136db8ee14d 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.closest('.note').find('.js-awards-block').addClass 'current' + $addBtn.parents('.note').find('.js-awards-block').addClass 'current' else $addBtn.closest('.js-awards-block').addClass 'current' diff --git a/app/assets/javascripts/network/branch-graph.js.coffee b/app/assets/javascripts/branch-graph.js.coffee index f2fd2a775a4..f2fd2a775a4 100644 --- a/app/assets/javascripts/network/branch-graph.js.coffee +++ b/app/assets/javascripts/branch-graph.js.coffee diff --git a/app/assets/javascripts/ci/build.coffee b/app/assets/javascripts/ci/build.coffee index 2d515d7efa2..f763ba96e33 100644 --- a/app/assets/javascripts/ci/build.coffee +++ b/app/assets/javascripts/ci/build.coffee @@ -17,8 +17,6 @@ class @CiBuild .off 'resize.build' .on 'resize.build', @hideSidebar - @updateArtifactRemoveDate() - if $('#build-trace').length @getInitialBuildTrace() @initScrollButtonAffix() @@ -105,10 +103,3 @@ 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 b560500cce6..29ac0f70b30 100644 --- a/app/assets/javascripts/dispatcher.js.coffee +++ b/app/assets/javascripts/dispatcher.js.coffee @@ -29,7 +29,6 @@ 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() @@ -54,13 +53,9 @@ 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() @@ -73,7 +68,9 @@ class Dispatcher new Diff() new ZenMode() shortcut_handler = new ShortcutsNavigation() - when 'projects:commits:show', 'projects:activity' + when 'projects:commits:show' + shortcut_handler = new ShortcutsNavigation() + when 'projects:activity' shortcut_handler = new ShortcutsNavigation() when 'projects:show' shortcut_handler = new ShortcutsNavigation() @@ -99,7 +96,6 @@ 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,11 +129,15 @@ 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', 'show' + when 'new' new ProjectNew() + when 'show' + new ProjectShow() when 'wikis' new Wikis() shortcut_handler = new ShortcutsNavigation() @@ -146,9 +146,9 @@ class Dispatcher when 'snippets' shortcut_handler = new ShortcutsNavigation() new ZenMode() if path[2] == 'show' - when 'labels', 'graphs', 'compare', 'pipelines', 'forks', \ - 'milestones', 'project_members', 'deploy_keys', 'builds', \ - 'hooks', 'services', 'protected_branches' + when 'labels', 'graphs' + shortcut_handler = new ShortcutsNavigation() + when 'project_members', 'deploy_keys', '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 d65c018dad5..3d009a96d05 100644 --- a/app/assets/javascripts/due_date_select.js.coffee +++ b/app/assets/javascripts/due_date_select.js.coffee @@ -1,21 +1,5 @@ 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() @@ -48,7 +32,7 @@ class @DueDateSelect date = new Date value.replace(new RegExp('-', 'g'), ',') mediumDate = $.datepicker.formatDate 'M d, yy', date else - mediumDate = 'No due date' + mediumDate = 'None' data = {} data[abilityName] = {} @@ -66,8 +50,7 @@ class @DueDateSelect $selectbox.hide() $value.css('display', '') - cssClass = if Date.parse(mediumDate) then 'bold' else 'no-value' - $valueContent.html("<span class='#{cssClass}'>#{mediumDate}</span>") + $valueContent.html(mediumDate) $sidebarValue.html(mediumDate) if value isnt '' diff --git a/app/assets/javascripts/issuable.js.coffee b/app/assets/javascripts/issuable.js.coffee index d0901be1509..c2447120033 100644 --- a/app/assets/javascripts/issuable.js.coffee +++ b/app/assets/javascripts/issuable.js.coffee @@ -56,6 +56,13 @@ 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() @@ -64,16 +71,58 @@ 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)) - Turbolinks.visit(issuesUrl); + Issuable.toggleLabelFilters() + + dataType: "json" + + reload: -> + if Issuable.created + Issuable.initChecks() + + $('#filter_issue_search').val($('#issue_search').val()) initChecks: -> - $('.check_all_issues').off('click').on('click', -> + $('.check_all_issues').on 'click', -> $('.selected_issue').prop('checked', @checked) Issuable.checkChanged() - ) - $('.selected_issue').off('change').on('change', 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 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 5b7a4831dfc..898506fde32 100644 --- a/app/assets/javascripts/issuable_form.js.coffee +++ b/app/assets/javascripts/issuable_form.js.coffee @@ -102,10 +102,6 @@ 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 b454f9389dd..16d023dd391 100644 --- a/app/assets/javascripts/issues-bulk-assignment.js.coffee +++ b/app/assets/javascripts/issues-bulk-assignment.js.coffee @@ -9,9 +9,6 @@ class @IssuableBulkActions @bindEvents() - # Fixes bulk-assign not working when navigating through pages - Issuable.initChecks(); - getElement: (selector) -> @container.find selector @@ -100,22 +97,13 @@ class @IssuableBulkActions $labels = @form.find('.labels-filter input[name="update[label_ids][]"]') $labels.each (k, label) -> - labelIds.push parseInt($(label).val()) if label + labelIds.push $(label).val() if label labelIds ###* - * Returns Label IDs that will be removed from issue selection - * @return {Array} Array of labels IDs + * Just an alias of @getUnmarkedIndeterminedLabels + * @return {Array} Array of labels ### getLabelsToRemove: -> - result = [] - indeterminatedLabels = @getUnmarkedIndeterminedLabels() - labelsToApply = @getLabelsToApply() - - indeterminatedLabels.map (id) -> - # We need to exclude label IDs that will be applied - # By not doing this will cause issues from selection to not add labels at all - result.push(id) if labelsToApply.indexOf(id) is -1 - - result + @getUnmarkedIndeterminedLabels() diff --git a/app/assets/javascripts/labels_select.js.coffee b/app/assets/javascripts/labels_select.js.coffee index d350a7c0e7f..9ca88f1226e 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 = '<span class="no-value">None</span>' + labelNoneHTMLTemplate = _.template('<div class="light">None</div>') 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) diff --git a/app/assets/javascripts/layout_nav.js.coffee b/app/assets/javascripts/layout_nav.js.coffee index f8f0aea427e..6adac6dac97 100644 --- a/app/assets/javascripts/layout_nav.js.coffee +++ b/app/assets/javascripts/layout_nav.js.coffee @@ -1,25 +1,14 @@ -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) +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) diff --git a/app/assets/javascripts/lib/common_utils.js.coffee b/app/assets/javascripts/lib/common_utils.js.coffee index e39dcb2daa9..0000e99a650 100644 --- a/app/assets/javascripts/lib/common_utils.js.coffee +++ b/app/assets/javascripts/lib/common_utils.js.coffee @@ -1,46 +1,5 @@ ((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/logo.js.coffee b/app/assets/javascripts/logo.js.coffee index dc2590a0355..9fdc27a9787 100644 --- a/app/assets/javascripts/logo.js.coffee +++ b/app/assets/javascripts/logo.js.coffee @@ -42,3 +42,9 @@ 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/merged_buttons.js.coffee b/app/assets/javascripts/merged_buttons.js.coffee deleted file mode 100644 index 4929295c10b..00000000000 --- a/app/assets/javascripts/merged_buttons.js.coffee +++ /dev/null @@ -1,30 +0,0 @@ -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 02480f3a025..648e1f3bde0 100644 --- a/app/assets/javascripts/milestone_select.js.coffee +++ b/app/assets/javascripts/milestone_select.js.coffee @@ -24,10 +24,14 @@ class @MilestoneSelect if issueUpdateURL milestoneLinkTemplate = _.template( - '<a href="/<%= namespace %>/<%= path %>/milestones/<%= iid %>" class="bold has-tooltip" data-container="body" title="<%= remaining %>"><%= _.escape(title) %></a>' + '<a href="/<%= namespace %>/<%= path %>/milestones/<%= iid %>"> + <span class="has-tooltip" data-container="body" title="<%= remaining %>"> + <%= _.escape(title) %> + </span> + </a>' ) - milestoneLinkNoneTemplate = '<span class="no-value">None</span>' + milestoneLinkNoneTemplate = '<div class="light">None</div>' collapsedSidebarLabelTemplate = _.template( '<span class="has-tooltip" data-container="body" title="<%= remaining %>" data-placement="left"> @@ -112,7 +116,7 @@ class @MilestoneSelect .val() data = {} data[abilityName] = {} - data[abilityName].milestone_id = if selected? then selected else null + data[abilityName].milestone_id = selected $loading .fadeIn() $dropdown.trigger('loading.gl.dropdown') diff --git a/app/assets/javascripts/network/network.js.coffee b/app/assets/javascripts/network.js.coffee index f4ef07a50a7..f4ef07a50a7 100644 --- a/app/assets/javascripts/network/network.js.coffee +++ b/app/assets/javascripts/network.js.coffee diff --git a/app/assets/javascripts/network/application.js.coffee b/app/assets/javascripts/network/application.js.coffee deleted file mode 100644 index cb9eead855b..00000000000 --- a/app/assets/javascripts/network/application.js.coffee +++ /dev/null @@ -1,20 +0,0 @@ -# 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/notes.js.coffee b/app/assets/javascripts/notes.js.coffee index e2d3241437b..ad216910c8d 100644 --- a/app/assets/javascripts/notes.js.coffee +++ b/app/assets/javascripts/notes.js.coffee @@ -115,14 +115,12 @@ 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/right_sidebar.js.coffee b/app/assets/javascripts/right_sidebar.js.coffee index 8eb005b0a22..c9cb0f4bb32 100644 --- a/app/assets/javascripts/right_sidebar.js.coffee +++ b/app/assets/javascripts/right_sidebar.js.coffee @@ -43,55 +43,6 @@ 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-id') then 'PATCH' else 'POST' - ajaxUrlExtra = if $this.attr('data-id') then "/#{$this.attr('data-id')}" else '' - - $.ajax( - url: "#{$this.data('url')}#{ajaxUrlExtra}" - type: ajaxType - dataType: 'json' - data: - issuable_id: $this.data('issuable') - 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.todo? - $btn - .attr 'aria-label', $btn.data('mark-text') - .attr 'data-id', data.todo.id - $btnText.text $btn.data('mark-text') - else - $btn - .attr 'aria-label', $btn.data('todo-text') - .removeAttr 'data-id' - $btnText.text $btn.data('todo-text') sidebarDropdownLoading: (e) -> $sidebarCollapsedIcon = $(@).closest('.block').find('.sidebar-collapsed-icon') @@ -166,3 +117,5 @@ 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 421328554b8..5eb915a51ea 100644 --- a/app/assets/javascripts/search_autocomplete.js.coffee +++ b/app/assets/javascripts/search_autocomplete.js.coffee @@ -67,12 +67,8 @@ class @SearchAutocomplete getData: (term, callback) -> _this = @ - unless term - if contents = @getCategoryContents() - @searchInput.data('glDropdown').filter.options.callback contents - @enableAutocomplete() - - return + # Do not trigger request if input is empty + return if @searchInput.val() is '' # Prevent multiple ajax calls return if @loadingSuggestions @@ -126,37 +122,6 @@ 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 @@ -244,12 +209,6 @@ class @SearchAutocomplete @isFocused = true @wrap.addClass('search-active') - @getData() if @getValue() is '' - - - getValue: -> return @searchInput.val() - - onClearInputClick: (e) => e.preventDefault() @searchInput.val('').focus() @@ -270,10 +229,6 @@ class @SearchAutocomplete @locationBadgeEl.text(badgeText).show() @wrap.addClass('has-location-badge') - - hasLocationBadge: -> return @wrap.is '.has-location-badge' - - restoreOriginalState: -> inputs = Object.keys @originalState @@ -302,14 +257,13 @@ class @SearchAutocomplete @getElement("##{input}").val('') - removeLocationBadge: -> - @locationBadgeEl.hide() + + # Reset state @resetSearchState() - @wrap.removeClass('has-location-badge') - @disableAutocomplete() + @wrap.removeClass('has-location-badge') disableAutocomplete: -> @searchInput.addClass('disabled') diff --git a/app/assets/javascripts/shortcuts.js.coffee b/app/assets/javascripts/shortcuts.js.coffee index c03877e9b06..f3d66004138 100644 --- a/app/assets/javascripts/shortcuts.js.coffee +++ b/app/assets/javascripts/shortcuts.js.coffee @@ -1,7 +1,7 @@ class @Shortcuts - constructor: (skipResetBindings) -> + constructor: -> @enabledHelp = [] - Mousetrap.reset() if not skipResetBindings + Mousetrap.reset() 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 deleted file mode 100644 index 6d21e5d1150..00000000000 --- a/app/assets/javascripts/shortcuts_blob.coffee +++ /dev/null @@ -1,10 +0,0 @@ -#= 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 68009e58645..2ce63c16428 100644 --- a/app/assets/javascripts/sidebar.js.coffee +++ b/app/assets/javascripts/sidebar.js.coffee @@ -3,33 +3,13 @@ expanded = 'page-sidebar-expanded' toggleSidebar = -> $('.page-with-sidebar').toggleClass("#{collapsed} #{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') + $('header').toggleClass("header-collapsed header-expanded") setTimeout ( -> - niceScrollBars = $('.nav-sidebar').niceScroll(); + niceScrollBars = $('.nicescroll').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 01b28171f72..f27780dda93 100644 --- a/app/assets/javascripts/star.js.coffee +++ b/app/assets/javascripts/star.js.coffee @@ -9,11 +9,9 @@ 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_select.js.coffee b/app/assets/javascripts/users_select.js.coffee index 2548efb2186..88246b0feb8 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 = if selected? then selected else null + data[abilityName].assignee_id = selected $loading .fadeIn() $dropdown.trigger('loading.gl.dropdown') @@ -72,7 +72,7 @@ class @UsersSelect assigneeTemplate = _.template( '<% if (username) { %> - <a class="author_link bold" href="/u/<%= username %>"> + <a class="author_link " 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="no-value assign-yourself"> + <span class="assign-yourself"> No assignee - <a href="#" class="js-assign-yourself"> assign yourself diff --git a/app/assets/stylesheets/framework/gitlab-theme.scss b/app/assets/stylesheets/framework/gitlab-theme.scss index 0a8603b6702..408d4a68e1e 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 { - .toggle-nav-collapse, - .pin-nav-btn { + + .collapse-nav a { color: $color-light; background: $color; diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss index dca4dbb9f7d..63996ea44f6 100644 --- a/app/assets/stylesheets/framework/header.scss +++ b/app/assets/stylesheets/framework/header.scss @@ -3,7 +3,7 @@ * */ header { - transition: padding $sidebar-transition-duration; + transition-duration: .3s; &.navbar-empty { height: $header-height; @@ -79,9 +79,14 @@ header { &.header-collapsed { padding: 0 16px; + + .side-nav-toggle { + display: block; + } } .side-nav-toggle { + display: none; position: absolute; left: -10px; margin: 6px 0; @@ -103,7 +108,9 @@ 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; @@ -191,6 +198,18 @@ header { } } +.header-collapsed { + margin-left: 0; + + .header-content { + + @media (min-width: $screen-sm-max) { + padding-left: 30px; + transition-duration: .3s; + } + } +} + .tanuki-shape { transition: all 0.8s; diff --git a/app/assets/stylesheets/framework/lists.scss b/app/assets/stylesheets/framework/lists.scss index a12c0bba44a..b34ec16cdba 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: 52px; + min-height: 30px; } } } diff --git a/app/assets/stylesheets/framework/nav.scss b/app/assets/stylesheets/framework/nav.scss index a55918f8711..4de89daeb36 100644 --- a/app/assets/stylesheets/framework/nav.scss +++ b/app/assets/stylesheets/framework/nav.scss @@ -74,7 +74,6 @@ .container-fluid { background-color: $background-color; - margin-bottom: 0; } li { @@ -242,12 +241,6 @@ } } } - - &.adjust { - .nav-text, .nav-controls { - width: auto; - } - } } .layout-nav { @@ -257,7 +250,7 @@ z-index: 11; background: $background-color; border-bottom: 1px solid $border-color; - transition: padding $sidebar-transition-duration; + transition-duration: .3s; text-align: center; .container-fluid { @@ -287,10 +280,11 @@ } .dropdown { - position: absolute; - top: 7px; - right: 15px; - z-index: 2; + margin-left: 7px; + + @media (max-width: $screen-xs-min) { + margin-left: 0; + } li.active { font-weight: bold; @@ -353,12 +347,6 @@ .badge { color: $gl-icon-color; } - - &:hover { - a, i { - color: $black; - } - } } } diff --git a/app/assets/stylesheets/framework/sidebar.scss b/app/assets/stylesheets/framework/sidebar.scss index 281c0a0e1e9..b7ec3f70bfb 100644 --- a/app/assets/stylesheets/framework/sidebar.scss +++ b/app/assets/stylesheets/framework/sidebar.scss @@ -1,31 +1,26 @@ .page-with-sidebar { padding-top: $header-height; - transition: padding $sidebar-transition-duration; + transition-duration: .3s; .sidebar-wrapper { position: fixed; top: 0; bottom: 0; + overflow-y: auto; + overflow-x: hidden; left: 0; height: 100%; - overflow: hidden; - transition: width $sidebar-transition-duration; + transition-duration: .3s; } } .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; @@ -39,19 +34,22 @@ } } -.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; +.sidebar-wrapper { - @media (min-width: $sidebar-breakpoint) { - bottom: 50px; + .sidebar-user { + padding: 15px 22px; + position: fixed; + bottom: 0; + width: $sidebar_width; + overflow: hidden; + transition-duration: .3s; + + .username { + margin-left: 10px; + width: $sidebar_width - 2 * 10px; + font-size: 16px; + line-height: 34px; + } } } @@ -67,46 +65,39 @@ .nav-sidebar { - position: absolute; - top: 50px; - bottom: 65px; - width: $sidebar_width; - overflow-y: auto; - overflow-x: hidden; - - @media (min-width: $sidebar-breakpoint) { - bottom: 115px; - } + 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 { - padding: 7px 15px 7px 12px; + width: $sidebar_width; + padding: 7px 15px 7px 23px; font-size: $gl-font-size; line-height: 24px; display: block; text-decoration: none; font-weight: normal; outline: none; - white-space: nowrap; - &:hover, - &:active, - &:focus { + &:hover { + text-decoration: none; + } + + &:active, &:focus { text-decoration: none; } @@ -118,6 +109,10 @@ svg { margin-right: 13px; } + + &.back-link i { + transition-duration: .3s; + } } } @@ -128,50 +123,37 @@ } } -.toggle-nav-collapse { +.sidebar-subnav { + margin-left: 0; + padding-left: 0; + + li { + list-style: none; + } +} + +.collapse-nav a { width: $sidebar_width; - position: absolute; + position: fixed; top: 0; left: 0; - min-height: 50px; padding: 5px 0; font-size: 18px; - line-height: 30px; -} - -.nav-header-btn { - padding: 10px 5px; - color: inherit; + background: transparent; + height: 50px; + text-align: center; + line-height: 40px; transition-duration: .3s; + outline: none; - &:hover, - &:focus { - color: $white-light; + &:hover { text-decoration: none; } } -.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); - } +.sidebar-wrapper { + &.hidden-nav { + width: 0; } } @@ -180,34 +162,62 @@ .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 { - .sidebar-wrapper { - width: $sidebar_width; - } -} -.page-sidebar-pinned { - .content-wrapper, - .layout-nav { - @media (min-width: $sidebar-breakpoint) { - padding-left: $sidebar_width; - } + @media (max-width: $screen-sm-max) { + padding-left: 0; } -} -header.header-pinned-nav { - @media (min-width: $sidebar-breakpoint) { - padding-left: ($sidebar_width + $gl-padding); + .sidebar-wrapper { + width: $sidebar_width; - .side-nav-toggle { - display: none; + .nav-sidebar { + width: $sidebar_width; } - .header-content { - padding-left: 0; + .nav-sidebar li a { + width: $sidebar_width; + + &.back-link { + i { + opacity: 0; + } + } } } } diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index acada1f16a0..752d8ec8788 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -6,8 +6,6 @@ $sidebar_width: 220px; $gutter_collapsed_width: 62px; $gutter_width: 290px; $gutter_inner_width: 258px; -$sidebar-transition-duration: .15s; -$sidebar-breakpoint: 1440px; /* * UI elements diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss index 761e33f0df7..c8c6bbde084 100644 --- a/app/assets/stylesheets/pages/commits.scss +++ b/app/assets/stylesheets/pages/commits.scss @@ -7,111 +7,84 @@ margin-right: 9px; } -.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; - } +.lists-separator { + margin: 10px 0; + border-color: #ddd; } -.commit-row-title { - line-height: 1; - margin-bottom: 7px; - - .notes_count { - float: right; - margin-right: 10px; - } +.commits-row { + ul { + margin: 0; - .str-truncated { - max-width: 70%; - } - - .commit-row-message { - color: $gl-dark-link-color; + li.commit { + padding: 8px 0; + } } - .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; - } + .commits-row-date { + font-size: 15px; + line-height: 20px; + margin-bottom: 5px; } } -.commit-actions { - @media (min-width: $screen-sm-min) { - float: right; - margin-left: $gl-padding; - margin-top: 2px; - font-size: 0; - } +li.commit { + list-style: none; - .btn-transparent { - padding-left: 0; - padding-right: 0; - } + .commit-row-title { + font-size: $list-font-size; + line-height: 20px; + margin-bottom: 2px; - .btn { - &:not(:first-child) { - margin-left: $gl-padding; + .btn-clipboard { + margin-top: -1px; } - } -} -.commit-short-id { - font-family: $monospace_font; - font-weight: 600; -} + .notes_count { + float: right; + margin-right: 10px; + } -.commit { - padding: 10px 0; + .commit_short_id { + min-width: 65px; + color: $gl-dark-link-color; + font-family: $monospace_font; + } - @media (min-width: $screen-sm-min) { - padding-left: 46px; - } + .str-truncated { + max-width: 70%; + } - &:not(:last-child) { - border-bottom: 1px solid #eee; - } + .commit-row-message { + color: $gl-dark-link-color; - a, - button { - color: $gl-dark-link-color; - vertical-align: baseline; - } + &:hover { + text-decoration: underline; + } + } - .avatar { - margin-left: -46px; + .text-expander { + background: #eee; + color: #555; + padding: 0 5px; + cursor: pointer; + margin-left: 4px; + &:hover { + background-color: #ddd; + } + } } .item-title { display: inline-block; - - @media (min-width: $screen-sm-min) { - max-width: 70%; - } + max-width: 70%; } .commit-row-description { font-size: 14px; border-left: 1px solid #eee; padding: 10px 15px; - margin: 10px 0; + margin: 5px 0 10px 5px; background: #f9f9f9; display: none; @@ -120,7 +93,6 @@ background: inherit; padding: 0; margin: 0; - white-space: pre-wrap; } a { @@ -130,7 +102,7 @@ .commit-row-info { color: $gl-gray; - line-height: 1; + line-height: 24px; a { color: $gl-gray; @@ -139,6 +111,10 @@ .avatar { margin-right: 8px; } + + .committed_ago { + display: inline-block; + } } &.inline-commit { diff --git a/app/assets/stylesheets/pages/environments.scss b/app/assets/stylesheets/pages/environments.scss deleted file mode 100644 index e160d676e35..00000000000 --- a/app/assets/stylesheets/pages/environments.scss +++ /dev/null @@ -1,5 +0,0 @@ -.environments { - .commit-title { - margin: 0; - } -} diff --git a/app/assets/stylesheets/pages/groups.scss b/app/assets/stylesheets/pages/groups.scss index ac7721cbe15..ec6c099df5b 100644 --- a/app/assets/stylesheets/pages/groups.scss +++ b/app/assets/stylesheets/pages/groups.scss @@ -39,20 +39,3 @@ } } } - -.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/issuable.scss b/app/assets/stylesheets/pages/issuable.scss index 687117233f6..ea453ce356a 100644 --- a/app/assets/stylesheets/pages/issuable.scss +++ b/app/assets/stylesheets/pages/issuable.scss @@ -34,10 +34,6 @@ color: inherit; } - .issuable-header-text { - margin-top: 7px; - } - .block { @include clearfix; padding: $gl-padding 0; @@ -64,6 +60,10 @@ margin-top: 0; } + .issuable-count { + margin-top: 7px; + } + .gutter-toggle { margin-left: 20px; padding-left: 10px; @@ -145,6 +145,7 @@ .assign-yourself { margin-top: 10px; + font-weight: normal; display: block; } } @@ -157,10 +158,6 @@ font-weight: normal; } - .no-value { - color: $gl-placeholder-color; - } - .sidebar-collapsed-icon { display: none; } @@ -251,16 +248,11 @@ padding-bottom: 0; margin-bottom: 10px; } - - .issuable-header-btn { - display: none; - } } - .issuable-header-btn { + .issuable-pager { background: $gray-normal; border: 1px solid $border-gray-normal; - &:hover { background: $gray-dark; border: 1px solid $border-gray-dark; @@ -271,7 +263,7 @@ } } - a { + a:not(.issuable-pager) { &:hover { color: $md-link-color; text-decoration: none; @@ -330,7 +322,7 @@ margin-left: 5px; a { - color: $gl-placeholder-color; + color: #8c8c8c; } } diff --git a/app/assets/stylesheets/pages/labels.scss b/app/assets/stylesheets/pages/labels.scss index 046c38aba44..bc65404a741 100644 --- a/app/assets/stylesheets/pages/labels.scss +++ b/app/assets/stylesheets/pages/labels.scss @@ -115,13 +115,6 @@ } } -.draggable-handler { - display: inline-block; - opacity: 0; - transition: opacity .3s; - color: $gray-darkest; -} - .prioritized-labels { margin-bottom: 30px; @@ -129,13 +122,6 @@ 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 53bff508c72..a47f2580aa3 100644 --- a/app/assets/stylesheets/pages/merge_requests.scss +++ b/app/assets/stylesheets/pages/merge_requests.scss @@ -313,13 +313,3 @@ } } } - -.merged-buttons { - .btn { - float: left; - - &:not(:last-child) { - margin-right: 10px; - } - } -} diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss index 35d728aec83..0c084118753 100644 --- a/app/assets/stylesheets/pages/notes.scss +++ b/app/assets/stylesheets/pages/notes.scss @@ -139,12 +139,6 @@ ul.notes { @media (min-width: $screen-sm-min) { padding-right: 0; } - - @media (max-width: $screen-xs-min) { - .inline { - display: block; - } - } } .note-emoji-button { @@ -264,11 +258,7 @@ 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/projects.scss b/app/assets/stylesheets/pages/projects.scss index c85d23a31f0..bb250904255 100644 --- a/app/assets/stylesheets/pages/projects.scss +++ b/app/assets/stylesheets/pages/projects.scss @@ -5,12 +5,10 @@ font-weight: normal; } } - .no-ssh-key-message, .project-limit-message { background-color: #f28d35; margin-bottom: 0; } - .new_project, .edit-project { fieldset.features { @@ -20,6 +18,13 @@ } } +.project-name-holder { + .help-inline { + vertical-align: top; + padding: 7px; + } +} + .project-home-panel { background: $white-light; text-align: left; @@ -224,20 +229,13 @@ right: 16px; bottom: 0; - @media (max-width: $screen-lg-min) { - top: 0; + .btn { + padding: 3px 10px; + background-color: $background-color; } - .access-request-button { - position: absolute; - right: 0; - bottom: 61px; - - @media (max-width: $screen-lg-min) { - position: relative; - bottom: 0; - margin-right: 10px; - } + @media (max-width: 1304px) { + top: 0; } } @@ -288,6 +286,10 @@ color: #555; } +.project_member_row form { + margin: 0; +} + .transfer-project .select2-container { min-width: 200px; } @@ -371,7 +373,6 @@ a.deploy-project-label { .project-import .btn { float: left; - margin-bottom: 10px; margin-right: 10px; } diff --git a/app/assets/stylesheets/pages/tree.scss b/app/assets/stylesheets/pages/tree.scss index 99c9e81ddb9..f16fc7f388f 100644 --- a/app/assets/stylesheets/pages/tree.scss +++ b/app/assets/stylesheets/pages/tree.scss @@ -101,7 +101,7 @@ margin: 0; .commit { - padding: 0 0 0 55px; + padding: 0; .commit-row-title { .commit-row-message { @@ -129,6 +129,4 @@ .tree-controls { float: right; margin-top: 11px; - position: relative; - z-index: 2; } diff --git a/app/controllers/autocomplete_controller.rb b/app/controllers/autocomplete_controller.rb index c89678cf2d8..3865b2d61fd 100644 --- a/app/controllers/autocomplete_controller.rb +++ b/app/controllers/autocomplete_controller.rb @@ -35,7 +35,6 @@ class AutocompleteController < ApplicationController project = Project.find_by_id(params[:project_id]) projects = current_user.authorized_projects - projects = projects.search(params[:search]) if params[:search].present? projects = projects.select do |project| current_user.can?(:admin_issue, project) end diff --git a/app/controllers/concerns/membership_actions.rb b/app/controllers/concerns/membership_actions.rb deleted file mode 100644 index a24273fad0b..00000000000 --- a/app/controllers/concerns/membership_actions.rb +++ /dev/null @@ -1,58 +0,0 @@ -module MembershipActions - extend ActiveSupport::Concern - include MembersHelper - - def request_access - membershipable.request_access(current_user) - - redirect_to polymorphic_path(membershipable), - notice: 'Your request for access has been queued for review.' - end - - def approve_access_request - @member = membershipable.members.request.find(params[:id]) - - return render_403 unless can?(current_user, action_member_permission(:update, @member), @member) - - @member.accept_request - - redirect_to polymorphic_url([membershipable, :members]) - end - - def leave - @member = membershipable.members.find_by(user_id: current_user) - return render_403 unless @member - - source_type = @member.real_source_type.humanize(capitalize: false) - - if can?(current_user, action_member_permission(:destroy, @member), @member) - notice = - if @member.request? - "Your access request to the #{source_type} has been withdrawn." - else - "You left the \"#{@member.source.human_name}\" #{source_type}." - end - @member.destroy - - redirect_to [:dashboard, @member.real_source_type.tableize], notice: notice - else - if cannot_leave? - alert = "You can not leave the \"#{@member.source.human_name}\" #{source_type}." - alert << " Transfer or delete the #{source_type}." - redirect_to polymorphic_url(membershipable), alert: alert - else - render_403 - end - end - end - - protected - - def membershipable - raise NotImplementedError - end - - def cannot_leave? - raise NotImplementedError - end -end diff --git a/app/controllers/groups/group_members_controller.rb b/app/controllers/groups/group_members_controller.rb index d0f2e2949f0..48dbf656e84 100644 --- a/app/controllers/groups/group_members_controller.rb +++ b/app/controllers/groups/group_members_controller.rb @@ -1,13 +1,11 @@ class Groups::GroupMembersController < Groups::ApplicationController - include MembershipActions - # Authorize - before_action :authorize_admin_group_member!, except: [:index, :leave, :request_access] + before_action :authorize_admin_group_member!, except: [:index, :leave] def index @project = @group.projects.find(params[:project_id]) if params[:project_id] @members = @group.group_members - @members = @members.non_pending unless can?(current_user, :admin_group, @group) + @members = @members.non_invite unless can?(current_user, :admin_group, @group) if params[:search].present? users = @group.users.search(params[:search]).to_a @@ -60,16 +58,25 @@ class Groups::GroupMembersController < Groups::ApplicationController end end - protected + def leave + @group_member = @group.group_members.find_by(user_id: current_user) - def member_params - params.require(:group_member).permit(:access_level, :user_id) + if can?(current_user, :destroy_group_member, @group_member) + @group_member.destroy + + redirect_to(dashboard_groups_path, notice: "You left #{group.name} group.") + else + if @group.last_owner?(current_user) + redirect_to(dashboard_groups_path, alert: "You can not leave #{group.name} group because you're the last owner. Transfer or delete the group.") + else + return render_403 + end + end end - # MembershipActions concern - alias_method :membershipable, :group + protected - def cannot_leave? - @group.last_owner?(current_user) + def member_params + params.require(:group_member).permit(:access_level, :user_id) end end diff --git a/app/controllers/jwt_controller.rb b/app/controllers/jwt_controller.rb index 014b9b43ff2..131a16dad9b 100644 --- a/app/controllers/jwt_controller.rb +++ b/app/controllers/jwt_controller.rb @@ -42,7 +42,7 @@ class JwtController < ApplicationController end def authenticate_user(login, password) - user = Gitlab::Auth.find_with_user_password(login, password) + user = Gitlab::Auth.find_in_gitlab_or_ldap(login, password) Gitlab::Auth.rate_limit!(request.ip, success: user.present?, login: login) user end diff --git a/app/controllers/profiles/notifications_controller.rb b/app/controllers/profiles/notifications_controller.rb index 40d1906a53f..18ee55c839a 100644 --- a/app/controllers/profiles/notifications_controller.rb +++ b/app/controllers/profiles/notifications_controller.rb @@ -1,13 +1,12 @@ class Profiles::NotificationsController < Profiles::ApplicationController def show - @user = current_user - @group_notifications = current_user.notification_settings.for_groups - @project_notifications = current_user.notification_settings.for_projects - @global_notification_setting = current_user.global_notification_setting + @user = current_user + @group_notifications = current_user.notification_settings.for_groups + @project_notifications = current_user.notification_settings.for_projects end def update - if current_user.update_attributes(user_params) && update_notification_settings + if current_user.update_attributes(user_params) flash[:notice] = "Notification settings saved" else flash[:alert] = "Failed to save new settings" @@ -17,18 +16,6 @@ class Profiles::NotificationsController < Profiles::ApplicationController end def user_params - params.require(:user).permit(:notification_email) - end - - def global_notification_setting_params - params.require(:global_notification_setting).permit(:level) - end - - private - - def update_notification_settings - return true unless global_notification_setting_params - - current_user.global_notification_setting.update_attributes(global_notification_setting_params) + params.require(:user).permit(:notification_email, :notification_level) end end diff --git a/app/controllers/projects/artifacts_controller.rb b/app/controllers/projects/artifacts_controller.rb index f11c8321464..832d7deb57d 100644 --- a/app/controllers/projects/artifacts_controller.rb +++ b/app/controllers/projects/artifacts_controller.rb @@ -1,18 +1,22 @@ class Projects::ArtifactsController < Projects::ApplicationController layout 'project' before_action :authorize_read_build! - before_action :authorize_update_build!, only: [:keep] - before_action :validate_artifacts! def download unless artifacts_file.file_storage? return redirect_to artifacts_file.url end + unless artifacts_file.exists? + return render_404 + end + send_file artifacts_file.path, disposition: 'attachment' end def browse + return render_404 unless build.artifacts? + directory = params[:path] ? "#{params[:path]}/" : '' @entry = build.artifacts_metadata_entry(directory) @@ -30,17 +34,8 @@ class Projects::ArtifactsController < Projects::ApplicationController end end - def keep - build.keep_artifacts! - redirect_to namespace_project_build_path(project.namespace, project, build) - end - private - def validate_artifacts! - render_404 unless build.artifacts? - end - def build @build ||= project.builds.find_by!(id: params[:build_id]) end diff --git a/app/controllers/projects/builds_controller.rb b/app/controllers/projects/builds_controller.rb index ef3051d7519..14c82826342 100644 --- a/app/controllers/projects/builds_controller.rb +++ b/app/controllers/projects/builds_controller.rb @@ -51,7 +51,7 @@ class Projects::BuildsController < Projects::ApplicationController return render_404 end - build = Ci::Build.retry(@build, current_user) + build = Ci::Build.retry(@build) redirect_to build_path(build) end diff --git a/app/controllers/projects/commit_controller.rb b/app/controllers/projects/commit_controller.rb index 6751737d15e..20637fa46fe 100644 --- a/app/controllers/projects/commit_controller.rb +++ b/app/controllers/projects/commit_controller.rb @@ -46,7 +46,7 @@ class Projects::CommitController < Projects::ApplicationController def retry_builds ci_builds.latest.failed.each do |build| if build.retryable? - Ci::Build.retry(build, current_user) + Ci::Build.retry(build) end end diff --git a/app/controllers/projects/environments_controller.rb b/app/controllers/projects/environments_controller.rb deleted file mode 100644 index 4b433796161..00000000000 --- a/app/controllers/projects/environments_controller.rb +++ /dev/null @@ -1,49 +0,0 @@ -class Projects::EnvironmentsController < Projects::ApplicationController - layout 'project' - before_action :authorize_read_environment! - before_action :authorize_create_environment!, only: [:new, :create] - before_action :authorize_update_environment!, only: [:destroy] - before_action :environment, only: [:show, :destroy] - - def index - @environments = project.environments - end - - def show - @deployments = environment.deployments.order(id: :desc).page(params[:page]) - end - - def new - @environment = project.environments.new - end - - def create - @environment = project.environments.create(create_params) - - if @environment.persisted? - redirect_to namespace_project_environment_path(project.namespace, project, @environment) - else - render 'new' - end - end - - def destroy - if @environment.destroy - flash[:notice] = 'Environment was successfully removed.' - else - flash[:alert] = 'Failed to remove environment.' - end - - redirect_to namespace_project_environments_path(project.namespace, project) - end - - private - - def create_params - params.require(:environment).permit(:name) - end - - def environment - @environment ||= project.environments.find(params[:id]) - end -end diff --git a/app/controllers/projects/git_http_controller.rb b/app/controllers/projects/git_http_controller.rb index f907d63258b..348d6cf4d96 100644 --- a/app/controllers/projects/git_http_controller.rb +++ b/app/controllers/projects/git_http_controller.rb @@ -43,7 +43,7 @@ class Projects::GitHttpController < Projects::ApplicationController return if project && project.public? && upload_pack? authenticate_or_request_with_http_basic do |login, password| - auth_result = Gitlab::Auth.find_for_git_client(login, password, project: project, ip: request.ip) + auth_result = Gitlab::Auth.find(login, password, project: project, ip: request.ip) if auth_result.type == :ci && upload_pack? @ci = true diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 851822d805a..67e7187c10d 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -204,19 +204,10 @@ class Projects::MergeRequestsController < Projects::ApplicationController @merge_request.update(merge_error: nil) - if params[:merge_when_build_succeeds].present? - if @merge_request.pipeline && @merge_request.pipeline.active? - MergeRequests::MergeWhenBuildSucceedsService.new(@project, current_user, merge_params) - .execute(@merge_request) - @status = :merge_when_build_succeeds - elsif @merge_request.pipeline.success? - # This can be triggered when a user clicks the auto merge button while - # the tests finish at about the same time - MergeWorker.perform_async(@merge_request.id, current_user.id, params) - @status = :success - else - @status = :failed - end + if params[:merge_when_build_succeeds].present? && @merge_request.pipeline && @merge_request.pipeline.active? + MergeRequests::MergeWhenBuildSucceedsService.new(@project, current_user, merge_params) + .execute(@merge_request) + @status = :merge_when_build_succeeds else MergeWorker.perform_async(@merge_request.id, current_user.id, params) @status = :success diff --git a/app/controllers/projects/pipelines_controller.rb b/app/controllers/projects/pipelines_controller.rb index 127bd1a4318..cac440ae53e 100644 --- a/app/controllers/projects/pipelines_controller.rb +++ b/app/controllers/projects/pipelines_controller.rb @@ -32,7 +32,7 @@ class Projects::PipelinesController < Projects::ApplicationController end def retry - pipeline.retry_failed(current_user) + pipeline.retry_failed redirect_back_or_default default: namespace_project_pipelines_path(project.namespace, project) end diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb index 35d067cd029..cdea5f0b776 100644 --- a/app/controllers/projects/project_members_controller.rb +++ b/app/controllers/projects/project_members_controller.rb @@ -1,12 +1,10 @@ class Projects::ProjectMembersController < Projects::ApplicationController - include MembershipActions - # Authorize - before_action :authorize_admin_project_member!, except: [:index, :leave, :request_access] + before_action :authorize_admin_project_member!, except: [:leave, :index] def index @project_members = @project.project_members - @project_members = @project_members.non_pending unless can?(current_user, :admin_project, @project) + @project_members = @project_members.non_invite unless can?(current_user, :admin_project, @project) if params[:search].present? users = @project.users.search(params[:search]).to_a @@ -16,10 +14,9 @@ class Projects::ProjectMembersController < Projects::ApplicationController @project_members = @project_members.order('access_level DESC') @group = @project.group - if @group @group_members = @group.group_members - @group_members = @group_members.non_pending unless can?(current_user, :admin_group, @group) + @group_members = @group_members.non_invite unless can?(current_user, :admin_group, @group) if params[:search].present? users = @group.users.search(params[:search]).to_a @@ -76,6 +73,26 @@ class Projects::ProjectMembersController < Projects::ApplicationController end end + def leave + @project_member = @project.project_members.find_by(user_id: current_user) + + if can?(current_user, :destroy_project_member, @project_member) + @project_member.destroy + + respond_to do |format| + format.html { redirect_to dashboard_projects_path, notice: "You left the project." } + format.js { head :ok } + end + else + if current_user == @project.owner + message = 'You can not leave your own project. Transfer or delete the project.' + redirect_back_or_default(default: { action: 'index' }, options: { alert: message }) + else + render_403 + end + end + end + def apply_import source_project = Project.find(params[:source_project_id]) @@ -95,11 +112,4 @@ class Projects::ProjectMembersController < Projects::ApplicationController def member_params params.require(:project_member).permit(:user_id, :access_level) end - - # MembershipActions concern - alias_method :membershipable, :project - - def cannot_leave? - current_user == @project.owner - end end diff --git a/app/controllers/projects/todos_controller.rb b/app/controllers/projects/todos_controller.rb deleted file mode 100644 index a51bd5e2b49..00000000000 --- a/app/controllers/projects/todos_controller.rb +++ /dev/null @@ -1,31 +0,0 @@ -class Projects::TodosController < Projects::ApplicationController - def create - todos = TodoService.new.mark_todo(issuable, current_user) - - render json: { - todo: todos, - count: current_user.todos.pending.count, - } - end - - def update - current_user.todos.find_by_id(params[:id]).update(state: :done) - - render json: { - count: current_user.todos.pending.count, - } - end - - private - - def issuable - @issuable ||= begin - case params[:issuable_type] - when "issue" - @project.issues.find(params[:issuable_id]) - when "merge_request" - @project.merge_requests.find(params[:issuable_id]) - end - end - end -end diff --git a/app/controllers/projects/wikis_controller.rb b/app/controllers/projects/wikis_controller.rb index 7ec1e73b3be..2aa6bed0724 100644 --- a/app/controllers/projects/wikis_controller.rb +++ b/app/controllers/projects/wikis_controller.rb @@ -16,9 +16,6 @@ class Projects::WikisController < Projects::ApplicationController if @page render 'show' elsif file = @project_wiki.find_file(params[:id], params[:version_id]) - response.headers['Content-Security-Policy'] = "default-src 'none'" - response.headers['X-Content-Security-Policy'] = "default-src 'none'" - if file.on_disk? send_file file.on_disk_path, disposition: 'inline' else diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 17aed816cbd..dae8f7b1447 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -40,7 +40,7 @@ class SessionsController < Devise::SessionsController # Handle an "initial setup" state, where there's only one user, it's an admin, # and they require a password change. def check_initial_setup - return unless User.limit(2).count == 1 # Count as much 2 to know if we have exactly one + return unless User.count == 1 user = User.admins.last diff --git a/app/finders/notes_finder.rb b/app/finders/notes_finder.rb index 0b7832e6583..ee14ac60fb4 100644 --- a/app/finders/notes_finder.rb +++ b/app/finders/notes_finder.rb @@ -12,7 +12,7 @@ class NotesFinder when "commit" project.notes.for_commit_id(target_id).non_diff_notes when "issue" - project.issues.visible_to_user(current_user).find(target_id).notes.inc_author + project.issues.find(target_id).notes.inc_author when "merge_request" project.merge_requests.find(target_id).mr_and_commit_notes.inc_author when "snippet", "project_snippet" diff --git a/app/finders/snippets_finder.rb b/app/finders/snippets_finder.rb index 00ff1611039..01cbf91c658 100644 --- a/app/finders/snippets_finder.rb +++ b/app/finders/snippets_finder.rb @@ -51,7 +51,7 @@ class SnippetsFinder snippets = project.snippets.fresh if current_user - if project.team.member?(current_user) || current_user.admin? + if project.team.member?(current_user.id) || current_user.admin? snippets else snippets.public_and_internal diff --git a/app/finders/todos_finder.rb b/app/finders/todos_finder.rb index aa47c6c157e..1d88116d7d2 100644 --- a/app/finders/todos_finder.rb +++ b/app/finders/todos_finder.rb @@ -36,7 +36,7 @@ class TodosFinder private def action_id? - action_id.present? && [Todo::ASSIGNED, Todo::MENTIONED, Todo::BUILD_FAILED, Todo::MARKED].include?(action_id.to_i) + action_id.present? && [Todo::ASSIGNED, Todo::MENTIONED, Todo::BUILD_FAILED].include?(action_id.to_i) end def action_id diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb index 85559fbc5f5..cec2dc753fe 100644 --- a/app/helpers/blob_helper.rb +++ b/app/helpers/blob_helper.rb @@ -116,7 +116,7 @@ module BlobHelper end def blob_text_viewable?(blob) - blob && blob.text? && !blob.lfs_pointer? && !blob.only_display_raw? + blob && blob.text? && !blob.lfs_pointer? end def blob_size(blob) diff --git a/app/helpers/branches_helper.rb b/app/helpers/branches_helper.rb index 3ee3fc74f0c..e39548e17e1 100644 --- a/app/helpers/branches_helper.rb +++ b/app/helpers/branches_helper.rb @@ -14,8 +14,4 @@ module BranchesHelper ::Gitlab::GitAccess.new(current_user, project).can_push_to_branch?(branch_name) end - - def project_branches - options_for_select(@project.repository.branch_names, @project.default_branch) - end end diff --git a/app/helpers/button_helper.rb b/app/helpers/button_helper.rb index 07a3f452460..f742922d926 100644 --- a/app/helpers/button_helper.rb +++ b/app/helpers/button_helper.rb @@ -17,15 +17,7 @@ module ButtonHelper def clipboard_button(data = {}) content_tag :button, icon('clipboard'), - class: "btn", - data: data, - type: :button - end - - def clipboard_button_with_class(data = {}, css_class: 'btn-clipboard') - content_tag :button, - icon('clipboard'), - class: "btn #{css_class}", + class: 'btn btn-clipboard', data: data, type: :button end diff --git a/app/helpers/ci_status_helper.rb b/app/helpers/ci_status_helper.rb index 8e4ae1e6aec..07e5c146844 100644 --- a/app/helpers/ci_status_helper.rb +++ b/app/helpers/ci_status_helper.rb @@ -38,10 +38,10 @@ module CiStatusHelper icon(icon_name + ' fw') end - def render_commit_status(commit, tooltip_placement: 'auto left', cssclass: '') + def render_commit_status(commit, tooltip_placement: 'auto left') project = commit.project path = builds_namespace_project_commit_path(project.namespace, project, commit) - render_status_with_link('commit', commit.status, path, tooltip_placement, cssclass: cssclass) + render_status_with_link('commit', commit.status, path, tooltip_placement) end def render_pipeline_status(pipeline, tooltip_placement: 'auto left') @@ -57,10 +57,10 @@ module CiStatusHelper private - def render_status_with_link(type, status, path, tooltip_placement, cssclass: '') + def render_status_with_link(type, status, path, tooltip_placement) link_to ci_icon_for_status(status), path, - class: "ci-status-link ci-status-icon-#{status.dasherize} #{cssclass}", + class: "ci-status-link ci-status-icon-#{status.dasherize}", title: "#{type.titleize}: #{ci_label_for_status(status)}", data: { toggle: 'tooltip', placement: tooltip_placement } end diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb index 474041eccbb..d328f56c80c 100644 --- a/app/helpers/commits_helper.rb +++ b/app/helpers/commits_helper.rb @@ -16,16 +16,6 @@ module CommitsHelper commit_person_link(commit, options.merge(source: :committer)) end - def commit_author_avatar(commit, options = {}) - options = options.merge(source: :author) - user = commit.send(options[:source]) - - source_email = clean(commit.send "#{options[:source]}_email".to_sym) - person_email = user.try(:email) || source_email - - image_tag(avatar_icon(person_email, options[:size]), class: "avatar #{"s#{options[:size]}" if options[:size]} hidden-xs", width: options[:size], alt: "") - end - def image_diff_class(diff) if diff.deleted_file "deleted" @@ -112,24 +102,24 @@ module CommitsHelper if current_controller?(:projects, :commits) if @repo.blob_at(commit.id, @path) return link_to( - "Browse File", + "Browse File »", namespace_project_blob_path(project.namespace, project, tree_join(commit.id, @path)), - class: "btn btn-default" + class: "pull-right" ) elsif @path.present? return link_to( - "Browse Directory", + "Browse Directory »", namespace_project_tree_path(project.namespace, project, tree_join(commit.id, @path)), - class: "btn btn-default" + class: "pull-right" ) end end link_to( "Browse Files", namespace_project_tree_path(project.namespace, project, commit), - class: "btn btn-default" + class: "pull-right" ) end @@ -139,7 +129,7 @@ module CommitsHelper tooltip = "Revert this #{commit.change_type_title} in a new merge request" if has_tooltip if can_collaborate_with_project? - btn_class = "btn btn-warning btn-#{btn_class}" unless btn_class.nil? + btn_class = "btn btn-grouped btn-close btn-#{btn_class}" unless btn_class.nil? link_to 'Revert', '#modal-revert-commit', 'data-toggle' => 'modal', 'data-container' => 'body', title: (tooltip if has_tooltip), class: "#{btn_class} #{'has-tooltip' if has_tooltip}" elsif can?(current_user, :fork_project, @project) continue_params = { @@ -151,7 +141,7 @@ module CommitsHelper namespace_key: current_user.namespace.id, continue: continue_params) - btn_class = "btn btn-grouped btn-warning" unless btn_class.nil? + btn_class = "btn btn-grouped btn-close" unless btn_class.nil? link_to 'Revert', fork_path, class: btn_class, method: :post, 'data-toggle' => 'tooltip', 'data-container' => 'body', title: (tooltip if has_tooltip) end @@ -163,7 +153,7 @@ module CommitsHelper tooltip = "Cherry-pick this #{commit.change_type_title} in a new merge request" if can_collaborate_with_project? - btn_class = "btn btn-default btn-#{btn_class}" unless btn_class.nil? + btn_class = "btn btn-default btn-grouped btn-#{btn_class}" unless btn_class.nil? link_to 'Cherry-pick', '#modal-cherry-pick-commit', 'data-toggle' => 'modal', 'data-container' => 'body', title: (tooltip if has_tooltip), class: "#{btn_class} #{'has-tooltip' if has_tooltip}" elsif can?(current_user, :fork_project, @project) continue_params = { @@ -197,10 +187,12 @@ module CommitsHelper source_email = clean(commit.send "#{options[:source]}_email".to_sym) person_name = user.try(:name) || source_name + person_email = user.try(:email) || source_email text = if options[:avatar] - %Q{<span class="commit-#{options[:source]}-name">#{person_name}</span>} + avatar = image_tag(avatar_icon(person_email, options[:size]), class: "avatar #{"s#{options[:size]}" if options[:size]}", width: options[:size], alt: "") + %Q{#{avatar} <span class="commit-#{options[:source]}-name">#{person_name}</span>} else person_name end diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb index e22dce59d0f..cbe47176831 100644 --- a/app/helpers/diff_helper.rb +++ b/app/helpers/diff_helper.rb @@ -135,11 +135,6 @@ module DiffHelper toggle_whitespace_link(url, options) end - def diff_compare_whitespace_link(project, from, to, options) - url = namespace_project_compare_path(project.namespace, project, from, to, params_with_whitespace) - toggle_whitespace_link(url, options) - end - private def hide_whitespace? diff --git a/app/helpers/gitlab_routing_helper.rb b/app/helpers/gitlab_routing_helper.rb index 5386ddadc62..2ce2d4e694f 100644 --- a/app/helpers/gitlab_routing_helper.rb +++ b/app/helpers/gitlab_routing_helper.rb @@ -13,23 +13,10 @@ # merge_request_path(merge_request) # module GitlabRoutingHelper - # Project def project_path(project, *args) namespace_project_path(project.namespace, project, *args) end - def project_url(project, *args) - namespace_project_url(project.namespace, project, *args) - end - - def edit_project_path(project, *args) - edit_namespace_project_path(project.namespace, project, *args) - end - - def edit_project_url(project, *args) - edit_namespace_project_url(project.namespace, project, *args) - end - def project_files_path(project, *args) namespace_project_tree_path(project.namespace, project, @ref || project.repository.root_ref) end @@ -42,10 +29,6 @@ module GitlabRoutingHelper namespace_project_pipelines_path(project.namespace, project, *args) end - def project_environments_path(project, *args) - namespace_project_environments_path(project.namespace, project, *args) - end - def project_builds_path(project, *args) namespace_project_builds_path(project.namespace, project, *args) end @@ -58,6 +41,10 @@ module GitlabRoutingHelper activity_namespace_project_path(project.namespace, project, *args) end + def edit_project_path(project, *args) + edit_namespace_project_path(project.namespace, project, *args) + end + def runners_path(project, *args) namespace_project_runners_path(project.namespace, project, *args) end @@ -78,6 +65,14 @@ module GitlabRoutingHelper namespace_project_milestone_path(entity.project.namespace, entity.project, entity, *args) end + def project_url(project, *args) + namespace_project_url(project.namespace, project, *args) + end + + def edit_project_url(project, *args) + edit_namespace_project_url(project.namespace, project, *args) + end + def issue_url(entity, *args) namespace_project_issue_url(entity.project.namespace, entity.project, entity, *args) end @@ -97,56 +92,4 @@ module GitlabRoutingHelper toggle_subscription_namespace_project_merge_request_path(entity.project.namespace, entity.project, entity) end end - - ## Members - def project_members_url(project, *args) - namespace_project_project_members_url(project.namespace, project) - end - - def project_member_path(project_member, *args) - namespace_project_project_member_path(project_member.source.namespace, project_member.source, project_member) - end - - def request_access_project_members_path(project, *args) - request_access_namespace_project_project_members_path(project.namespace, project) - end - - def leave_project_members_path(project, *args) - leave_namespace_project_project_members_path(project.namespace, project) - end - - def approve_access_request_project_member_path(project_member, *args) - approve_access_request_namespace_project_project_member_path(project_member.source.namespace, project_member.source, project_member) - end - - def resend_invite_project_member_path(project_member, *args) - resend_invite_namespace_project_project_member_path(project_member.source.namespace, project_member.source, project_member) - end - - # Groups - - ## Members - def group_members_url(group, *args) - group_group_members_url(group, *args) - end - - def group_member_path(group_member, *args) - group_group_member_path(group_member.source, group_member) - end - - def request_access_group_members_path(group, *args) - request_access_group_group_members_path(group) - end - - def leave_group_members_path(group, *args) - leave_group_group_members_path(group) - end - - def approve_access_request_group_member_path(group_member, *args) - approve_access_request_group_group_member_path(group_member.source, group_member) - end - - def resend_invite_group_member_path(group_member, *args) - resend_invite_group_group_member_path(group_member.source, group_member) - end end diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb index b9211e88473..4cac69c6795 100644 --- a/app/helpers/groups_helper.rb +++ b/app/helpers/groups_helper.rb @@ -1,4 +1,24 @@ module GroupsHelper + def remove_user_from_group_message(group, member) + if member.user + "Are you sure you want to remove \"#{member.user.name}\" from \"#{group.name}\"?" + else + "Are you sure you want to revoke the invitation for \"#{member.invite_email}\" to join \"#{group.name}\"?" + end + end + + def leave_group_message(group) + "Are you sure you want to leave \"#{group}\" group?" + end + + def should_user_see_group_roles?(user, group) + if user + user.is_admin? || group.members.exists?(user_id: user.id) + else + false + end + end + def can_change_group_visibility_level?(group) can?(current_user, :change_visibility_level, group) end diff --git a/app/helpers/issuables_helper.rb b/app/helpers/issuables_helper.rb index 8dbc51a689f..40d8ce8a1d3 100644 --- a/app/helpers/issuables_helper.rb +++ b/app/helpers/issuables_helper.rb @@ -67,12 +67,6 @@ module IssuablesHelper end end - def has_todo(issuable) - unless current_user.nil? - current_user.todos.find_by(target_id: issuable.id, state: :pending) - end - end - private def sidebar_gutter_collapsed? diff --git a/app/helpers/members_helper.rb b/app/helpers/members_helper.rb deleted file mode 100644 index 877c77050be..00000000000 --- a/app/helpers/members_helper.rb +++ /dev/null @@ -1,39 +0,0 @@ -module MembersHelper - # Returns a `<action>_<source>_member` association, e.g.: - # - admin_project_member, update_project_member, destroy_project_member - # - admin_group_member, update_group_member, destroy_group_member - def action_member_permission(action, member) - "#{action}_#{member.type.underscore}".to_sym - end - - def remove_member_message(member, user: nil) - user = current_user if defined?(current_user) - - text = 'Are you sure you want to ' - action = - if member.request? - if member.user == user - 'withdraw your access request for' - else - "deny #{member.user.name}'s request to join" - end - elsif member.invite? - "revoke the invitation for #{member.invite_email} to join" - else - "remove #{member.user.name} from" - end - - text << action << " the #{member.source.human_name} #{member.real_source_type.humanize(capitalize: false)}?" - end - - def remove_member_title(member) - text = " from #{member.real_source_type.humanize(capitalize: false)}" - - text.prepend(member.request? ? 'Deny access request' : 'Remove user') - end - - def leave_confirmation_message(member_source) - "Are you sure you want to leave the " \ - "\"#{member_source.human_name}\" #{member_source.class.to_s.humanize(capitalize: false)}?" - end -end diff --git a/app/helpers/nav_helper.rb b/app/helpers/nav_helper.rb index 3ff8be5e284..469accf3142 100644 --- a/app/helpers/nav_helper.rb +++ b/app/helpers/nav_helper.rb @@ -12,10 +12,10 @@ module NavHelper end def page_sidebar_class - if pinned_nav? - "page-sidebar-expanded page-sidebar-pinned" - else + if nav_menu_collapsed? "page-sidebar-collapsed" + else + "page-sidebar-expanded" end end @@ -36,15 +36,7 @@ module NavHelper end def nav_header_class - class_name = '' - class_name << " with-horizontal-nav" if defined?(nav) && nav - - if pinned_nav? - class_name << " header-expanded header-pinned-nav" - else - class_name << " header-collapsed" - end - + class_name = " with-horizontal-nav" if defined?(nav) && nav class_name end @@ -55,8 +47,4 @@ module NavHelper def nav_control_class "nav-control" if current_user end - - def pinned_nav? - cookies[:pin_nav] == 'true' - end end diff --git a/app/helpers/notifications_helper.rb b/app/helpers/notifications_helper.rb index 50c21fc0d49..b8e64b3890a 100644 --- a/app/helpers/notifications_helper.rb +++ b/app/helpers/notifications_helper.rb @@ -61,23 +61,4 @@ module NotificationsHelper end end end - - def notification_level_radio_buttons - html = "" - - NotificationSetting.levels.each_key do |level| - level = level.to_sym - next if level == :global - - html << content_tag(:div, class: "radio") do - content_tag(:label, { value: level }) do - radio_button_tag(:"global_notification_setting[level]", level, @global_notification_setting.level.to_sym == level) + - content_tag(:div, level.to_s.capitalize, class: "level-title") + - content_tag(:p, notification_description(level)) - end - end - end - - html.html_safe - end end diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index d91e3332e48..5e5d170a9f3 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -1,4 +1,12 @@ module ProjectsHelper + def remove_from_project_team_message(project, member) + if member.user + "You are going to remove #{member.user.name} from #{project.name} project team. Are you sure?" + else + "You are going to revoke the invitation for #{member.invite_email} to join #{project.name} project team. Are you sure?" + end + end + def link_to_project(project) link_to [project.namespace.becomes(Namespace), project], title: h(project.name) do title = content_tag(:span, project.name, class: 'project-name') @@ -41,7 +49,7 @@ module ProjectsHelper author_html = author_html.html_safe if opts[:name] - link_to(author_html, user_path(author), class: "author_link #{"#{opts[:extra_class]}" if opts[:extra_class]} #{"#{opts[:mobile_classes]}" if opts[:mobile_classes]}").html_safe + link_to(author_html, user_path(author), class: "author_link #{"#{opts[:mobile_classes]}" if opts[:mobile_classes]}").html_safe else title = opts[:title].sub(":name", sanitize(author.name)) link_to(author_html, user_path(author), class: "author_link has-tooltip", title: title, data: { container: 'body' } ).html_safe @@ -107,6 +115,14 @@ module ProjectsHelper end end + def user_max_access_in_project(user_id, project) + level = project.team.max_member_access(user_id) + + if level + Gitlab::Access.options_with_owner.key(level) + end + end + def license_short_name(project) return 'LICENSE' if project.repository.license_key.nil? @@ -140,10 +156,6 @@ module ProjectsHelper nav_tabs << :container_registry end - if can?(current_user, :read_environment, project) - nav_tabs << :environments - end - if can?(current_user, :admin_project, project) nav_tabs << :settings end @@ -274,6 +286,10 @@ module ProjectsHelper end end + def leave_project_message(project) + "Are you sure you want to leave \"#{project.name}\" project?" + end + def new_readme_path ref = @repository.root_ref if @repository ref ||= 'master' diff --git a/app/helpers/time_helper.rb b/app/helpers/time_helper.rb index b04b0a5114c..8142f733e76 100644 --- a/app/helpers/time_helper.rb +++ b/app/helpers/time_helper.rb @@ -20,6 +20,7 @@ module TimeHelper end end + def date_from_to(from, to) "#{from.to_s(:short)} - #{to.to_s(:short)}" end diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb index 9adf5ef29f7..b4923fbb138 100644 --- a/app/helpers/todos_helper.rb +++ b/app/helpers/todos_helper.rb @@ -12,7 +12,6 @@ module TodosHelper when Todo::ASSIGNED then 'assigned you' when Todo::MENTIONED then 'mentioned you on' when Todo::BUILD_FAILED then 'The build failed for your' - when Todo::MARKED then 'marked this as a Todo for' end end diff --git a/app/mailers/emails/groups.rb b/app/mailers/emails/groups.rb new file mode 100644 index 00000000000..1c43f95dc8c --- /dev/null +++ b/app/mailers/emails/groups.rb @@ -0,0 +1,52 @@ +module Emails + module Groups + def group_access_granted_email(group_member_id) + @group_member = GroupMember.find(group_member_id) + @group = @group_member.group + + @target_url = group_url(@group) + @current_user = @group_member.user + + mail(to: @group_member.user.notification_email, + subject: subject("Access to group was granted")) + end + + def group_member_invited_email(group_member_id, token) + @group_member = GroupMember.find group_member_id + @group = @group_member.group + @token = token + + @target_url = group_url(@group) + @current_user = @group_member.user + + mail(to: @group_member.invite_email, + subject: "Invitation to join group #{@group.name}") + end + + def group_invite_accepted_email(group_member_id) + @group_member = GroupMember.find group_member_id + return if @group_member.created_by.nil? + + @group = @group_member.group + + @target_url = group_url(@group) + @current_user = @group_member.created_by + + mail(to: @group_member.created_by.notification_email, + subject: subject("Invitation accepted")) + end + + def group_invite_declined_email(group_id, invite_email, access_level, created_by_id) + return if created_by_id.nil? + + @group = Group.find(group_id) + @current_user = @created_by = User.find(created_by_id) + @access_level = access_level + @invite_email = invite_email + + @target_url = group_url(@group) + mail(to: @created_by.notification_email, + subject: subject("Invitation declined")) + end + end +end diff --git a/app/mailers/emails/members.rb b/app/mailers/emails/members.rb deleted file mode 100644 index 6dde2e9847d..00000000000 --- a/app/mailers/emails/members.rb +++ /dev/null @@ -1,81 +0,0 @@ -module Emails - module Members - extend ActiveSupport::Concern - include MembersHelper - - included do - helper_method :member_source, :member - end - - def member_access_requested_email(member_source_type, member_id) - @member_source_type = member_source_type - @member_id = member_id - - admins = member_source.members.owners_and_masters.includes(:user).pluck(:notification_email) - - mail(to: admins, - subject: subject("Request to join the #{member_source.human_name} #{member_source.model_name.singular}")) - end - - def member_access_granted_email(member_source_type, member_id) - @member_source_type = member_source_type - @member_id = member_id - - mail(to: member.user.notification_email, - subject: subject("Access to the #{member_source.human_name} #{member_source.model_name.singular} was granted")) - end - - def member_access_denied_email(member_source_type, source_id, user_id) - @member_source_type = member_source_type - @member_source = member_source_class.find(source_id) - requester = User.find(user_id) - - mail(to: requester.notification_email, - subject: subject("Access to the #{member_source.human_name} #{member_source.model_name.singular} was denied")) - end - - def member_invited_email(member_source_type, member_id, token) - @member_source_type = member_source_type - @member_id = member_id - @token = token - - mail(to: member.invite_email, - subject: "Invitation to join the #{member_source.human_name} #{member_source.model_name.singular}") - end - - def member_invite_accepted_email(member_source_type, member_id) - @member_source_type = member_source_type - @member_id = member_id - return unless member.created_by - - mail(to: member.created_by.notification_email, - subject: subject('Invitation accepted')) - end - - def member_invite_declined_email(member_source_type, source_id, invite_email, created_by_id) - return unless created_by_id - - @member_source_type = member_source_type - @member_source = member_source_class.find(source_id) - @invite_email = invite_email - inviter = User.find(created_by_id) - - mail(to: inviter.notification_email, - subject: subject('Invitation declined')) - end - - def member - @member ||= Member.find(@member_id) - end - - def member_source - @member_source ||= member.source - end - - private - - def member_source_class - @member_source_type.classify.constantize - end - end -end diff --git a/app/mailers/emails/projects.rb b/app/mailers/emails/projects.rb index 689fb3e0ffb..fdf1e9f5afc 100644 --- a/app/mailers/emails/projects.rb +++ b/app/mailers/emails/projects.rb @@ -1,5 +1,55 @@ module Emails module Projects + def project_access_granted_email(project_member_id) + @project_member = ProjectMember.find project_member_id + @project = @project_member.project + + @target_url = namespace_project_url(@project.namespace, @project) + @current_user = @project_member.user + + mail(to: @project_member.user.notification_email, + subject: subject("Access to project was granted")) + end + + def project_member_invited_email(project_member_id, token) + @project_member = ProjectMember.find project_member_id + @project = @project_member.project + @token = token + + @target_url = namespace_project_url(@project.namespace, @project) + @current_user = @project_member.user + + mail(to: @project_member.invite_email, + subject: "Invitation to join project #{@project.name_with_namespace}") + end + + def project_invite_accepted_email(project_member_id) + @project_member = ProjectMember.find project_member_id + return if @project_member.created_by.nil? + + @project = @project_member.project + + @target_url = namespace_project_url(@project.namespace, @project) + @current_user = @project_member.created_by + + mail(to: @project_member.created_by.notification_email, + subject: subject("Invitation accepted")) + end + + def project_invite_declined_email(project_id, invite_email, access_level, created_by_id) + return if created_by_id.nil? + + @project = Project.find(project_id) + @current_user = @created_by = User.find(created_by_id) + @access_level = access_level + @invite_email = invite_email + + @target_url = namespace_project_url(@project.namespace, @project) + + mail(to: @created_by.notification_email, + subject: subject("Invitation declined")) + end + def project_was_moved_email(project_id, user_id, old_path_with_namespace) @current_user = @user = User.find user_id @project = Project.find project_id diff --git a/app/mailers/notify.rb b/app/mailers/notify.rb index 0cc709f68e4..1c663bdd521 100644 --- a/app/mailers/notify.rb +++ b/app/mailers/notify.rb @@ -6,15 +6,13 @@ class Notify < BaseMailer include Emails::Notes include Emails::Projects include Emails::Profile + include Emails::Groups include Emails::Builds - include Emails::Members add_template_helper MergeRequestsHelper add_template_helper DiffHelper add_template_helper BlobHelper add_template_helper EmailsHelper - add_template_helper MembersHelper - add_template_helper GitlabRoutingHelper def test_email(recipient_email, subject, body) mail(to: recipient_email, diff --git a/app/models/ability.rb b/app/models/ability.rb index 9c58b956007..44515550d9e 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -9,6 +9,7 @@ class Ability when CommitStatus then commit_status_abilities(user, subject) when Project then project_abilities(user, subject) when Issue then issue_abilities(user, subject) + when ExternalIssue then external_issue_abilities(user, subject) when Note then note_abilities(user, subject) when ProjectSnippet then project_snippet_abilities(user, subject) when PersonalSnippet then personal_snippet_abilities(user, subject) @@ -18,7 +19,6 @@ class Ability when GroupMember then group_member_abilities(user, subject) when ProjectMember then project_member_abilities(user, subject) when User then user_abilities - when ExternalIssue, Deployment, Environment then project_abilities(user, subject.project) else [] end.concat(global_abilities(user)) end @@ -187,8 +187,6 @@ class Ability project_report_rules elsif team.guest?(user) project_guest_rules - else - [] end end @@ -230,8 +228,6 @@ class Ability :read_build, :read_container_image, :read_pipeline, - :read_environment, - :read_deployment ] end @@ -250,8 +246,6 @@ class Ability :push_code, :create_container_image, :update_container_image, - :create_environment, - :create_deployment ] end @@ -269,8 +263,6 @@ class Ability @project_master_rules ||= project_dev_rules + [ :push_code_to_protected_branches, :update_project_snippet, - :update_environment, - :update_deployment, :admin_milestone, :admin_project_snippet, :admin_project_member, @@ -281,9 +273,7 @@ class Ability :admin_commit_status, :admin_build, :admin_container_image, - :admin_pipeline, - :admin_environment, - :admin_deployment + :admin_pipeline ] end @@ -327,8 +317,6 @@ class Ability unless project.builds_enabled rules += named_abilities('build') rules += named_abilities('pipeline') - rules += named_abilities('environment') - rules += named_abilities('deployment') end unless project.container_registry_enabled @@ -523,6 +511,10 @@ class Ability end end + def external_issue_abilities(user, subject) + project_abilities(user, subject.project) + end + private def restricted_public_level? @@ -541,7 +533,7 @@ class Ability def filter_confidential_issues_abilities(user, issue, rules) return rules if user.admin? || !issue.confidential? - unless issue.author == user || issue.assignee == user || issue.project.team.member?(user, Gitlab::Access::REPORTER) + unless issue.author == user || issue.assignee == user || issue.project.team.member?(user.id) rules.delete(:admin_issue) rules.delete(:read_issue) rules.delete(:update_issue) diff --git a/app/models/blob.rb b/app/models/blob.rb index 4279ea2ce57..0fea6b7f576 100644 --- a/app/models/blob.rb +++ b/app/models/blob.rb @@ -24,7 +24,7 @@ class Blob < SimpleDelegator end def only_display_raw? - size && truncated? + size && size > 5.megabytes end def svg? diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 764d8e4e136..6a64ca451f7 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -11,8 +11,6 @@ module Ci scope :unstarted, ->() { where(runner_id: nil) } scope :ignore_failures, ->() { where(allow_failure: false) } - scope :with_artifacts, ->() { where.not(artifacts_file: nil) } - scope :with_expired_artifacts, ->() { with_artifacts.where('artifacts_expire_at < ?', Time.now) } mount_uploader :artifacts_file, ArtifactUploader mount_uploader :artifacts_metadata, ArtifactUploader @@ -40,7 +38,7 @@ module Ci new_build.save end - def retry(build, user = nil) + def retry(build) new_build = Ci::Build.new(status: 'pending') new_build.ref = build.ref new_build.tag = build.tag @@ -54,7 +52,6 @@ module Ci new_build.stage = build.stage new_build.stage_idx = build.stage_idx new_build.trigger_request = build.trigger_request - new_build.user = user new_build.save MergeRequests::AddTodoWhenBuildFailsService.new(build.project, nil).close(new_build) new_build @@ -76,17 +73,6 @@ module Ci build.update_coverage build.execute_hooks end - - after_transition any => [:success] do |build| - if build.environment.present? - service = CreateDeploymentService.new(build.project, build.user, - environment: build.environment, - sha: build.sha, - ref: build.ref, - tag: build.tag) - service.execute(build) - end - end end def retryable? @@ -97,6 +83,10 @@ module Ci !self.pipeline.statuses.latest.include?(self) end + def retry + Ci::Build.retry(self) + end + def depends_on_builds # Get builds of the same type latest_builds = self.pipeline.builds.latest @@ -327,7 +317,7 @@ module Ci end def artifacts? - !artifacts_expired? && artifacts_file.exists? + artifacts_file.exists? end def artifacts_metadata? @@ -338,15 +328,11 @@ module Ci Gitlab::Ci::Build::Artifacts::Metadata.new(artifacts_metadata.path, path, **options).to_entry end - def erase_artifacts! - remove_artifacts_file! - remove_artifacts_metadata! - end - def erase(opts = {}) return false unless erasable? - erase_artifacts! + remove_artifacts_file! + remove_artifacts_metadata! erase_trace! update_erased!(opts[:erased_by]) end @@ -359,25 +345,6 @@ module Ci !self.erased_at.nil? end - def artifacts_expired? - artifacts_expire_at && artifacts_expire_at < Time.now - end - - def artifacts_expire_in - artifacts_expire_at - Time.now if artifacts_expire_at - end - - def artifacts_expire_in=(value) - self.artifacts_expire_at = - if value - Time.now + ChronicDuration.parse(value) - end - end - - def keep_artifacts! - self.update(artifacts_expire_at: nil) - end - private def erase_trace! @@ -385,7 +352,7 @@ module Ci end def update_erased!(user = nil) - self.update(erased_by: user, erased_at: Time.now, artifacts_expire_at: nil) + self.update(erased_by: user, erased_at: Time.now) end def yaml_variables diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index 13be5b0fa5d..d780467034e 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -76,10 +76,8 @@ module Ci builds.running_or_pending.each(&:cancel) end - def retry_failed(user) - builds.latest.failed.select(&:retryable?).each do |build| - Ci::Build.retry(build, user) - end + def retry_failed + builds.latest.failed.select(&:retryable?).each(&:retry) end def latest? @@ -163,10 +161,6 @@ module Ci git_commit_message =~ /(\[ci skip\])/ if git_commit_message end - def environments - builds.where.not(environment: nil).success.pluck(:environment).uniq - end - def notes Note.for_commit_id(sha) end diff --git a/app/models/concerns/access_requestable.rb b/app/models/concerns/access_requestable.rb deleted file mode 100644 index eedd32a729f..00000000000 --- a/app/models/concerns/access_requestable.rb +++ /dev/null @@ -1,16 +0,0 @@ -# == AccessRequestable concern -# -# Contains functionality related to objects that can receive request for access. -# -# Used by Project, and Group. -# -module AccessRequestable - extend ActiveSupport::Concern - - def request_access(user) - members.create( - access_level: Gitlab::Access::DEVELOPER, - user: user, - requested_at: Time.now.utc) - end -end diff --git a/app/models/concerns/awardable.rb b/app/models/concerns/awardable.rb index 539c7c31e30..aa4b4201250 100644 --- a/app/models/concerns/awardable.rb +++ b/app/models/concerns/awardable.rb @@ -5,7 +5,7 @@ module Awardable has_many :award_emoji, as: :awardable, dependent: :destroy if self < Participable - participant :award_emoji_with_associations + participant :award_emoji end end @@ -34,12 +34,8 @@ module Awardable end end - def award_emoji_with_associations - award_emoji.includes(:user) - end - def grouped_awards(with_thumbs: true) - awards = award_emoji_with_associations.group_by(&:name) + awards = award_emoji.group_by(&:name) if with_thumbs awards[AwardEmoji::UPVOTE_NAME] ||= [] diff --git a/app/models/deployment.rb b/app/models/deployment.rb deleted file mode 100644 index e498ca96e3c..00000000000 --- a/app/models/deployment.rb +++ /dev/null @@ -1,29 +0,0 @@ -class Deployment < ActiveRecord::Base - include InternalId - - belongs_to :project, required: true, validate: true - belongs_to :environment, required: true, validate: true - belongs_to :user - belongs_to :deployable, polymorphic: true - - validates :sha, presence: true - validates :ref, presence: true - - delegate :name, to: :environment, prefix: true - - def commit - project.commit(sha) - end - - def commit_title - commit.try(:title) - end - - def short_sha - Commit.truncate_sha(sha) - end - - def last? - self == environment.last_deployment - end -end diff --git a/app/models/environment.rb b/app/models/environment.rb deleted file mode 100644 index ac3a571a1f3..00000000000 --- a/app/models/environment.rb +++ /dev/null @@ -1,16 +0,0 @@ -class Environment < ActiveRecord::Base - belongs_to :project, required: true, validate: true - - has_many :deployments - - validates :name, - presence: true, - uniqueness: { scope: :project_id }, - length: { within: 0..255 }, - format: { with: Gitlab::Regex.environment_name_regex, - message: Gitlab::Regex.environment_name_regex_message } - - def last_deployment - deployments.last - end -end diff --git a/app/models/group.rb b/app/models/group.rb index e66e04371b2..aec92e335e6 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -3,18 +3,11 @@ require 'carrierwave/orm/activerecord' class Group < Namespace include Gitlab::ConfigHelper include Gitlab::VisibilityLevel - include AccessRequestable include Referable has_many :group_members, dependent: :destroy, as: :source, class_name: 'GroupMember' alias_method :members, :group_members - has_many :users, -> { where(members: { requested_at: nil }) }, through: :group_members - - has_many :owners, - -> { where(members: { access_level: Gitlab::Access::OWNER }) }, - through: :group_members, - source: :user - + has_many :users, through: :group_members has_many :project_group_links, dependent: :destroy has_many :shared_projects, through: :project_group_links, source: :project has_many :notification_settings, dependent: :destroy, as: :source @@ -65,10 +58,6 @@ class Group < Namespace "#{self.class.reference_prefix}#{name}" end - def web_url - Gitlab::Routing.url_helpers.group_url(self) - end - def human_name name end @@ -94,6 +83,10 @@ class Group < Namespace end end + def owners + @owners ||= group_members.owners.includes(:user).map(&:user) + end + def add_users(user_ids, access_level, current_user = nil) user_ids.each do |user_id| Member.add_user(self.group_members, user_id, access_level, current_user) diff --git a/app/models/issue.rb b/app/models/issue.rb index 1bdf9c011b2..235922710ad 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -51,18 +51,10 @@ class Issue < ActiveRecord::Base end def self.visible_to_user(user) - return where('issues.confidential IS NULL OR issues.confidential IS FALSE') if user.blank? + return where(confidential: false) if user.blank? return all if user.admin? - where(' - issues.confidential IS NULL - OR issues.confidential IS FALSE - OR (issues.confidential = TRUE - AND (issues.author_id = :user_id - OR issues.assignee_id = :user_id - OR issues.project_id IN(:project_ids)))', - user_id: user.id, - project_ids: user.authorized_projects(Gitlab::Access::REPORTER).select(:id)) + where('issues.confidential = false OR (issues.confidential = true AND (issues.author_id = :user_id OR issues.assignee_id = :user_id OR issues.project_id IN(:project_ids)))', user_id: user.id, project_ids: user.authorized_projects.select(:id)) end def self.reference_prefix diff --git a/app/models/member.rb b/app/models/member.rb index cea6d259760..d3060f07fc0 100644 --- a/app/models/member.rb +++ b/app/models/member.rb @@ -26,28 +26,20 @@ class Member < ActiveRecord::Base allow_nil: true } - scope :invite, -> { where.not(invite_token: nil) } - scope :non_invite, -> { where(invite_token: nil) } - scope :request, -> { where.not(requested_at: nil) } - scope :non_request, -> { where(requested_at: nil) } - scope :non_pending, -> { non_request.non_invite } - + scope :invite, -> { where(user_id: nil) } + scope :non_invite, -> { where("user_id IS NOT NULL") } scope :guests, -> { where(access_level: GUEST) } scope :reporters, -> { where(access_level: REPORTER) } scope :developers, -> { where(access_level: DEVELOPER) } scope :masters, -> { where(access_level: MASTER) } scope :owners, -> { where(access_level: OWNER) } - scope :owners_and_masters, -> { where(access_level: [OWNER, MASTER]) } before_validation :generate_invite_token, on: :create, if: -> (member) { member.invite_email.present? } - after_create :send_invite, if: :invite? - after_create :send_request, if: :request? - after_create :create_notification_setting, unless: :pending? - after_create :post_create_hook, unless: :pending? - after_update :post_update_hook, unless: :pending? - after_destroy :post_destroy_hook, unless: :pending? - after_destroy :post_decline_request, if: :request? + after_create :create_notification_setting, unless: :invite? + after_create :post_create_hook, unless: :invite? + after_update :post_update_hook, unless: :invite? + after_destroy :post_destroy_hook, unless: :invite? delegate :name, :username, :email, to: :user, prefix: true @@ -104,31 +96,10 @@ class Member < ActiveRecord::Base end end - def real_source_type - source_type - end - def invite? self.invite_token.present? end - def request? - requested_at.present? - end - - def pending? - invite? || request? - end - - def accept_request - return false unless request? - - updated = self.update(requested_at: nil) - after_accept_request if updated - - updated - end - def accept_invite!(new_user) return false unless invite? @@ -186,10 +157,6 @@ class Member < ActiveRecord::Base # override in subclass end - def send_request - # override in subclass - end - def post_create_hook system_hook_service.execute_hooks_for(self, :create) end @@ -210,14 +177,6 @@ class Member < ActiveRecord::Base # override in subclass end - def after_accept_request - post_create_hook - end - - def post_decline_request - # override in subclass - end - def system_hook_service SystemHooksService.new end diff --git a/app/models/members/group_member.rb b/app/models/members/group_member.rb index 363db877968..f63a0debf1a 100644 --- a/app/models/members/group_member.rb +++ b/app/models/members/group_member.rb @@ -8,6 +8,9 @@ class GroupMember < Member validates_format_of :source_type, with: /\ANamespace\z/ default_scope { where(source_type: SOURCE_TYPE) } + scope :with_group, ->(group) { where(source_id: group.id) } + scope :with_user, ->(user) { where(user_id: user.id) } + def self.access_level_roles Gitlab::Access.options_with_owner end @@ -20,11 +23,6 @@ class GroupMember < Member access_level end - # Because source_type is `Namespace`... - def real_source_type - 'Group' - end - private def send_invite @@ -33,12 +31,6 @@ class GroupMember < Member super end - def send_request - notification_service.new_group_access_request(self) - - super - end - def post_create_hook notification_service.new_group_member(self) @@ -64,10 +56,4 @@ class GroupMember < Member super end - - def post_decline_request - notification_service.decline_group_access_request(self) - - super - end end diff --git a/app/models/members/project_member.rb b/app/models/members/project_member.rb index 250ee04fd1d..46955b430f3 100644 --- a/app/models/members/project_member.rb +++ b/app/models/members/project_member.rb @@ -11,6 +11,8 @@ class ProjectMember < Member default_scope { where(source_type: SOURCE_TYPE) } scope :in_project, ->(project) { where(source_id: project.id) } + scope :in_projects, ->(projects) { where(source_id: projects.pluck(:id)) } + scope :with_user, ->(user) { where(user_id: user.id) } before_destroy :delete_member_todos @@ -82,7 +84,7 @@ class ProjectMember < Member Gitlab::Access.sym_options end - def access_level_roles + def access_roles Gitlab::Access.options end end @@ -111,12 +113,6 @@ class ProjectMember < Member super end - def send_request - notification_service.new_project_access_request(self) - - super - end - def post_create_hook unless owner? event_service.join_project(self.project, self.user) @@ -152,12 +148,6 @@ class ProjectMember < Member super end - def post_decline_request - notification_service.decline_project_access_request(self) - - super - end - def event_service EventCreateService.new end diff --git a/app/models/note.rb b/app/models/note.rb index 4b6748053ff..585d8c4ad84 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -88,9 +88,22 @@ class Note < ActiveRecord::Base table = arel_table pattern = "%#{query}%" - Note.joins('LEFT JOIN issues ON issues.id = noteable_id'). - where(table[:note].matches(pattern)). - merge(Issue.visible_to_user(as_user)) + found_notes = joins('LEFT JOIN issues ON issues.id = noteable_id'). + where(table[:note].matches(pattern)) + + if as_user + found_notes.where(' + issues.confidential IS NULL + OR issues.confidential IS FALSE + OR (issues.confidential IS TRUE + AND (issues.author_id = :user_id + OR issues.assignee_id = :user_id + OR issues.project_id IN(:project_ids)))', + user_id: as_user.id, + project_ids: as_user.authorized_projects.select(:id)) + else + found_notes.where('issues.confidential IS NULL OR issues.confidential IS FALSE') + end end end @@ -187,10 +200,6 @@ class Note < ActiveRecord::Base award_emoji_supported? && contains_emoji_only? end - def emoji_awardable? - !system? - end - def clear_blank_line_code! self.line_code = nil if self.line_code.blank? end diff --git a/app/models/notification_setting.rb b/app/models/notification_setting.rb index 0ce87968e46..17fb15b08df 100644 --- a/app/models/notification_setting.rb +++ b/app/models/notification_setting.rb @@ -7,6 +7,7 @@ class NotificationSetting < ActiveRecord::Base belongs_to :source, polymorphic: true validates :user, presence: true + validates :source, presence: true validates :level, presence: true validates :user_id, uniqueness: { scope: [:source_type, :source_id], message: "already exists in source", diff --git a/app/models/project.rb b/app/models/project.rb index 0ede6c6b139..9dca63f124b 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -5,7 +5,6 @@ class Project < ActiveRecord::Base include Gitlab::ShellAdapter include Gitlab::VisibilityLevel include Gitlab::CurrentSettings - include AccessRequestable include Referable include Sortable include AfterCommitQueue @@ -81,7 +80,7 @@ class Project < ActiveRecord::Base has_one :jira_service, dependent: :destroy has_one :redmine_service, dependent: :destroy has_one :custom_issue_tracker_service, dependent: :destroy - has_one :gitlab_issue_tracker_service, dependent: :destroy, inverse_of: :project + has_one :gitlab_issue_tracker_service, dependent: :destroy has_one :external_wiki_service, dependent: :destroy has_one :forked_project_link, dependent: :destroy, foreign_key: "forked_to_project_id" @@ -103,9 +102,8 @@ class Project < ActiveRecord::Base has_many :snippets, dependent: :destroy, class_name: 'ProjectSnippet' has_many :hooks, dependent: :destroy, class_name: 'ProjectHook' has_many :protected_branches, dependent: :destroy - has_many :project_members, dependent: :destroy, as: :source, class_name: 'ProjectMember' - alias_method :members, :project_members - has_many :users, -> { where(members: { requested_at: nil }) }, through: :project_members + has_many :project_members, dependent: :destroy, as: :source, class_name: 'ProjectMember' + has_many :users, through: :project_members has_many :deploy_keys_projects, dependent: :destroy has_many :deploy_keys, through: :deploy_keys_projects has_many :users_star_projects, dependent: :destroy @@ -127,8 +125,6 @@ class Project < ActiveRecord::Base has_many :runners, through: :runner_projects, source: :runner, class_name: 'Ci::Runner' has_many :variables, dependent: :destroy, class_name: 'Ci::Variable', foreign_key: :gl_project_id has_many :triggers, dependent: :destroy, class_name: 'Ci::Trigger', foreign_key: :gl_project_id - has_many :environments, dependent: :destroy - has_many :deployments, dependent: :destroy accepts_nested_attributes_for :variables, allow_destroy: true @@ -150,6 +146,7 @@ class Project < ActiveRecord::Base message: Gitlab::Regex.project_path_regex_message } validates :issues_enabled, :merge_requests_enabled, :wiki_enabled, inclusion: { in: [true, false] } + validates :issues_tracker_id, length: { maximum: 255 }, allow_blank: true validates :namespace, presence: true validates_uniqueness_of :name, scope: :namespace_id validates_uniqueness_of :path, scope: :namespace_id @@ -592,6 +589,10 @@ class Project < ActiveRecord::Base update_column(:has_external_issue_tracker, services.external_issue_trackers.any?) end + def can_have_issues_tracker_id? + self.issues_enabled && !self.default_issues_tracker? + end + def build_missing_services services_templates = Service.where(template: true) @@ -684,6 +685,16 @@ class Project < ActiveRecord::Base end end + def project_member_by_name_or_email(name = nil, email = nil) + user = users.find_by('name like ? or email like ?', name, email) + project_members.where(user: user) if user + end + + # Get Team Member record by user id + def project_member_by_id(user_id) + project_members.find_by(user_id: user_id) + end + def name_with_namespace @name_with_namespace ||= begin if namespace @@ -693,7 +704,6 @@ class Project < ActiveRecord::Base end end end - alias_method :human_name, :name_with_namespace def path_with_namespace if namespace diff --git a/app/models/project_services/bamboo_service.rb b/app/models/project_services/bamboo_service.rb index b5c76e4d4fe..1d1780dcfbf 100644 --- a/app/models/project_services/bamboo_service.rb +++ b/app/models/project_services/bamboo_service.rb @@ -1,4 +1,6 @@ class BambooService < CiService + include HTTParty + prop_accessor :bamboo_url, :build_key, :username, :password validates :bamboo_url, presence: true, url: true, if: :activated? @@ -59,7 +61,18 @@ class BambooService < CiService end def build_info(sha) - @response = get_path("rest/api/latest/result?label=#{sha}") + url = URI.join(bamboo_url, "/rest/api/latest/result?label=#{sha}").to_s + + if username.blank? && password.blank? + @response = HTTParty.get(url, verify: false) + else + url << '&os_authType=basic' + auth = { + username: username, + password: password + } + @response = HTTParty.get(url, verify: false, basic_auth: auth) + end end def build_page(sha, ref) @@ -67,11 +80,11 @@ class BambooService < CiService if @response.code != 200 || @response['results']['results']['size'] == '0' # If actual build link can't be determined, send user to build summary page. - URI.join("#{bamboo_url}/", "browse/#{build_key}").to_s + URI.join(bamboo_url, "/browse/#{build_key}").to_s else # If actual build link is available, go to build result page. result_key = @response['results']['results']['result']['planResultKey']['key'] - URI.join("#{bamboo_url}/", "browse/#{result_key}").to_s + URI.join(bamboo_url, "/browse/#{result_key}").to_s end end @@ -99,27 +112,8 @@ class BambooService < CiService def execute(data) return unless supported_events.include?(data[:object_kind]) - get_path("updateAndBuild.action?buildKey=#{build_key}") - end - - private - - def build_url(path) - URI.join("#{bamboo_url}/", path).to_s - end - - def get_path(path) - url = build_url(path) - - if username.blank? && password.blank? - HTTParty.get(url, verify: false) - else - url << '&os_authType=basic' - HTTParty.get(url, verify: false, - basic_auth: { - username: username, - password: password - }) - end + # Bamboo requires a GET and does not take any data. + url = URI.join(bamboo_url, "/updateAndBuild.action?buildKey=#{build_key}").to_s + self.class.get(url, verify: false) end end diff --git a/app/models/project_services/issue_tracker_service.rb b/app/models/project_services/issue_tracker_service.rb index 87ecb3b8b86..6ae9b16d3ce 100644 --- a/app/models/project_services/issue_tracker_service.rb +++ b/app/models/project_services/issue_tracker_service.rb @@ -38,9 +38,9 @@ class IssueTrackerService < Service if enabled_in_gitlab_config self.properties = { title: issues_tracker['title'], - project_url: issues_tracker['project_url'], - issues_url: issues_tracker['issues_url'], - new_issue_url: issues_tracker['new_issue_url'] + project_url: add_issues_tracker_id(issues_tracker['project_url']), + issues_url: add_issues_tracker_id(issues_tracker['issues_url']), + new_issue_url: add_issues_tracker_id(issues_tracker['new_issue_url']) } else self.properties = {} @@ -83,4 +83,16 @@ class IssueTrackerService < Service def issues_tracker Gitlab.config.issues_tracker[to_param] end + + def add_issues_tracker_id(url) + if self.project + id = self.project.issues_tracker_id + + if id + url = url.gsub(":issues_tracker_id", id) + end + end + + url + end end diff --git a/app/models/project_services/teamcity_service.rb b/app/models/project_services/teamcity_service.rb index a4a967c9bc9..b0dcb52eba1 100644 --- a/app/models/project_services/teamcity_service.rb +++ b/app/models/project_services/teamcity_service.rb @@ -1,4 +1,6 @@ class TeamcityService < CiService + include HTTParty + prop_accessor :teamcity_url, :build_type, :username, :password validates :teamcity_url, presence: true, url: true, if: :activated? @@ -62,7 +64,15 @@ class TeamcityService < CiService end def build_info(sha) - @response = get_path("httpAuth/app/rest/builds/branch:unspecified:any,number:#{sha}") + url = URI.join( + teamcity_url, + "/httpAuth/app/rest/builds/branch:unspecified:any,number:#{sha}" + ).to_s + auth = { + username: username, + password: password + } + @response = HTTParty.get(url, verify: false, basic_auth: auth) end def build_page(sha, ref) @@ -71,11 +81,14 @@ class TeamcityService < CiService if @response.code != 200 # If actual build link can't be determined, # send user to build summary page. - build_url("viewLog.html?buildTypeId=#{build_type}") + URI.join(teamcity_url, "/viewLog.html?buildTypeId=#{build_type}").to_s else # If actual build link is available, go to build result page. built_id = @response['build']['id'] - build_url("viewLog.html?buildId=#{built_id}&buildTypeId=#{build_type}") + URI.join( + teamcity_url, + "/viewLog.html?buildId=#{built_id}&buildTypeId=#{build_type}" + ).to_s end end @@ -110,8 +123,8 @@ class TeamcityService < CiService branch = Gitlab::Git.ref_name(data[:ref]) - HTTParty.post( - build_url('httpAuth/app/rest/buildQueue'), + self.class.post( + URI.join(teamcity_url, '/httpAuth/app/rest/buildQueue').to_s, body: "<build branchName=\"#{branch}\">"\ "<buildType id=\"#{build_type}\"/>"\ '</build>', @@ -119,18 +132,4 @@ class TeamcityService < CiService basic_auth: auth ) end - - private - - def build_url(path) - URI.join("#{teamcity_url}/", path).to_s - end - - def get_path(path) - HTTParty.get(build_url(path), verify: false, - basic_auth: { - username: username, - password: password - }) - end end diff --git a/app/models/project_team.rb b/app/models/project_team.rb index 73e736820af..70a8bbaba65 100644 --- a/app/models/project_team.rb +++ b/app/models/project_team.rb @@ -21,13 +21,23 @@ class ProjectTeam end end + def find(user_id) + user = project.users.find_by(id: user_id) + + if group + user ||= group.users.find_by(id: user_id) + end + + user + end + def find_member(user_id) - member = project.members.non_request.find_by(user_id: user_id) + member = project.project_members.find_by(user_id: user_id) # If user is not in project members # we should check for group membership if group && !member - member = group.members.non_request.find_by(user_id: user_id) + member = group.group_members.find_by(user_id: user_id) end member @@ -51,10 +61,13 @@ class ProjectTeam ProjectMember.truncate_team(project) end + def users + members + end + def members @members ||= fetch_members end - alias_method :users, :members def guests @guests ||= fetch_members(:guests) @@ -118,14 +131,8 @@ class ProjectTeam max_member_access(user.id) == Gitlab::Access::MASTER end - def member?(user, min_member_access = nil) - member = !!find_member(user.id) - - if min_member_access - member && max_member_access(user.id) >= min_member_access - else - member - end + def member?(user_id) + !!find_member(user_id) end def human_max_access(user_id) @@ -137,7 +144,7 @@ class ProjectTeam def max_member_access(user_id) access = [] - project.members.non_request.each do |member| + project.project_members.each do |member| if member.user_id == user_id access << member.access_field if member.access_field break @@ -145,7 +152,7 @@ class ProjectTeam end if group - group.members.non_request.each do |member| + group.group_members.each do |member| if member.user_id == user_id access << member.access_field if member.access_field break @@ -160,7 +167,6 @@ class ProjectTeam access.compact.max end - private def max_invited_level(user_id) project.project_group_links.map do |group_link| @@ -177,15 +183,17 @@ class ProjectTeam end.compact.max end + private + def fetch_members(level = nil) - project_members = project.members.non_request - group_members = group ? group.members.non_request : [] + project_members = project.project_members + group_members = group ? group.group_members : [] invited_members = [] if project.invited_groups.any? && project.allowed_to_share_with_group? project.project_group_links.each do |group_link| invited_group = group_link.group - im = invited_group.members.non_request + im = invited_group.group_members if level int_level = GroupMember.access_level_roles[level.to_s.singularize.titleize] diff --git a/app/models/repository.rb b/app/models/repository.rb index e5b277cb198..1ab163510bf 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -446,7 +446,7 @@ class Repository def blob_at(sha, path) unless Gitlab::Git.blank_ref?(sha) - Blob.decorate(Gitlab::Git::Blob.find(self, sha, path)) + Gitlab::Git::Blob.find(self, sha, path) end end diff --git a/app/models/service.rb b/app/models/service.rb index 40d39933ad8..bf352397509 100644 --- a/app/models/service.rb +++ b/app/models/service.rb @@ -18,7 +18,7 @@ class Service < ActiveRecord::Base after_commit :reset_updated_properties after_commit :cache_project_has_external_issue_tracker - belongs_to :project, inverse_of: :services + belongs_to :project has_one :service_hook validates :project_id, presence: true, unless: Proc.new { |service| service.template? } diff --git a/app/models/todo.rb b/app/models/todo.rb index 2792fa9b9a8..3a091373329 100644 --- a/app/models/todo.rb +++ b/app/models/todo.rb @@ -2,7 +2,6 @@ class Todo < ActiveRecord::Base ASSIGNED = 1 MENTIONED = 2 BUILD_FAILED = 3 - MARKED = 4 belongs_to :author, class_name: "User" belongs_to :note diff --git a/app/models/user.rb b/app/models/user.rb index 8d0427da5ab..e0987e07e1f 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -10,8 +10,6 @@ class User < ActiveRecord::Base include CaseSensitivity include TokenAuthenticatable - DEFAULT_NOTIFICATION_LEVEL = :participating - add_authentication_token_field :authentication_token default_value_for :admin, false @@ -56,7 +54,8 @@ class User < ActiveRecord::Base # Groups has_many :members, dependent: :destroy - has_many :group_members, dependent: :destroy, source: 'GroupMember' + has_many :project_members, source: 'ProjectMember' + has_many :group_members, source: 'GroupMember' has_many :groups, through: :group_members has_many :owned_groups, -> { where members: { access_level: Gitlab::Access::OWNER } }, through: :group_members, source: :group has_many :masters_groups, -> { where members: { access_level: Gitlab::Access::MASTER } }, through: :group_members, source: :group @@ -64,13 +63,13 @@ class User < ActiveRecord::Base # Projects has_many :groups_projects, through: :groups, source: :projects has_many :personal_projects, through: :namespace, source: :projects - has_many :project_members, dependent: :destroy, class_name: 'ProjectMember' has_many :projects, through: :project_members has_many :created_projects, foreign_key: :creator_id, class_name: 'Project' has_many :users_star_projects, dependent: :destroy has_many :starred_projects, through: :users_star_projects, source: :project has_many :snippets, dependent: :destroy, foreign_key: :author_id, class_name: "Snippet" + has_many :project_members, dependent: :destroy, class_name: 'ProjectMember' has_many :issues, dependent: :destroy, foreign_key: :author_id has_many :notes, dependent: :destroy, foreign_key: :author_id has_many :merge_requests, dependent: :destroy, foreign_key: :author_id @@ -100,6 +99,7 @@ class User < ActiveRecord::Base presence: true, uniqueness: { case_sensitive: false } + validates :notification_level, presence: true validate :namespace_uniq, if: ->(user) { user.username_changed? } validate :avatar_type, if: ->(user) { user.avatar.present? && user.avatar_changed? } validate :unique_email, if: ->(user) { user.email_changed? } @@ -133,6 +133,13 @@ class User < ActiveRecord::Base # Note: When adding an option, it MUST go on the end of the array. enum project_view: [:readme, :activity, :files] + # Notification level + # Note: When adding an option, it MUST go on the end of the array. + # + # TODO: Add '_prefix: :notification' to enum when update to Rails 5. https://github.com/rails/rails/pull/19813 + # Because user.notification_disabled? is much better than user.disabled? + enum notification_level: [:disabled, :participating, :watch, :global, :mention] + alias_attribute :private_token, :authentication_token delegate :path, to: :namespace, allow_nil: true, prefix: true @@ -404,8 +411,8 @@ class User < ActiveRecord::Base end # Returns projects user is authorized to access. - def authorized_projects(min_access_level = nil) - Project.where("projects.id IN (#{projects_union(min_access_level).to_sql})") + def authorized_projects + Project.where("projects.id IN (#{projects_union.to_sql})") end def viewable_starred_projects @@ -793,17 +800,6 @@ class User < ActiveRecord::Base notification_settings.find_or_initialize_by(source: source) end - # Lazy load global notification setting - # Initializes User setting with Participating level if setting not persisted - def global_notification_setting - return @global_notification_setting if defined?(@global_notification_setting) - - @global_notification_setting = notification_settings.find_or_initialize_by(source: nil) - @global_notification_setting.update_attributes(level: NotificationSetting.levels[DEFAULT_NOTIFICATION_LEVEL]) unless @global_notification_setting.persisted? - - @global_notification_setting - end - def assigned_open_merge_request_count(force: false) Rails.cache.fetch(['users', id, 'assigned_open_merge_request_count'], force: force) do assigned_merge_requests.opened.count @@ -823,19 +819,11 @@ class User < ActiveRecord::Base private - def projects_union(min_access_level = nil) - relations = [personal_projects.select(:id), - groups_projects.select(:id), - projects.select(:id), - groups.joins(:shared_projects).select(:project_id)] - - - if min_access_level - scope = { access_level: Gitlab::Access.values.select { |access| access >= min_access_level } } - relations = [relations.shift] + relations.map { |relation| relation.where(members: scope) } - end - - Gitlab::SQL::Union.new(relations) + def projects_union + Gitlab::SQL::Union.new([personal_projects.select(:id), + groups_projects.select(:id), + projects.select(:id), + groups.joins(:shared_projects).select(:project_id)]) end def ci_projects_union diff --git a/app/services/ci/create_builds_service.rb b/app/services/ci/create_builds_service.rb index 3a74ae094e8..64bcdac5c65 100644 --- a/app/services/ci/create_builds_service.rb +++ b/app/services/ci/create_builds_service.rb @@ -29,8 +29,7 @@ module Ci :options, :allow_failure, :stage, - :stage_idx, - :environment) + :stage_idx) build_attrs.merge!(ref: @pipeline.ref, tag: @pipeline.tag, diff --git a/app/services/ci/register_build_service.rb b/app/services/ci/register_build_service.rb index f0ed09a629a..4ff268a6f06 100644 --- a/app/services/ci/register_build_service.rb +++ b/app/services/ci/register_build_service.rb @@ -7,19 +7,15 @@ module Ci builds = if current_runner.shared? - builds. - # don't run projects which have not enabled shared runners - joins(:project).where(projects: { builds_enabled: true, shared_runners_enabled: true }). - - # this returns builds that are ordered by number of running builds - # we prefer projects that don't use shared runners at all - joins("LEFT JOIN (#{running_builds_for_shared_runners.to_sql}) AS project_builds ON ci_builds.gl_project_id=project_builds.gl_project_id"). - order('COALESCE(project_builds.running_builds, 0) ASC', 'ci_builds.id ASC') + # don't run projects which have not enables shared runners + builds.joins(:project).where(projects: { builds_enabled: true, shared_runners_enabled: true }) else - # do run projects which are only assigned to this runner (FIFO) - builds.where(project: current_runner.projects.where(builds_enabled: true)).order('created_at ASC') + # do run projects which are only assigned to this runner + builds.where(project: current_runner.projects.where(builds_enabled: true)) end + builds = builds.order('created_at ASC') + build = builds.find do |build| build.can_be_served?(current_runner) end @@ -39,12 +35,5 @@ module Ci rescue StateMachines::InvalidTransition nil end - - private - - def running_builds_for_shared_runners - Ci::Build.running.where(runner: Ci::Runner.shared). - group(:gl_project_id).select(:gl_project_id, 'count(*) AS running_builds') - end end end diff --git a/app/services/create_deployment_service.rb b/app/services/create_deployment_service.rb deleted file mode 100644 index efeb9df9527..00000000000 --- a/app/services/create_deployment_service.rb +++ /dev/null @@ -1,18 +0,0 @@ -require_relative 'base_service' - -class CreateDeploymentService < BaseService - def execute(deployable = nil) - environment = project.environments.find_or_create_by( - name: params[:environment] - ) - - project.deployments.create( - environment: environment, - ref: params[:ref], - tag: params[:tag], - sha: params[:sha], - user: current_user, - deployable: deployable - ) - end -end diff --git a/app/services/git_hooks_service.rb b/app/services/git_hooks_service.rb index d7a0c25a044..8f5c3393dfc 100644 --- a/app/services/git_hooks_service.rb +++ b/app/services/git_hooks_service.rb @@ -3,7 +3,7 @@ class GitHooksService def execute(user, repo_path, oldrev, newrev, ref) @repo_path = repo_path - @user = Gitlab::GlId.gl_id(user) + @user = Gitlab::ShellEnv.gl_id(user) @oldrev = oldrev @newrev = newrev @ref = ref diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb index f804ac171c4..91ca82ed3b7 100644 --- a/app/services/notification_service.rb +++ b/app/services/notification_service.rb @@ -173,26 +173,16 @@ class NotificationService end end - # Project access request - def new_project_access_request(project_member) - mailer.member_access_requested_email(project_member.real_source_type, project_member.id).deliver_later - end - - def decline_project_access_request(project_member) - mailer.member_access_denied_email(project_member.real_source_type, project_member.project.id, project_member.user.id).deliver_later - end - def invite_project_member(project_member, token) - mailer.member_invited_email(project_member.real_source_type, project_member.id, token).deliver_later + mailer.project_member_invited_email(project_member.id, token).deliver_later end def accept_project_invite(project_member) - mailer.member_invite_accepted_email(project_member.real_source_type, project_member.id).deliver_later + mailer.project_invite_accepted_email(project_member.id).deliver_later end def decline_project_invite(project_member) - mailer.member_invite_declined_email( - project_member.real_source_type, + mailer.project_invite_declined_email( project_member.project.id, project_member.invite_email, project_member.access_level, @@ -201,33 +191,23 @@ class NotificationService end def new_project_member(project_member) - mailer.member_access_granted_email(project_member.real_source_type, project_member.id).deliver_later + mailer.project_access_granted_email(project_member.id).deliver_later end def update_project_member(project_member) - mailer.member_access_granted_email(project_member.real_source_type, project_member.id).deliver_later - end - - # Group access request - def new_group_access_request(group_member) - mailer.member_access_requested_email(group_member.real_source_type, group_member.id).deliver_later - end - - def decline_group_access_request(group_member) - mailer.member_access_denied_email(group_member.real_source_type, group_member.group.id, group_member.user.id).deliver_later + mailer.project_access_granted_email(project_member.id).deliver_later end def invite_group_member(group_member, token) - mailer.member_invited_email(group_member.real_source_type, group_member.id, token).deliver_later + mailer.group_member_invited_email(group_member.id, token).deliver_later end def accept_group_invite(group_member) - mailer.member_invite_accepted_email(group_member.id).deliver_later + mailer.group_invite_accepted_email(group_member.id).deliver_later end def decline_group_invite(group_member) - mailer.member_invite_declined_email( - group_member.real_source_type, + mailer.group_invite_declined_email( group_member.group.id, group_member.invite_email, group_member.access_level, @@ -236,11 +216,11 @@ class NotificationService end def new_group_member(group_member) - mailer.member_access_granted_email(group_member.real_source_type, group_member.id).deliver_later + mailer.group_access_granted_email(group_member.id).deliver_later end def update_group_member(group_member) - mailer.member_access_granted_email(group_member.real_source_type, group_member.id).deliver_later + mailer.group_access_granted_email(group_member.id).deliver_later end def project_was_moved(project, old_path_with_namespace) @@ -299,11 +279,10 @@ class NotificationService end def users_with_global_level_watch(ids) - NotificationSetting.where( - user_id: ids, - source_type: nil, - level: NotificationSetting.levels[:watch] - ).pluck(:user_id) + User.where( + id: ids, + notification_level: NotificationSetting.levels[:watch] + ).pluck(:id) end # Build a list of users based on project notifcation settings @@ -373,9 +352,7 @@ class NotificationService users = users.reject(&:blocked?) users.reject do |user| - global_notification_setting = user.global_notification_setting - - next global_notification_setting.level == level unless project + next user.notification_level == level unless project setting = user.notification_settings_for(project) @@ -384,13 +361,13 @@ class NotificationService end # reject users who globally set mention notification and has no setting per project/group - next global_notification_setting.level == level unless setting + next user.notification_level == level unless setting # reject users who set mention notification in project next true if setting.level == level # reject users who have mention level in project and disabled in global settings - setting.global? && global_notification_setting.level == level + setting.global? && user.notification_level == level end end @@ -479,6 +456,7 @@ class NotificationService def build_recipients(target, project, current_user, action: nil, previous_assignee: nil) recipients = target.participants(current_user) + recipients = add_project_watchers(recipients, project) recipients = reject_mention_users(recipients, project) diff --git a/app/services/todo_service.rb b/app/services/todo_service.rb index e1f9ea64dc4..8e03ff8ddde 100644 --- a/app/services/todo_service.rb +++ b/app/services/todo_service.rb @@ -139,16 +139,10 @@ class TodoService pending_todos(user, attributes).update_all(state: :done) end - # When user marks an issue as todo - def mark_todo(issuable, current_user) - attributes = attributes_for_todo(issuable.project, issuable, current_user, Todo::MARKED) - create_todos(current_user, attributes) - end - private def create_todos(users, attributes) - Array(users).map do |user| + Array(users).each do |user| next if pending_todos(user, attributes).exists? Todo.create(attributes.merge(user_id: user.id)) end diff --git a/app/views/admin/background_jobs/_head.html.haml b/app/views/admin/background_jobs/_head.html.haml deleted file mode 100644 index d78682532ed..00000000000 --- a/app/views/admin/background_jobs/_head.html.haml +++ /dev/null @@ -1,14 +0,0 @@ -.nav-links.sub-nav - %ul{ class: (container_class) } - = nav_link(controller: :background_jobs) do - = link_to admin_background_jobs_path, title: 'Background Jobs' do - %span - Background Jobs - = nav_link(controller: :logs) do - = link_to admin_logs_path, title: 'Logs' do - %span - Logs - = nav_link(controller: :health_check) do - = link_to admin_health_check_path, title: 'Health Check' do - %span - Health Check diff --git a/app/views/admin/background_jobs/show.html.haml b/app/views/admin/background_jobs/show.html.haml index 654d261aa99..de5bc050cf0 100644 --- a/app/views/admin/background_jobs/show.html.haml +++ b/app/views/admin/background_jobs/show.html.haml @@ -1,50 +1,46 @@ -- @no_container = true - page_title "Background Jobs" -= render 'admin/background_jobs/head' +%h3.page-title Background Jobs +%p.light GitLab uses #{link_to "sidekiq", "http://sidekiq.org/"} library for async job processing -%div{ class: (container_class) } - %h3.page-title Background Jobs - %p.light GitLab uses #{link_to "sidekiq", "http://sidekiq.org/"} library for async job processing +%hr - %hr +.panel.panel-default + .panel-heading Sidekiq running processes + .panel-body + - if @sidekiq_processes.empty? + %h4.cred + %i.fa.fa-exclamation-triangle + There are no running sidekiq processes. Please restart GitLab + - else + .table-holder + %table.table + %thead + %th USER + %th PID + %th CPU + %th MEM + %th STATE + %th START + %th COMMAND + %tbody + - @sidekiq_processes.each do |process| + - next unless process.match(/(sidekiq \d+\.\d+\.\d+.+$)/) + - data = process.strip.split(' ') + %tr + %td= gitlab_config.user + - 5.times do + %td= data.shift + %td= data.join(' ') - .panel.panel-default - .panel-heading Sidekiq running processes - .panel-body - - if @sidekiq_processes.empty? - %h4.cred - %i.fa.fa-exclamation-triangle - There are no running sidekiq processes. Please restart GitLab - - else - .table-holder - %table.table - %thead - %th USER - %th PID - %th CPU - %th MEM - %th STATE - %th START - %th COMMAND - %tbody - - @sidekiq_processes.each do |process| - - next unless process.match(/(sidekiq \d+\.\d+\.\d+.+$)/) - - data = process.strip.split(' ') - %tr - %td= gitlab_config.user - - 5.times do - %td= data.shift - %td= data.join(' ') + .clearfix + %p + %i.fa.fa-exclamation-circle + If '[25 of 25 busy]' is shown, restart GitLab with 'sudo service gitlab reload'. + %p + %i.fa.fa-exclamation-circle + If more than one sidekiq process is listed, stop GitLab, kill the remaining sidekiq processes (sudo pkill -u #{gitlab_config.user} -f sidekiq) and restart GitLab. - .clearfix - %p - %i.fa.fa-exclamation-circle - If '[25 of 25 busy]' is shown, restart GitLab with 'sudo service gitlab reload'. - %p - %i.fa.fa-exclamation-circle - If more than one sidekiq process is listed, stop GitLab, kill the remaining sidekiq processes (sudo pkill -u #{gitlab_config.user} -f sidekiq) and restart GitLab. - - .panel.panel-default - %iframe{src: sidekiq_path, width: '100%', height: 970, style: "border: none"} +.panel.panel-default + %iframe{src: sidekiq_path, width: '100%', height: 970, style: "border: none"} diff --git a/app/views/admin/builds/index.html.haml b/app/views/admin/builds/index.html.haml index efd5b12cfeb..d74cf8598e8 100644 --- a/app/views/admin/builds/index.html.haml +++ b/app/views/admin/builds/index.html.haml @@ -1,54 +1,49 @@ -- @no_container = true -= render "admin/dashboard/head" - -%div{ class: (container_class) } - - .top-area - %ul.nav-links - %li{class: ('active' if @scope.nil?)} - = link_to admin_builds_path do - All - %span.badge.js-totalbuilds-count= @all_builds.count(:id) - - %li{class: ('active' if @scope == 'running')} - = link_to admin_builds_path(scope: :running) do - Running - %span.badge.js-running-count= number_with_delimiter(@all_builds.running_or_pending.count(:id)) - - %li{class: ('active' if @scope == 'finished')} - = link_to admin_builds_path(scope: :finished) do - Finished - %span.badge.js-running-count= number_with_delimiter(@all_builds.finished.count(:id)) - - .nav-controls - - if @all_builds.running_or_pending.any? - = link_to 'Cancel all', cancel_all_admin_builds_path, data: { confirm: 'Are you sure?' }, class: 'btn btn-danger', method: :post - - .row-content-block.second-block - #{(@scope || 'all').capitalize} builds - - %ul.content-list - - if @builds.blank? - %li - .nothing-here-block No builds to show - - else - .table-holder - %table.table.builds - %thead - %tr - %th Status - %th Build ID - %th Project - %th Commit - %th Ref - %th Runner - %th Name - %th Tags - %th Duration - %th Finished at - %th - - - @builds.each do |build| - = render "admin/builds/build", build: build - - = paginate @builds, theme: 'gitlab' +.top-area + %ul.nav-links + %li{class: ('active' if @scope.nil?)} + = link_to admin_builds_path do + All + %span.badge.js-totalbuilds-count= @all_builds.count(:id) + + %li{class: ('active' if @scope == 'running')} + = link_to admin_builds_path(scope: :running) do + Running + %span.badge.js-running-count= number_with_delimiter(@all_builds.running_or_pending.count(:id)) + + %li{class: ('active' if @scope == 'finished')} + = link_to admin_builds_path(scope: :finished) do + Finished + %span.badge.js-running-count= number_with_delimiter(@all_builds.finished.count(:id)) + + .nav-controls + - if @all_builds.running_or_pending.any? + = link_to 'Cancel all', cancel_all_admin_builds_path, data: { confirm: 'Are you sure?' }, class: 'btn btn-danger', method: :post + +.row-content-block.second-block + #{(@scope || 'all').capitalize} builds + +%ul.content-list + - if @builds.blank? + %li + .nothing-here-block No builds to show + - else + .table-holder + %table.table.builds + %thead + %tr + %th Status + %th Build ID + %th Project + %th Commit + %th Ref + %th Runner + %th Name + %th Tags + %th Duration + %th Finished at + %th + + - @builds.each do |build| + = render "admin/builds/build", build: build + + = paginate @builds, theme: 'gitlab' diff --git a/app/views/admin/dashboard/_head.html.haml b/app/views/admin/dashboard/_head.html.haml deleted file mode 100644 index 7b3f88c24df..00000000000 --- a/app/views/admin/dashboard/_head.html.haml +++ /dev/null @@ -1,22 +0,0 @@ -.nav-links.sub-nav - %ul{ class: (container_class) } - = nav_link(controller: :dashboard, html_options: {class: 'home'}) do - = link_to admin_root_path, title: 'Overview' do - %span - Overview - = nav_link(controller: [:admin, :projects]) do - = link_to admin_namespaces_projects_path, title: 'Projects' do - %span - Projects - = nav_link(controller: :users) do - = link_to admin_users_path, title: 'Users' do - %span - Users - = nav_link(controller: :groups) do - = link_to admin_groups_path, title: 'Groups' do - %span - Groups - = nav_link path: 'builds#index' do - = link_to admin_builds_path, title: 'Builds' do - %span - Builds diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml index 4682016a886..6dd2fef395d 100644 --- a/app/views/admin/dashboard/index.html.haml +++ b/app/views/admin/dashboard/index.html.haml @@ -1,159 +1,155 @@ -- @no_container = true -= render "admin/dashboard/head" +.admin-dashboard.prepend-top-default + .row + .col-md-4 + %h4 Statistics + %hr + %p + Forks + %span.light.pull-right + = number_with_delimiter(ForkedProjectLink.count) + %p + Issues + %span.light.pull-right + = number_with_delimiter(Issue.count) + %p + Merge Requests + %span.light.pull-right + = number_with_delimiter(MergeRequest.count) + %p + Notes + %span.light.pull-right + = number_with_delimiter(Note.count) + %p + Snippets + %span.light.pull-right + = number_with_delimiter(Snippet.count) + %p + SSH Keys + %span.light.pull-right + = number_with_delimiter(Key.count) + %p + Milestones + %span.light.pull-right + = number_with_delimiter(Milestone.count) + %p + Active Users + %span.light.pull-right + = number_with_delimiter(User.active.count) + .col-md-4 + %h4 + Features + %hr + %p + Sign up + %span.light.pull-right + = boolean_to_icon signup_enabled? + %p + LDAP + %span.light.pull-right + = boolean_to_icon Gitlab.config.ldap.enabled + %p + Gravatar + %span.light.pull-right + = boolean_to_icon gravatar_enabled? + %p + OmniAuth + %span.light.pull-right + = boolean_to_icon Gitlab.config.omniauth.enabled + %p + Reply by email + %span.light.pull-right + = boolean_to_icon Gitlab::IncomingEmail.enabled? + .col-md-4 + %h4 + Components + - if current_application_settings.version_check_enabled + .pull-right + = version_status_badge -%div{ class: (container_class) } - .admin-dashboard.prepend-top-default - .row - .col-md-4 - %h4 Statistics - %hr - %p - Forks - %span.light.pull-right - = number_with_delimiter(ForkedProjectLink.count) - %p - Issues - %span.light.pull-right - = number_with_delimiter(Issue.count) - %p - Merge Requests - %span.light.pull-right - = number_with_delimiter(MergeRequest.count) - %p - Notes - %span.light.pull-right - = number_with_delimiter(Note.count) - %p - Snippets - %span.light.pull-right - = number_with_delimiter(Snippet.count) - %p - SSH Keys - %span.light.pull-right - = number_with_delimiter(Key.count) - %p - Milestones - %span.light.pull-right - = number_with_delimiter(Milestone.count) - %p - Active Users - %span.light.pull-right - = number_with_delimiter(User.active.count) - .col-md-4 - %h4 - Features - %hr - %p - Sign up - %span.light.pull-right - = boolean_to_icon signup_enabled? - %p - LDAP - %span.light.pull-right - = boolean_to_icon Gitlab.config.ldap.enabled - %p - Gravatar - %span.light.pull-right - = boolean_to_icon gravatar_enabled? - %p - OmniAuth - %span.light.pull-right - = boolean_to_icon Gitlab.config.omniauth.enabled - %p - Reply by email - %span.light.pull-right - = boolean_to_icon Gitlab::IncomingEmail.enabled? - .col-md-4 - %h4 - Components - - if current_application_settings.version_check_enabled - .pull-right - = version_status_badge + %hr + %p + GitLab + %span.pull-right + = Gitlab::VERSION + %p + GitLab Shell + %span.pull-right + = Gitlab::Shell.new.version + %p + GitLab API + %span.pull-right + = API::API::version + %p + Git + %span.pull-right + = Gitlab::Git.version + %p + Ruby + %span.pull-right + #{RUBY_VERSION}p#{RUBY_PATCHLEVEL} - %hr - %p - GitLab - %span.pull-right - = Gitlab::VERSION - %p - GitLab Shell - %span.pull-right - = Gitlab::Shell.new.version - %p - GitLab API - %span.pull-right - = API::API::version - %p - Git - %span.pull-right - = Gitlab::Git.version - %p - Ruby - %span.pull-right - #{RUBY_VERSION}p#{RUBY_PATCHLEVEL} + %p + Rails + %span.pull-right + #{Rails::VERSION::STRING} - %p - Rails - %span.pull-right - #{Rails::VERSION::STRING} + %p + = Gitlab::Database.adapter_name + %span.pull-right + = Gitlab::Database.version + %hr + .row + .col-sm-4 + .light-well + %h4 Projects + .data + = link_to admin_namespaces_projects_path do + %h1= number_with_delimiter(Project.count) + %hr + = link_to('New Project', new_project_path, class: "btn btn-new") + .col-sm-4 + .light-well + %h4 Users + .data + = link_to admin_users_path do + %h1= number_with_delimiter(User.count) + %hr + = link_to 'New User', new_admin_user_path, class: "btn btn-new" + .col-sm-4 + .light-well + %h4 Groups + .data + = link_to admin_groups_path do + %h1= number_with_delimiter(Group.count) + %hr + = link_to 'New Group', new_admin_group_path, class: "btn btn-new" + .row.prepend-top-10 + .col-md-4 + %h4 Latest projects + %hr + - @projects.each do |project| %p - = Gitlab::Database.adapter_name - %span.pull-right - = Gitlab::Database.version - %hr - .row - .col-sm-4 - .light-well - %h4 Projects - .data - = link_to admin_namespaces_projects_path do - %h1= number_with_delimiter(Project.count) - %hr - = link_to('New Project', new_project_path, class: "btn btn-new") - .col-sm-4 - .light-well - %h4 Users - .data - = link_to admin_users_path do - %h1= number_with_delimiter(User.count) - %hr - = link_to 'New User', new_admin_user_path, class: "btn btn-new" - .col-sm-4 - .light-well - %h4 Groups - .data - = link_to admin_groups_path do - %h1= number_with_delimiter(Group.count) - %hr - = link_to 'New Group', new_admin_group_path, class: "btn btn-new" - - .row.prepend-top-10 - .col-md-4 - %h4 Latest projects - %hr - - @projects.each do |project| - %p - = link_to project.name_with_namespace, [:admin, project.namespace.becomes(Namespace), project], class: 'str-truncated' - %span.light.pull-right - #{time_ago_with_tooltip(project.created_at)} + = link_to project.name_with_namespace, [:admin, project.namespace.becomes(Namespace), project], class: 'str-truncated' + %span.light.pull-right + #{time_ago_with_tooltip(project.created_at)} - .col-md-4 - %h4 Latest users - %hr - - @users.each do |user| - %p - = link_to [:admin, user], class: 'str-truncated' do - = user.name - %span.light.pull-right - #{time_ago_with_tooltip(user.created_at)} + .col-md-4 + %h4 Latest users + %hr + - @users.each do |user| + %p + = link_to [:admin, user], class: 'str-truncated' do + = user.name + %span.light.pull-right + #{time_ago_with_tooltip(user.created_at)} - .col-md-4 - %h4 Latest groups - %hr - - @groups.each do |group| - %p - = link_to [:admin, group], class: 'str-truncated' do - = group.name - %span.light.pull-right - #{time_ago_with_tooltip(group.created_at)} + .col-md-4 + %h4 Latest groups + %hr + - @groups.each do |group| + %p + = link_to [:admin, group], class: 'str-truncated' do + = group.name + %span.light.pull-right + #{time_ago_with_tooltip(group.created_at)} diff --git a/app/views/admin/groups/index.html.haml b/app/views/admin/groups/index.html.haml index 4f1996ef7ab..775072a7441 100644 --- a/app/views/admin/groups/index.html.haml +++ b/app/views/admin/groups/index.html.haml @@ -1,45 +1,41 @@ -- @no_container = true - page_title "Groups" -= render "admin/dashboard/head" +%h3.page-title + Groups (#{number_with_delimiter(@groups.total_count)}) -%div{ class: (container_class) } - %h3.page-title - Groups (#{number_with_delimiter(@groups.total_count)}) +%p.light + Group allows you to keep projects organized. + Use groups for uniting related projects. - %p.light - Group allows you to keep projects organized. - Use groups for uniting related projects. +.top-area + .nav-search + = form_tag admin_groups_path, method: :get, class: 'form-inline' do + = hidden_field_tag :sort, @sort + = text_field_tag :name, params[:name], class: "form-control" + = button_tag "Search", class: "btn submit btn-primary" - .top-area - .nav-search - = form_tag admin_groups_path, method: :get, class: 'form-inline' do - = hidden_field_tag :sort, @sort - = text_field_tag :name, params[:name], class: "form-control" - = button_tag "Search", class: "btn submit btn-primary" - - .nav-controls - .dropdown.inline - %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"} - %span.light - - if @sort.present? - = sort_options_hash[@sort] - - else + .nav-controls + .dropdown.inline + %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"} + %span.light + - if @sort.present? + = sort_options_hash[@sort] + - else + = sort_title_recently_created + %b.caret + %ul.dropdown-menu + %li + = link_to admin_groups_path(sort: sort_value_recently_created) do = sort_title_recently_created - %b.caret - %ul.dropdown-menu - %li - = link_to admin_groups_path(sort: sort_value_recently_created) do - = sort_title_recently_created - = link_to admin_groups_path(sort: sort_value_oldest_created) do - = sort_title_oldest_created - = link_to admin_groups_path(sort: sort_value_recently_updated) do - = sort_title_recently_updated - = link_to admin_groups_path(sort: sort_value_oldest_updated) do - = sort_title_oldest_updated - = link_to 'New Group', new_admin_group_path, class: "btn btn-new" + = link_to admin_groups_path(sort: sort_value_oldest_created) do + = sort_title_oldest_created + = link_to admin_groups_path(sort: sort_value_recently_updated) do + = sort_title_recently_updated + = link_to admin_groups_path(sort: sort_value_oldest_updated) do + = sort_title_oldest_updated + = link_to 'New Group', new_admin_group_path, class: "btn btn-new" - %ul.content-list - - @groups.each do |group| - = render 'group', group: group +%ul.content-list + - @groups.each do |group| + = render 'group', group: group - = paginate @groups, theme: "gitlab" += paginate @groups, theme: "gitlab" diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml index 5b8a0262ea0..f309e80a39a 100644 --- a/app/views/admin/groups/show.html.haml +++ b/app/views/admin/groups/show.html.haml @@ -109,7 +109,7 @@ %span.pull-right.light = member.human_access - if can?(current_user, :destroy_group_member, member) - = link_to group_group_member_path(@group, member), data: { confirm: remove_member_message(member) }, method: :delete, remote: true, class: "btn-xs btn btn-remove", title: 'Remove user from group' do + = link_to group_group_member_path(@group, member), data: { confirm: remove_user_from_group_message(@group, member) }, method: :delete, remote: true, class: "btn-xs btn btn-remove", title: 'Remove user from group' do %i.fa.fa-minus.fa-inverse .panel-footer = paginate @members, param_name: 'members_page', theme: 'gitlab' diff --git a/app/views/admin/health_check/show.html.haml b/app/views/admin/health_check/show.html.haml index 7b8407f9152..c2313986a7f 100644 --- a/app/views/admin/health_check/show.html.haml +++ b/app/views/admin/health_check/show.html.haml @@ -1,52 +1,49 @@ -- @no_container = true - page_title "Health Check" -= render 'admin/background_jobs/head' -%div{ class: (container_class) } - %h3.page-title - Health Check - .bs-callout.clearfix - .pull-left - %p - Access token is - %code#health-check-token= current_application_settings.health_check_access_token - = button_to reset_health_check_token_admin_application_settings_path, - method: :put, class: 'btn btn-default', - data: { confirm: 'Are you sure you want to reset the health check token?' } do - = icon('refresh') - Reset health check access token - %p.light - Health information can be retrieved as plain text, JSON, or XML using: - %ul - %li - %code= health_check_url(token: current_application_settings.health_check_access_token) - %li - %code= health_check_url(token: current_application_settings.health_check_access_token, format: :json) - %li - %code= health_check_url(token: current_application_settings.health_check_access_token, format: :xml) +%h3.page-title + Health Check +.bs-callout.clearfix + .pull-left + %p + Access token is + %code#health-check-token= current_application_settings.health_check_access_token + = button_to reset_health_check_token_admin_application_settings_path, + method: :put, class: 'btn btn-default', + data: { confirm: 'Are you sure you want to reset the health check token?' } do + = icon('refresh') + Reset health check access token +%p.light + Health information can be retrieved as plain text, JSON, or XML using: + %ul + %li + %code= health_check_url(token: current_application_settings.health_check_access_token) + %li + %code= health_check_url(token: current_application_settings.health_check_access_token, format: :json) + %li + %code= health_check_url(token: current_application_settings.health_check_access_token, format: :xml) - %p.light - You can also ask for the status of specific services: - %ul - %li - %code= health_check_url(token: current_application_settings.health_check_access_token, checks: :cache) - %li - %code= health_check_url(token: current_application_settings.health_check_access_token, checks: :database) - %li - %code= health_check_url(token: current_application_settings.health_check_access_token, checks: :migrations) +%p.light + You can also ask for the status of specific services: + %ul + %li + %code= health_check_url(token: current_application_settings.health_check_access_token, checks: :cache) + %li + %code= health_check_url(token: current_application_settings.health_check_access_token, checks: :database) + %li + %code= health_check_url(token: current_application_settings.health_check_access_token, checks: :migrations) - %hr - .panel.panel-default - .panel-heading - Current Status: - - if @errors.blank? - = icon('circle', class: 'cgreen') - Healthy - - else - = icon('warning', class: 'cred') - Unhealthy - .panel-body - - if @errors.blank? - No Health Problems Detected - - else - = @errors +%hr +.panel.panel-default + .panel-heading + Current Status: + - if @errors.blank? + = icon('circle', class: 'cgreen') + Healthy + - else + = icon('warning', class: 'cred') + Unhealthy + .panel-body + - if @errors.blank? + No Health Problems Detected + - else + = @errors diff --git a/app/views/admin/logs/show.html.haml b/app/views/admin/logs/show.html.haml index 5ddc3b9ea85..698feb571ac 100644 --- a/app/views/admin/logs/show.html.haml +++ b/app/views/admin/logs/show.html.haml @@ -1,32 +1,28 @@ -- @no_container = true - page_title "Logs" - loggers = [Gitlab::GitLogger, Gitlab::AppLogger, Gitlab::ProductionLogger, Gitlab::SidekiqLogger, Gitlab::RepositoryCheckLogger] -= render 'admin/background_jobs/head' - -%div{ class: (container_class) } - %ul.nav-links.log-tabs - - loggers.each do |klass| - %li{ class: (klass == Gitlab::GitLogger ? 'active' : '') } - = link_to klass::file_name, "##{klass::file_name_noext}", - 'data-toggle' => 'tab' - .row-content-block - To prevent performance issues admin logs output the last 2000 lines - .tab-content - - loggers.each do |klass| - .tab-pane{ class: (klass == Gitlab::GitLogger ? 'active' : ''), - id: klass::file_name_noext } - .file-holder#README - .file-title - %i.fa.fa-file - = klass::file_name - .pull-right - = link_to '#', class: 'log-bottom' do - %i.fa.fa-arrow-down - Scroll down - .file-content.logs - %ol - - klass.read_latest.each do |line| - %li - %p= line +%ul.nav-links.log-tabs + - loggers.each do |klass| + %li{ class: (klass == Gitlab::GitLogger ? 'active' : '') } + = link_to klass::file_name, "##{klass::file_name_noext}", + 'data-toggle' => 'tab' +.row-content-block + To prevent performance issues admin logs output the last 2000 lines +.tab-content + - loggers.each do |klass| + .tab-pane{ class: (klass == Gitlab::GitLogger ? 'active' : ''), + id: klass::file_name_noext } + .file-holder#README + .file-title + %i.fa.fa-file + = klass::file_name + .pull-right + = link_to '#', class: 'log-bottom' do + %i.fa.fa-arrow-down + Scroll down + .file-content.logs + %ol + - klass.read_latest.each do |line| + %li + %p= line diff --git a/app/views/admin/projects/index.html.haml b/app/views/admin/projects/index.html.haml index 4822cb693c2..aa07afa0d62 100644 --- a/app/views/admin/projects/index.html.haml +++ b/app/views/admin/projects/index.html.haml @@ -1,97 +1,94 @@ -- @no_container = true - page_title "Projects" = render 'shared/show_aside' -= render "admin/dashboard/head" -%div{ class: (container_class) } - .row.prepend-top-default - %aside.col-md-3 - .panel.admin-filter - = form_tag admin_namespaces_projects_path, method: :get, class: '' do - .form-group - = label_tag :name, 'Name:' - = text_field_tag :name, params[:name], class: "form-control" +.row.prepend-top-default + %aside.col-md-3 + .panel.admin-filter + = form_tag admin_namespaces_projects_path, method: :get, class: '' do + .form-group + = label_tag :name, 'Name:' + = text_field_tag :name, params[:name], class: "form-control" - .form-group - = label_tag :namespace_id, "Namespace" - = namespace_select_tag :namespace_id, selected: params[:namespace_id], class: 'input-large' + .form-group + = label_tag :namespace_id, "Namespace" + = namespace_select_tag :namespace_id, selected: params[:namespace_id], class: 'input-large' - .form-group - %strong Activity - .checkbox - = label_tag :with_push do - = check_box_tag :with_push, 1, params[:with_push] - %span Projects with push events - .checkbox - = label_tag :abandoned do - = check_box_tag :abandoned, 1, params[:abandoned] - %span No activity over 6 month - .checkbox - = label_tag :with_archived do - = check_box_tag :with_archived, 1, params[:with_archived] - %span Show archived projects + .form-group + %strong Activity + .checkbox + = label_tag :with_push do + = check_box_tag :with_push, 1, params[:with_push] + %span Projects with push events + .checkbox + = label_tag :abandoned do + = check_box_tag :abandoned, 1, params[:abandoned] + %span No activity over 6 month + .checkbox + = label_tag :with_archived do + = check_box_tag :with_archived, 1, params[:with_archived] + %span Show archived projects - %fieldset - %strong Visibility level: - .visibility-levels - - Project.visibility_levels.each do |label, level| - .checkbox - %label - = check_box_tag 'visibility_levels[]', level, params[:visibility_levels].present? && params[:visibility_levels].include?(level.to_s) - %span.descr - = visibility_level_icon(level) - = label - %fieldset - %strong Problems - .checkbox - = label_tag :last_repository_check_failed do - = check_box_tag :last_repository_check_failed, 1, params[:last_repository_check_failed] - %span Last repository check failed + %fieldset + %strong Visibility level: + .visibility-levels + - Project.visibility_levels.each do |label, level| + .checkbox + %label + = check_box_tag 'visibility_levels[]', level, params[:visibility_levels].present? && params[:visibility_levels].include?(level.to_s) + %span.descr + = visibility_level_icon(level) + = label + %fieldset + %strong Problems + .checkbox + = label_tag :last_repository_check_failed do + = check_box_tag :last_repository_check_failed, 1, params[:last_repository_check_failed] + %span Last repository check failed - = hidden_field_tag :sort, params[:sort] - = button_tag "Search", class: "btn submit btn-primary" - = link_to "Reset", admin_namespaces_projects_path, class: "btn btn-cancel" + = hidden_field_tag :sort, params[:sort] + = button_tag "Search", class: "btn submit btn-primary" + = link_to "Reset", admin_namespaces_projects_path, class: "btn btn-cancel" - %section.col-md-9 - .panel.panel-default - .panel-heading - Projects (#{@projects.total_count}) - .controls - .dropdown.inline - %button.dropdown-toggle.btn.btn-sm{type: 'button', 'data-toggle' => 'dropdown'} - %span.light - - if @sort.present? - = sort_options_hash[@sort] - - else + %section.col-md-9 + .panel.panel-default + .panel-heading + Projects (#{@projects.total_count}) + .controls + .dropdown.inline + %button.dropdown-toggle.btn.btn-sm{type: 'button', 'data-toggle' => 'dropdown'} + %span.light + - if @sort.present? + = sort_options_hash[@sort] + - else + = sort_title_recently_created + %b.caret + %ul.dropdown-menu + %li + = link_to admin_namespaces_projects_path(sort: sort_value_recently_created) do = sort_title_recently_created - %b.caret - %ul.dropdown-menu - %li - = link_to admin_namespaces_projects_path(sort: sort_value_recently_created) do - = sort_title_recently_created - = link_to admin_namespaces_projects_path(sort: sort_value_oldest_created) do - = sort_title_oldest_created - = link_to admin_namespaces_projects_path(sort: sort_value_recently_updated) do - = sort_title_recently_updated - = link_to admin_namespaces_projects_path(sort: sort_value_oldest_updated) do - = sort_title_oldest_updated - = link_to admin_namespaces_projects_path(sort: sort_value_largest_repo) do - = sort_title_largest_repo - = link_to 'New Project', new_project_path, class: "btn btn-sm btn-success" - %ul.well-list - - @projects.each do |project| - %li - .list-item-name - %span{ class: visibility_level_color(project.visibility_level) } - = visibility_level_icon(project.visibility_level) - = link_to project.name_with_namespace, [:admin, project.namespace.becomes(Namespace), project] - .pull-right - - if project.archived - %span.label.label-warning archived - %span.label.label-gray - = repository_size(project) - = link_to 'Edit', edit_namespace_project_path(project.namespace, project), id: "edit_#{dom_id(project)}", class: "btn btn-sm" - = link_to 'Destroy', [project.namespace.becomes(Namespace), project], data: { confirm: remove_project_message(project) }, method: :delete, class: "btn btn-sm btn-remove" - - if @projects.blank? - .nothing-here-block 0 projects matches - = paginate @projects, theme: "gitlab" + = link_to admin_namespaces_projects_path(sort: sort_value_oldest_created) do + = sort_title_oldest_created + = link_to admin_namespaces_projects_path(sort: sort_value_recently_updated) do + = sort_title_recently_updated + = link_to admin_namespaces_projects_path(sort: sort_value_oldest_updated) do + = sort_title_oldest_updated + = link_to admin_namespaces_projects_path(sort: sort_value_largest_repo) do + = sort_title_largest_repo + = link_to 'New Project', new_project_path, class: "btn btn-sm btn-success" + %ul.well-list + - @projects.each do |project| + %li + .list-item-name + %span{ class: visibility_level_color(project.visibility_level) } + = visibility_level_icon(project.visibility_level) + = link_to project.name_with_namespace, [:admin, project.namespace.becomes(Namespace), project] + .pull-right + - if project.archived + %span.label.label-warning archived + %span.label.label-gray + = repository_size(project) + = link_to 'Edit', edit_namespace_project_path(project.namespace, project), id: "edit_#{dom_id(project)}", class: "btn btn-sm" + = link_to 'Destroy', [project.namespace.becomes(Namespace), project], data: { confirm: remove_project_message(project) }, method: :delete, class: "btn btn-sm btn-remove" + - if @projects.blank? + .nothing-here-block 0 projects matches + = paginate @projects, theme: "gitlab" diff --git a/app/views/admin/projects/show.html.haml b/app/views/admin/projects/show.html.haml index 9e55a562e18..73986d21bcf 100644 --- a/app/views/admin/projects/show.html.haml +++ b/app/views/admin/projects/show.html.haml @@ -142,7 +142,7 @@ %i.fa.fa-pencil-square-o %ul.well-list - @group_members.each do |member| - = render 'shared/members/member', member: member, show_controls: false + = render 'groups/group_members/group_member', member: member, show_controls: false .panel-footer = paginate @group_members, param_name: 'group_members_page', theme: 'gitlab' @@ -172,7 +172,7 @@ %span.light Owner - else %span.light= project_member.human_access - = link_to namespace_project_project_member_path(@project.namespace, @project, project_member), data: { confirm: remove_member_message(project_member)}, method: :delete, remote: true, class: "btn btn-sm btn-remove" do + = link_to namespace_project_project_member_path(@project.namespace, @project, project_member), data: { confirm: remove_from_project_team_message(@project, project_member)}, method: :delete, remote: true, class: "btn btn-sm btn-remove" do %i.fa.fa-times .panel-footer = paginate @project_members, param_name: 'project_members_page', theme: 'gitlab' diff --git a/app/views/admin/users/groups.html.haml b/app/views/admin/users/groups.html.haml index b0a709a568a..dbecb7bbfd6 100644 --- a/app/views/admin/users/groups.html.haml +++ b/app/views/admin/users/groups.html.haml @@ -13,7 +13,7 @@ .pull-right %span.light= group_member.human_access - unless group_member.owner? - = link_to group_group_member_path(group, group_member), data: { confirm: remove_member_message(group_member) }, method: :delete, remote: true, class: "btn-xs btn btn-remove", title: 'Remove user from group' do + = link_to group_group_member_path(group, group_member), data: { confirm: remove_user_from_group_message(group, group_member) }, method: :delete, remote: true, class: "btn-xs btn btn-remove", title: 'Remove user from group' do %i.fa.fa-times.fa-inverse - else .nothing-here-block This user has no groups. diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml index d0a696da64b..d6743081c8e 100644 --- a/app/views/admin/users/index.html.haml +++ b/app/views/admin/users/index.html.haml @@ -1,110 +1,107 @@ -- @no_container = true - page_title "Users" = render 'shared/show_aside' -= render "admin/dashboard/head" -%div{ class: (container_class) } - .admin-filter - %ul.nav-links - %li{class: "#{'active' unless params[:filter]}"} - = link_to admin_users_path do - Active - %small.badge= number_with_delimiter(User.active.count) - %li{class: "#{'active' if params[:filter] == "admins"}"} - = link_to admin_users_path(filter: "admins") do - Admins - %small.badge= number_with_delimiter(User.admins.count) - %li.filter-two-factor-enabled{class: "#{'active' if params[:filter] == 'two_factor_enabled'}"} - = link_to admin_users_path(filter: 'two_factor_enabled') do - 2FA Enabled - %small.badge= number_with_delimiter(User.with_two_factor.count) - %li.filter-two-factor-disabled{class: "#{'active' if params[:filter] == 'two_factor_disabled'}"} - = link_to admin_users_path(filter: 'two_factor_disabled') do - 2FA Disabled - %small.badge= number_with_delimiter(User.without_two_factor.count) - %li.filter-external{class: "#{'active' if params[:filter] == 'external'}"} - = link_to admin_users_path(filter: 'external') do - External - %small.badge= number_with_delimiter(User.external.count) - %li{class: "#{'active' if params[:filter] == "blocked"}"} - = link_to admin_users_path(filter: "blocked") do - Blocked - %small.badge= number_with_delimiter(User.blocked.count) - %li{class: "#{'active' if params[:filter] == "wop"}"} - = link_to admin_users_path(filter: "wop") do - Without projects - %small.badge= number_with_delimiter(User.without_projects.count) +.admin-filter + %ul.nav-links + %li{class: "#{'active' unless params[:filter]}"} + = link_to admin_users_path do + Active + %small.badge= number_with_delimiter(User.active.count) + %li{class: "#{'active' if params[:filter] == "admins"}"} + = link_to admin_users_path(filter: "admins") do + Admins + %small.badge= number_with_delimiter(User.admins.count) + %li.filter-two-factor-enabled{class: "#{'active' if params[:filter] == 'two_factor_enabled'}"} + = link_to admin_users_path(filter: 'two_factor_enabled') do + 2FA Enabled + %small.badge= number_with_delimiter(User.with_two_factor.count) + %li.filter-two-factor-disabled{class: "#{'active' if params[:filter] == 'two_factor_disabled'}"} + = link_to admin_users_path(filter: 'two_factor_disabled') do + 2FA Disabled + %small.badge= number_with_delimiter(User.without_two_factor.count) + %li.filter-external{class: "#{'active' if params[:filter] == 'external'}"} + = link_to admin_users_path(filter: 'external') do + External + %small.badge= number_with_delimiter(User.external.count) + %li{class: "#{'active' if params[:filter] == "blocked"}"} + = link_to admin_users_path(filter: "blocked") do + Blocked + %small.badge= number_with_delimiter(User.blocked.count) + %li{class: "#{'active' if params[:filter] == "wop"}"} + = link_to admin_users_path(filter: "wop") do + Without projects + %small.badge= number_with_delimiter(User.without_projects.count) - .row-content-block.second-block - .pull-right - .dropdown.inline - %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"} - %span.light - - if @sort.present? - = sort_options_hash[@sort] - - else + .row-content-block.second-block + .pull-right + .dropdown.inline + %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"} + %span.light + - if @sort.present? + = sort_options_hash[@sort] + - else + = sort_title_name + %b.caret + %ul.dropdown-menu + %li + = link_to admin_users_path(sort: sort_value_name, filter: params[:filter]) do = sort_title_name - %b.caret - %ul.dropdown-menu - %li - = link_to admin_users_path(sort: sort_value_name, filter: params[:filter]) do - = sort_title_name - = link_to admin_users_path(sort: sort_value_recently_signin, filter: params[:filter]) do - = sort_title_recently_signin - = link_to admin_users_path(sort: sort_value_oldest_signin, filter: params[:filter]) do - = sort_title_oldest_signin - = link_to admin_users_path(sort: sort_value_recently_created, filter: params[:filter]) do - = sort_title_recently_created - = link_to admin_users_path(sort: sort_value_oldest_created, filter: params[:filter]) do - = sort_title_oldest_created - = link_to admin_users_path(sort: sort_value_recently_updated, filter: params[:filter]) do - = sort_title_recently_updated - = link_to admin_users_path(sort: sort_value_oldest_updated, filter: params[:filter]) do - = sort_title_oldest_updated + = link_to admin_users_path(sort: sort_value_recently_signin, filter: params[:filter]) do + = sort_title_recently_signin + = link_to admin_users_path(sort: sort_value_oldest_signin, filter: params[:filter]) do + = sort_title_oldest_signin + = link_to admin_users_path(sort: sort_value_recently_created, filter: params[:filter]) do + = sort_title_recently_created + = link_to admin_users_path(sort: sort_value_oldest_created, filter: params[:filter]) do + = sort_title_oldest_created + = link_to admin_users_path(sort: sort_value_recently_updated, filter: params[:filter]) do + = sort_title_recently_updated + = link_to admin_users_path(sort: sort_value_oldest_updated, filter: params[:filter]) do + = sort_title_oldest_updated - = link_to 'New User', new_admin_user_path, class: "btn btn-new" - = form_tag admin_users_path, method: :get, class: 'form-inline' do - .form-group - = search_field_tag :name, params[:name], placeholder: 'Name, email or username', class: 'form-control', spellcheck: false - = hidden_field_tag "filter", params[:filter] - = button_tag class: 'btn btn-primary' do - %i.fa.fa-search + = link_to 'New User', new_admin_user_path, class: "btn btn-new" + = form_tag admin_users_path, method: :get, class: 'form-inline' do + .form-group + = search_field_tag :name, params[:name], placeholder: 'Name, email or username', class: 'form-control', spellcheck: false + = hidden_field_tag "filter", params[:filter] + = button_tag class: 'btn btn-primary' do + %i.fa.fa-search - .panel.panel-default - %ul.well-list - - @users.each do |user| - %li - .list-item-name - - if user.blocked? - = icon("lock", class: "cred") - - else - = icon("user", class: "cgreen") - = link_to user.name, [:admin, user] - - if user.admin? - %strong.cred (Admin) - - if user.external? - %strong.cred (External) - - if user == current_user - %span.cred It's you! +.panel.panel-default + %ul.well-list + - @users.each do |user| + %li + .list-item-name + - if user.blocked? + = icon("lock", class: "cred") + - else + = icon("user", class: "cgreen") + = link_to user.name, [:admin, user] + - if user.admin? + %strong.cred (Admin) + - if user.external? + %strong.cred (External) + - if user == current_user + %span.cred It's you! + .pull-right + %span.light + %i.fa.fa-envelope + = mail_to user.email, user.email, class: 'light' + .pull-right - %span.light - %i.fa.fa-envelope - = mail_to user.email, user.email, class: 'light' - - .pull-right - = link_to 'Edit', edit_admin_user_path(user), id: "edit_#{dom_id(user)}", class: 'btn-grouped btn btn-xs' - - unless user == current_user - - if user.ldap_blocked? - = link_to '#', title: 'Cannot unblock LDAP blocked users', data: {toggle: 'tooltip'}, class: 'btn-grouped btn btn-xs btn-success disabled' do - %i.fa.fa-lock - Unblock - - elsif user.blocked? - = link_to 'Unblock', unblock_admin_user_path(user), method: :put, class: 'btn-grouped btn btn-xs btn-success' - - else - = link_to 'Block', block_admin_user_path(user), data: {confirm: 'USER WILL BE BLOCKED! Are you sure?'}, method: :put, class: 'btn-grouped btn btn-xs btn-warning' - - if user.access_locked? - = link_to 'Unlock', unlock_admin_user_path(user), method: :put, class: 'btn-grouped btn btn-xs btn-success', data: { confirm: 'Are you sure?' } - - if user.can_be_removed? - = link_to 'Destroy', [:admin, user], data: { confirm: "USER #{user.name} WILL BE REMOVED! All issues, merge requests and groups linked to this user will also be removed! Maybe block the user instead? Are you sure?" }, method: :delete, class: 'btn-grouped btn btn-xs btn-remove' - = paginate @users, theme: "gitlab" + = link_to 'Edit', edit_admin_user_path(user), id: "edit_#{dom_id(user)}", class: 'btn-grouped btn btn-xs' + - unless user == current_user + - if user.ldap_blocked? + = link_to '#', title: 'Cannot unblock LDAP blocked users', data: {toggle: 'tooltip'}, class: 'btn-grouped btn btn-xs btn-success disabled' do + %i.fa.fa-lock + Unblock + - elsif user.blocked? + = link_to 'Unblock', unblock_admin_user_path(user), method: :put, class: 'btn-grouped btn btn-xs btn-success' + - else + = link_to 'Block', block_admin_user_path(user), data: {confirm: 'USER WILL BE BLOCKED! Are you sure?'}, method: :put, class: 'btn-grouped btn btn-xs btn-warning' + - if user.access_locked? + = link_to 'Unlock', unlock_admin_user_path(user), method: :put, class: 'btn-grouped btn btn-xs btn-success', data: { confirm: 'Are you sure?' } + - if user.can_be_removed? + = link_to 'Destroy', [:admin, user], data: { confirm: "USER #{user.name} WILL BE REMOVED! All issues, merge requests and groups linked to this user will also be removed! Maybe block the user instead? Are you sure?" }, method: :delete, class: 'btn-grouped btn btn-xs btn-remove' += paginate @users, theme: "gitlab" diff --git a/app/views/admin/users/projects.html.haml b/app/views/admin/users/projects.html.haml index 84b9ceb23b3..b655b2a15f5 100644 --- a/app/views/admin/users/projects.html.haml +++ b/app/views/admin/users/projects.html.haml @@ -38,5 +38,6 @@ %span.light= member.human_access - if member.respond_to? :project - = link_to namespace_project_project_member_path(project.namespace, project, member), data: { confirm: remove_member_message(member) }, remote: true, method: :delete, class: "btn-xs btn btn-remove", title: 'Remove user from project' do + = link_to namespace_project_project_member_path(project.namespace, project, member), data: { confirm: remove_from_project_team_message(project, member) }, remote: true, method: :delete, class: "btn-xs btn btn-remove", title: 'Remove user from project' do %i.fa.fa-times + diff --git a/app/views/dashboard/issues.atom.builder b/app/views/dashboard/issues.atom.builder index 0404d0728ea..83c0c6da21b 100644 --- a/app/views/dashboard/issues.atom.builder +++ b/app/views/dashboard/issues.atom.builder @@ -4,7 +4,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear xml.link href: issues_dashboard_url(format: :atom, private_token: current_user.try(:private_token)), rel: "self", type: "application/atom+xml" xml.link href: issues_dashboard_url, rel: "alternate", type: "text/html" xml.id issues_dashboard_url - xml.updated @issues.first.created_at.xmlschema if @issues.reorder(nil).any? + xml.updated @issues.first.created_at.xmlschema if @issues.any? - xml << render(partial: 'issues/issue', collection: @issues) if @issues.reorder(nil).any? + xml << render(partial: 'issues/issue', collection: @issues) if @issues.any? end diff --git a/app/views/groups/group_members/_group_member.html.haml b/app/views/groups/group_members/_group_member.html.haml new file mode 100644 index 00000000000..6bb542e658d --- /dev/null +++ b/app/views/groups/group_members/_group_member.html.haml @@ -0,0 +1,57 @@ +- user = member.user +- return unless user || member.invite? +- show_roles = local_assigns.fetch(:show_roles, true) + +%li{class: "#{dom_class(member)} js-toggle-container", id: dom_id(member)} + %span{class: ("list-item-name" if show_controls)} + - if member.user + = image_tag avatar_icon(user, 24), class: "avatar s24", alt: '' + %strong + = link_to user.name, user_path(user) + %span.cgray= user.username + - if user == current_user + %span.label.label-success It's you + - if user.blocked? + %label.label.label-danger + %strong Blocked + - else + = image_tag avatar_icon(member.invite_email, 24), class: "avatar s24", alt: '' + %strong + = member.invite_email + %span.cgray + invited + - if member.created_by + by + = link_to member.created_by.name, user_path(member.created_by) + = time_ago_with_tooltip(member.created_at) + + - if show_controls && can?(current_user, :admin_group_member, @group) + = link_to resend_invite_group_group_member_path(@group, member), method: :post, class: "btn-xs btn", title: 'Resend invite' do + Resend invite + + - if show_roles && should_user_see_group_roles?(current_user, @group) + %span.pull-right + %strong.member-access-level= member.human_access + - if show_controls + - if can?(current_user, :update_group_member, member) + = button_tag class: "btn-xs btn btn-grouped inline js-toggle-button", + title: 'Edit access level', type: 'button' do + = icon('pencil') + + - if can?(current_user, :destroy_group_member, member) + + - if current_user == user + = link_to leave_group_group_members_path(@group), data: { confirm: leave_group_message(@group.name)}, method: :delete, class: "btn-xs btn btn-remove", title: 'Remove user from group' do + = icon("sign-out") + Leave + - else + = link_to group_group_member_path(@group, member), data: { confirm: remove_user_from_group_message(@group, member) }, method: :delete, remote: true, class: "btn-xs btn btn-remove", title: 'Remove user from group' do + = icon('trash') + + .edit-member.hide.js-toggle-content + %br + = form_for [@group, member], remote: true do |f| + .prepend-top-10 + = f.select :access_level, options_for_select(GroupMember.access_level_roles, member.access_level), {}, class: 'form-control' + .prepend-top-10 + = f.submit 'Save', class: 'btn btn-save btn-sm' diff --git a/app/views/groups/group_members/index.html.haml b/app/views/groups/group_members/index.html.haml index a36531e095a..0eb6bbd4420 100644 --- a/app/views/groups/group_members/index.html.haml +++ b/app/views/groups/group_members/index.html.haml @@ -6,13 +6,12 @@ .panel-heading Add new user to group .panel-body - %p.light - Members of group have access to all group projects. + - if should_user_see_group_roles?(current_user, @group) + %p.light + Members of group have access to all group projects. .new-group-member-holder = render "new_group_member" - = render 'shared/members/requests', membership_source: @group, members: @members.request - .panel.panel-default .panel-heading %strong #{@group.name} @@ -26,8 +25,9 @@ = button_tag class: 'btn', title: 'Search' do = icon("search") %ul.content-list - = render partial: 'shared/members/member', collection: @members.non_request, as: :member - = paginate @members.non_request, theme: 'gitlab' + - @members.each do |member| + = render 'groups/group_members/group_member', member: member, show_controls: true + = paginate @members, theme: 'gitlab' :javascript $('form.member-search-form').on('submit', function(event) { diff --git a/app/views/groups/group_members/update.js.haml b/app/views/groups/group_members/update.js.haml index da71de4cd1e..df726e2b2b9 100644 --- a/app/views/groups/group_members/update.js.haml +++ b/app/views/groups/group_members/update.js.haml @@ -1,2 +1,2 @@ :plain - $("##{dom_id(@group_member)}").replaceWith('#{escape_javascript(render('shared/members/member', member: @group_member))}'); + $("##{dom_id(@group_member)}").replaceWith('#{escape_javascript(render(@group_member, member: @group_member, show_controls: true))}'); diff --git a/app/views/groups/issues.atom.builder b/app/views/groups/issues.atom.builder index b1628040325..c19671295af 100644 --- a/app/views/groups/issues.atom.builder +++ b/app/views/groups/issues.atom.builder @@ -4,7 +4,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear xml.link href: issues_group_url(format: :atom, private_token: current_user.try(:private_token)), rel: "self", type: "application/atom+xml" xml.link href: issues_group_url, rel: "alternate", type: "text/html" xml.id issues_group_url - xml.updated @issues.first.created_at.xmlschema if @issues.reorder(nil).any? + xml.updated @issues.first.created_at.xmlschema if @issues.any? - xml << render(partial: 'issues/issue', collection: @issues) if @issues.reorder(nil).any? + xml << render(partial: 'issues/issue', collection: @issues) if @issues.any? end diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml index 62ebd69485c..85635bc4616 100644 --- a/app/views/groups/show.html.haml +++ b/app/views/groups/show.html.haml @@ -19,9 +19,6 @@ .cover-desc.description = markdown(@group.description, pipeline: :description) - - if current_user - = render 'shared/members/access_request_buttons', source: @group - %div{ class: container_class } .top-area %ul.nav-links diff --git a/app/views/issues/_issue.atom.builder b/app/views/issues/_issue.atom.builder index 96831874144..68a2d19e58d 100644 --- a/app/views/issues/_issue.atom.builder +++ b/app/views/issues/_issue.atom.builder @@ -5,28 +5,10 @@ xml.entry do xml.updated issue.created_at.xmlschema xml.media :thumbnail, width: "40", height: "40", url: image_url(avatar_icon(issue.author_email)) - xml.author do + xml.author do |author| xml.name issue.author_name xml.email issue.author_email end xml.summary issue.title - xml.description issue.description if issue.description - xml.milestone issue.milestone.title if issue.milestone - xml.due_date issue.due_date if issue.due_date - - unless issue.labels.empty? - xml.labels do - issue.labels.each do |label| - xml.label label.name - end - end - end - - if issue.assignee - xml.assignee do - xml.name issue.assignee.name - xml.email issue.assignee.email - end - end end diff --git a/app/views/layouts/_collapse_button.html.haml b/app/views/layouts/_collapse_button.html.haml index 8c140a5943e..e4fab897377 100644 --- a/app/views/layouts/_collapse_button.html.haml +++ b/app/views/layouts/_collapse_button.html.haml @@ -1,3 +1 @@ -= link_to '#', class: 'nav-header-btn text-center toggle-nav-collapse', title: "Open/Close" do - %span.sr-only Toggle navigation - = icon('bars') += link_to icon('bars'), '#', class: 'toggle-nav-collapse', title: "Open/Close" diff --git a/app/views/layouts/_page.html.haml b/app/views/layouts/_page.html.haml index 199ab3c38c3..f89e8582792 100644 --- a/app/views/layouts/_page.html.haml +++ b/app/views/layouts/_page.html.haml @@ -1,6 +1,6 @@ -.page-with-sidebar{ class: "#{page_sidebar_class} #{page_gutter_class}" } +.page-with-sidebar.page-sidebar-collapsed{ class: "#{page_gutter_class}" } .sidebar-wrapper.nicescroll{ class: nav_sidebar_class } - = render partial: 'layouts/collapse_button' + - if defined?(sidebar) && sidebar = render "layouts/nav/#{sidebar}" - elsif current_user @@ -8,14 +8,13 @@ - else = render 'layouts/nav/explore' + .collapse-nav + = render partial: 'layouts/collapse_button' - if current_user = link_to current_user, class: 'sidebar-user', title: "Profile", data: {user: current_user.username} do = image_tag avatar_icon(current_user, 60), alt: 'Profile', class: 'avatar avatar s36' .username = current_user.username - = link_to '#', class: "nav-header-btn text-center pin-nav-btn #{'is-active' if pinned_nav?} js-nav-pin", title: 'Pin/Unpin navigation' do - %span.sr-only Toggle navigation pinning - = icon('thumb-tack') - if defined?(nav) && nav .layout-nav .container-fluid diff --git a/app/views/layouts/_search.html.haml b/app/views/layouts/_search.html.haml index 245b9c3b4d4..b49207fc315 100644 --- a/app/views/layouts/_search.html.haml +++ b/app/views/layouts/_search.html.haml @@ -36,31 +36,6 @@ - else = hidden_field_tag :search_code, true - :javascript - gl.projectOptions = gl.projectOptions || {}; - gl.projectOptions["#{j(@project.path)}"] = { - issuesPath: "#{namespace_project_issues_path(@project.namespace, @project)}", - mrPath: "#{namespace_project_merge_requests_path(@project.namespace, @project)}", - name: "#{j(@project.name)}" - }; - - - if @group and @group.path - :javascript - gl.groupOptions = gl.groupOptions || {}; - gl.groupOptions["#{j(@group.path)}"] = { - name: "#{j(@group.name)}", - issuesPath: "#{issues_group_path(j(@group.path))}", - mrPath: "#{merge_requests_group_path(j(@group.path))}" - }; - - - :javascript - gl.dashboardOptions = { - issuesPath: "#{issues_dashboard_url}", - mrPath: "#{merge_requests_dashboard_url}" - }; - - - if @snippet || @snippets = hidden_field_tag :snippets, true = hidden_field_tag :repository_ref, @ref diff --git a/app/views/layouts/admin.html.haml b/app/views/layouts/admin.html.haml index 87064cc9b3f..6591c52bdbd 100644 --- a/app/views/layouts/admin.html.haml +++ b/app/views/layouts/admin.html.haml @@ -1,5 +1,5 @@ - page_title "Admin Area" - header_title "Admin Area", admin_root_path -- nav "admin" +- sidebar "admin" = render template: "layouts/application" diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 33cedaaf2ee..2b86b289bbe 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -1,7 +1,7 @@ !!! 5 %html{ lang: "en"} = render "layouts/head" - %body{class: "#{user_application_theme}", data: {page: body_data_page, project: "#{@project.path if @project}", group: "#{@group.path if @group}"}} + %body{class: "#{user_application_theme}", 'data-page' => body_data_page} = Gon::Base.render_data -# Ideally this would be inside the head, but turbolinks only evaluates page-specific JS in the body. diff --git a/app/views/layouts/header/_default.html.haml b/app/views/layouts/header/_default.html.haml index 40a2c81eebd..ad30a367fc5 100644 --- a/app/views/layouts/header/_default.html.haml +++ b/app/views/layouts/header/_default.html.haml @@ -1,4 +1,4 @@ -%header.navbar.navbar-fixed-top.navbar-gitlab{ class: nav_header_class } +%header.navbar.navbar-fixed-top.navbar-gitlab.header-collapsed{ class: nav_header_class } %div{ class: fluid_layout ? "container-fluid" : "container-fluid" } .header-content %button.side-nav-toggle{type: 'button'} @@ -27,8 +27,9 @@ %li = link_to dashboard_todos_path, title: 'Todos', data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do = icon('bell fw') - %span.badge.todos-pending-count{ class: ("hidden" if todos_pending_count == 0) } - = todos_pending_count + - unless todos_pending_count == 0 + %span.badge.todos-pending-count + = todos_pending_count - if current_user.can_create_project? %li = link_to new_project_path, title: 'New project', data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do @@ -50,7 +51,7 @@ %h1.title= title .header-logo - = link_to root_path, class: 'home', title: 'Dashboard', id: 'logo' do + #logo = brand_header_logo = yield :header_content diff --git a/app/views/layouts/nav/_admin.html.haml b/app/views/layouts/nav/_admin.html.haml index 54aa34bee0b..f292730fe45 100644 --- a/app/views/layouts/nav/_admin.html.haml +++ b/app/views/layouts/nav/_admin.html.haml @@ -1,64 +1,107 @@ -%ul.nav-links.scrolling-tabs - .fade-left - = nav_link(controller: %w(dashboard admin projects users groups builds), html_options: {class: 'home'}) do - = link_to admin_root_path, title: 'Overview', class: 'shortcuts-tree' do +%ul.nav.nav-sidebar + = nav_link(controller: :dashboard, html_options: {class: 'home'}) do + = link_to admin_root_path, title: 'Overview' do + = icon('dashboard fw') %span Overview - = nav_link(controller: %w(background_jobs logs health_check)) do - = link_to admin_background_jobs_path, title: 'Monitoring' do + = nav_link(controller: [:admin, :projects]) do + = link_to admin_namespaces_projects_path, title: 'Projects' do + = icon('cube fw') %span - Monitoring + Projects + = nav_link(controller: :users) do + = link_to admin_users_path, title: 'Users' do + = icon('user fw') + %span + Users + = nav_link(controller: :groups) do + = link_to admin_groups_path, title: 'Groups' do + = icon('group fw') + %span + Groups = nav_link(controller: :deploy_keys) do = link_to admin_deploy_keys_path, title: 'Deploy Keys' do + = icon('key fw') %span Deploy Keys = nav_link path: ['runners#index', 'runners#show'] do = link_to admin_runners_path, title: 'Runners' do + = icon('cog fw') %span Runners + %span.count= number_with_delimiter(Ci::Runner.count(:all)) + = nav_link path: 'builds#index' do + = link_to admin_builds_path, title: 'Builds' do + = icon('link fw') + %span + Builds + %span.count= number_with_delimiter(Ci::Build.count(:all)) + = nav_link(controller: :logs) do + = link_to admin_logs_path, title: 'Logs' do + = icon('file-text fw') + %span + Logs + = nav_link(controller: :health_check) do + = link_to admin_health_check_path, title: 'Health Check' do + = icon('medkit fw') + %span + Health Check = nav_link(controller: :broadcast_messages) do = link_to admin_broadcast_messages_path, title: 'Messages' do + = icon('bullhorn fw') %span Messages = nav_link(controller: :hooks) do = link_to admin_hooks_path, title: 'Hooks' do + = icon('external-link fw') %span Hooks - + = nav_link(controller: :background_jobs) do + = link_to admin_background_jobs_path, title: 'Background Jobs' do + = icon('cog fw') + %span + Background Jobs = nav_link(controller: :appearances) do = link_to admin_appearances_path, title: 'Appearances' do + = icon('image') %span Appearance = nav_link(controller: :applications) do = link_to admin_applications_path, title: 'Applications' do + = icon('cloud fw') %span Applications = nav_link(controller: :services) do = link_to admin_application_settings_services_path, title: 'Service Templates' do + = icon('copy fw') %span Service Templates = nav_link(controller: :labels) do = link_to admin_labels_path, title: 'Labels' do + = icon('tags fw') %span Labels = nav_link(controller: :abuse_reports) do = link_to admin_abuse_reports_path, title: "Abuse Reports" do + = icon('exclamation-circle fw') %span Abuse Reports - %span.badge.count= number_with_delimiter(AbuseReport.count(:all)) + %span.count= number_with_delimiter(AbuseReport.count(:all)) - if askimet_enabled? = nav_link(controller: :spam_logs) do = link_to admin_spam_logs_path, title: "Spam Logs" do + = icon('exclamation-triangle fw') %span Spam Logs + %span.count= number_with_delimiter(SpamLog.count(:all)) = nav_link(controller: :application_settings, html_options: { class: 'separate-item'}) do = link_to admin_application_settings_path, title: 'Settings' do + = icon('cogs fw') %span Settings - .fade-right diff --git a/app/views/layouts/nav/_dashboard.html.haml b/app/views/layouts/nav/_dashboard.html.haml index 52e41b1a857..18cae5bf87f 100644 --- a/app/views/layouts/nav/_dashboard.html.haml +++ b/app/views/layouts/nav/_dashboard.html.haml @@ -1,64 +1,54 @@ %ul.nav.nav-sidebar = nav_link(path: ['root#index', 'projects#trending', 'projects#starred', 'dashboard/projects#index'], html_options: {class: "#{project_tab_class} home"}) do = link_to dashboard_projects_path, title: 'Projects', class: 'dashboard-shortcuts-projects' do - .icon-container - = navbar_icon('project') + = navbar_icon('project') %span Projects = nav_link(controller: :todos) do = link_to dashboard_todos_path, title: 'Todos' do - .icon-container - = icon('bell fw') + = icon('bell fw') %span Todos %span.count= number_with_delimiter(todos_pending_count) = nav_link(path: 'dashboard#activity') do = link_to activity_dashboard_path, class: 'dashboard-shortcuts-activity', title: 'Activity' do - .icon-container - = navbar_icon('activity') + = navbar_icon('activity') %span Activity = nav_link(controller: [:groups, 'groups/milestones', 'groups/group_members']) do = link_to dashboard_groups_path, title: 'Groups' do - .icon-container - = navbar_icon('group') + = navbar_icon('group') %span Groups = nav_link(controller: 'dashboard/milestones') do = link_to dashboard_milestones_path, title: 'Milestones' do - .icon-container - = navbar_icon('milestones') + = navbar_icon('milestones') %span Milestones = nav_link(path: 'dashboard#issues') do = link_to assigned_issues_dashboard_path, title: 'Issues', class: 'dashboard-shortcuts-issues' do - .icon-container - = navbar_icon('issues') + = navbar_icon('issues') %span Issues %span.count= number_with_delimiter(current_user.assigned_issues.opened.count) = nav_link(path: 'dashboard#merge_requests') do = link_to assigned_mrs_dashboard_path, title: 'Merge Requests', class: 'dashboard-shortcuts-merge_requests' do - .icon-container - = navbar_icon('mr') + = navbar_icon('mr') %span Merge Requests %span.count= number_with_delimiter(current_user.assigned_merge_requests.opened.count) = nav_link(controller: :snippets) do = link_to dashboard_snippets_path, title: 'Snippets' do - .icon-container - = icon('clipboard fw') + = icon('clipboard fw') %span Snippets = nav_link(controller: :help) do = link_to help_path, title: 'Help' do - .icon-container - = icon('question-circle fw') + = icon('question-circle fw') %span Help = nav_link(html_options: {class: profile_tab_class}) do = link_to profile_path, title: 'Profile Settings', data: {placement: 'bottom'} do - .icon-container - = icon('user fw') + = icon('user fw') %span Profile Settings diff --git a/app/views/layouts/nav/_group_settings.html.haml b/app/views/layouts/nav/_group_settings.html.haml index dac46648b9f..0b2673f1a82 100644 --- a/app/views/layouts/nav/_group_settings.html.haml +++ b/app/views/layouts/nav/_group_settings.html.haml @@ -14,3 +14,7 @@ %li = link_to edit_group_path(@group) do Edit Group + %li + = link_to leave_group_group_members_path(@group), + data: { confirm: leave_group_message(@group.name) }, method: :delete, title: 'Leave group' do + Leave Group diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml index a851cae4b56..53d1fcc30a6 100644 --- a/app/views/layouts/nav/_project.html.haml +++ b/app/views/layouts/nav/_project.html.haml @@ -1,26 +1,23 @@ - if current_user .controls + - access = user_max_access_in_project(current_user.id, @project) + - can_edit = can?(current_user, :admin_project, @project) .dropdown.project-settings-dropdown %a.dropdown-new.btn.btn-default#project-settings-button{href: '#', 'data-toggle' => 'dropdown'} = icon('cog') = icon('caret-down') %ul.dropdown-menu.dropdown-menu-align-right - - access = @project.team.max_member_access(current_user.id) - - can_edit = can?(current_user, :admin_project, @project) - - = render 'layouts/nav/project_settings', access: access, can_edit: can_edit - - - if can_edit || access - %li.divider - - if can_edit - %li - = link_to edit_project_path(@project) do - Edit Project - - if access - %li - = link_to polymorphic_path([:leave, @project, :members]), - data: { confirm: leave_confirmation_message(@project) }, method: :delete, title: 'Leave project' do - Leave Project + = render 'layouts/nav/project_settings' + %li.divider + - if can_edit + %li + = link_to edit_project_path(@project) do + Edit Project + - if access + %li + = link_to leave_namespace_project_project_members_path(@project.namespace, @project), + data: { confirm: leave_project_message(@project) }, method: :delete, title: 'Leave project' do + Leave Project %div{ class: nav_control_class } %ul.nav-links.scrolling-tabs @@ -42,7 +39,7 @@ Code - if project_nav_tab? :pipelines - = nav_link(controller: [:pipelines, :builds, :environments]) do + = nav_link(controller: :pipelines) do = link_to project_pipelines_path(@project), title: 'Pipelines', class: 'shortcuts-pipelines' do %span Pipelines diff --git a/app/views/layouts/nav/_project_settings.html.haml b/app/views/layouts/nav/_project_settings.html.haml index 13d32bd1354..885e78d38c6 100644 --- a/app/views/layouts/nav/_project_settings.html.haml +++ b/app/views/layouts/nav/_project_settings.html.haml @@ -3,43 +3,43 @@ = link_to namespace_project_project_members_path(@project.namespace, @project), title: 'Members', class: 'team-tab tab' do %span Members -- if access && can_edit - - if @project.allowed_to_share_with_group? - = nav_link(controller: :group_links) do - = link_to namespace_project_group_links_path(@project.namespace, @project), title: "Groups" do - %span - Groups - = nav_link(controller: :deploy_keys) do - = link_to namespace_project_deploy_keys_path(@project.namespace, @project), title: 'Deploy Keys' do + +- if @project.allowed_to_share_with_group? + = nav_link(controller: :group_links) do + = link_to namespace_project_group_links_path(@project.namespace, @project), title: "Groups" do + %span + Groups += nav_link(controller: :deploy_keys) do + = link_to namespace_project_deploy_keys_path(@project.namespace, @project), title: 'Deploy Keys' do + %span + Deploy Keys += nav_link(controller: :hooks) do + = link_to namespace_project_hooks_path(@project.namespace, @project), title: 'Webhooks' do + %span + Webhooks += nav_link(controller: :services) do + = link_to namespace_project_services_path(@project.namespace, @project), title: 'Services' do + %span + Services += nav_link(controller: :protected_branches) do + = link_to namespace_project_protected_branches_path(@project.namespace, @project), title: 'Protected Branches' do + %span + Protected Branches + +- if @project.builds_enabled? + = nav_link(controller: :runners) do + = link_to namespace_project_runners_path(@project.namespace, @project), title: 'Runners' do %span - Deploy Keys - = nav_link(controller: :hooks) do - = link_to namespace_project_hooks_path(@project.namespace, @project), title: 'Webhooks' do + Runners + = nav_link(controller: :variables) do + = link_to namespace_project_variables_path(@project.namespace, @project), title: 'Variables' do %span - Webhooks - = nav_link(controller: :services) do - = link_to namespace_project_services_path(@project.namespace, @project), title: 'Services' do + Variables + = nav_link(controller: :triggers) do + = link_to namespace_project_triggers_path(@project.namespace, @project), title: 'Triggers' do %span - Services - = nav_link(controller: :protected_branches) do - = link_to namespace_project_protected_branches_path(@project.namespace, @project), title: 'Protected Branches' do + Triggers + = nav_link(controller: :badges) do + = link_to namespace_project_badges_path(@project.namespace, @project), title: 'Badges' do %span - Protected Branches - - - if @project.builds_enabled? - = nav_link(controller: :runners) do - = link_to namespace_project_runners_path(@project.namespace, @project), title: 'Runners' do - %span - Runners - = nav_link(controller: :variables) do - = link_to namespace_project_variables_path(@project.namespace, @project), title: 'Variables' do - %span - Variables - = nav_link(controller: :triggers) do - = link_to namespace_project_triggers_path(@project.namespace, @project), title: 'Triggers' do - %span - Triggers - = nav_link(controller: :badges) do - = link_to namespace_project_badges_path(@project.namespace, @project), title: 'Badges' do - %span - Badges + Badges diff --git a/app/views/notify/group_access_granted_email.html.haml b/app/views/notify/group_access_granted_email.html.haml new file mode 100644 index 00000000000..f1916d624b6 --- /dev/null +++ b/app/views/notify/group_access_granted_email.html.haml @@ -0,0 +1,4 @@ +%p + = "You have been granted #{@group_member.human_access} access to group" + = link_to group_url(@group) do + = @group.name diff --git a/app/views/notify/group_access_granted_email.text.erb b/app/views/notify/group_access_granted_email.text.erb new file mode 100644 index 00000000000..ef9617bfc16 --- /dev/null +++ b/app/views/notify/group_access_granted_email.text.erb @@ -0,0 +1,4 @@ + +You have been granted <%= @group_member.human_access %> access to group <%= @group.name %> + +<%= url_for(group_url(@group)) %> diff --git a/app/views/notify/group_invite_accepted_email.html.haml b/app/views/notify/group_invite_accepted_email.html.haml new file mode 100644 index 00000000000..55efad384a7 --- /dev/null +++ b/app/views/notify/group_invite_accepted_email.html.haml @@ -0,0 +1,6 @@ +%p + #{@group_member.invite_email}, now known as + #{link_to @group_member.user.name, user_url(@group_member.user)}, + has accepted your invitation to join group + #{link_to @group.name, group_url(@group)}. + diff --git a/app/views/notify/group_invite_accepted_email.text.erb b/app/views/notify/group_invite_accepted_email.text.erb new file mode 100644 index 00000000000..f8b70f7a5a6 --- /dev/null +++ b/app/views/notify/group_invite_accepted_email.text.erb @@ -0,0 +1,3 @@ +<%= @group_member.invite_email %>, now known as <%= @group_member.user.name %>, has accepted your invitation to join group <%= @group.name %>. + +<%= group_url(@group) %> diff --git a/app/views/notify/group_invite_declined_email.html.haml b/app/views/notify/group_invite_declined_email.html.haml new file mode 100644 index 00000000000..f9525d84fac --- /dev/null +++ b/app/views/notify/group_invite_declined_email.html.haml @@ -0,0 +1,5 @@ +%p + #{@invite_email} + has declined your invitation to join group + #{link_to @group.name, group_url(@group)}. + diff --git a/app/views/notify/group_invite_declined_email.text.erb b/app/views/notify/group_invite_declined_email.text.erb new file mode 100644 index 00000000000..6c19a288d15 --- /dev/null +++ b/app/views/notify/group_invite_declined_email.text.erb @@ -0,0 +1,3 @@ +<%= @invite_email %> has declined your invitation to join group <%= @group.name %>. + +<%= group_url(@group) %> diff --git a/app/views/notify/group_member_invited_email.html.haml b/app/views/notify/group_member_invited_email.html.haml new file mode 100644 index 00000000000..163e88bfea3 --- /dev/null +++ b/app/views/notify/group_member_invited_email.html.haml @@ -0,0 +1,14 @@ +%p + You have been invited + - if inviter = @group_member.created_by + by + = link_to inviter.name, user_url(inviter) + to join group + = link_to @group.name, group_url(@group) + as #{@group_member.human_access}. + +%p + = link_to 'Accept invitation', invite_url(@token) + or + = link_to 'decline', decline_invite_url(@token) + diff --git a/app/views/notify/group_member_invited_email.text.erb b/app/views/notify/group_member_invited_email.text.erb new file mode 100644 index 00000000000..28ce4819b14 --- /dev/null +++ b/app/views/notify/group_member_invited_email.text.erb @@ -0,0 +1,4 @@ +You have been invited <%= "by #{@group_member.created_by.name} " if @group_member.created_by %>to join group <%= @group.name %> as <%= @group_member.human_access %>. + +Accept invitation: <%= invite_url(@token) %> +Decline invitation: <%= decline_invite_url(@token) %> diff --git a/app/views/notify/member_access_denied_email.html.haml b/app/views/notify/member_access_denied_email.html.haml deleted file mode 100644 index 71c9c50071a..00000000000 --- a/app/views/notify/member_access_denied_email.html.haml +++ /dev/null @@ -1,4 +0,0 @@ -%p - Your request to join the - #{link_to member_source.human_name, member_source.web_url} #{member_source.model_name.singular} - has been denied. diff --git a/app/views/notify/member_access_denied_email.text.erb b/app/views/notify/member_access_denied_email.text.erb deleted file mode 100644 index 87f2ef817ee..00000000000 --- a/app/views/notify/member_access_denied_email.text.erb +++ /dev/null @@ -1,3 +0,0 @@ -Your request to join the <%= member_source.human_name %> <%= member_source.model_name.singular %> has been denied. - -<%= member_source.web_url %> diff --git a/app/views/notify/member_access_granted_email.html.haml b/app/views/notify/member_access_granted_email.html.haml deleted file mode 100644 index 18dec806539..00000000000 --- a/app/views/notify/member_access_granted_email.html.haml +++ /dev/null @@ -1,3 +0,0 @@ -%p - You have been granted #{member.human_access} access to the - #{link_to member_source.human_name, member_source.web_url} #{member_source.model_name.singular}. diff --git a/app/views/notify/member_access_granted_email.text.erb b/app/views/notify/member_access_granted_email.text.erb deleted file mode 100644 index a9fb3a589a5..00000000000 --- a/app/views/notify/member_access_granted_email.text.erb +++ /dev/null @@ -1,3 +0,0 @@ -You have been granted <%= member.human_access %> access to the <%= member_source.human_name %> <%= member_source.model_name.singular %>. - -<%= member_source.web_url %> diff --git a/app/views/notify/member_access_requested_email.html.haml b/app/views/notify/member_access_requested_email.html.haml deleted file mode 100644 index 76f1f08a0cb..00000000000 --- a/app/views/notify/member_access_requested_email.html.haml +++ /dev/null @@ -1,3 +0,0 @@ -%p - #{link_to member.user.name, member.user} requested #{member.human_access} - access to the #{link_to member_source.human_name, polymorphic_url([member_source, :members])} #{member_source.model_name.singular}. diff --git a/app/views/notify/member_access_requested_email.text.erb b/app/views/notify/member_access_requested_email.text.erb deleted file mode 100644 index 9c5ee0eaf26..00000000000 --- a/app/views/notify/member_access_requested_email.text.erb +++ /dev/null @@ -1,3 +0,0 @@ -<%= member.user.name %> (<%= user_url(member.user) %>) requested <%= member.human_access %> access to the <%= member_source.human_name %> <%= member_source.model_name.singular %>. - -<%= polymorphic_url([member_source, :members]) %> diff --git a/app/views/notify/member_invite_accepted_email.html.haml b/app/views/notify/member_invite_accepted_email.html.haml deleted file mode 100644 index 2d1d40881eb..00000000000 --- a/app/views/notify/member_invite_accepted_email.html.haml +++ /dev/null @@ -1,5 +0,0 @@ -%p - #{member.invite_email}, now known as - #{link_to member.user.name, user_url(member.user)}, - has accepted your invitation to join the - #{link_to member_source.human_name, member_source.web_url} #{member_source.model_name.singular}. diff --git a/app/views/notify/member_invite_accepted_email.text.erb b/app/views/notify/member_invite_accepted_email.text.erb deleted file mode 100644 index cef87101427..00000000000 --- a/app/views/notify/member_invite_accepted_email.text.erb +++ /dev/null @@ -1,3 +0,0 @@ -<%= member.invite_email %>, now known as <%= member.user.name %>, has accepted your invitation to join the <%= member_source.human_name %> <%= member_source.model_name.singular %>. - -<%= member_source.web_url %> diff --git a/app/views/notify/member_invite_declined_email.html.haml b/app/views/notify/member_invite_declined_email.html.haml deleted file mode 100644 index aa1b373d1a6..00000000000 --- a/app/views/notify/member_invite_declined_email.html.haml +++ /dev/null @@ -1,4 +0,0 @@ -%p - #{@invite_email} - has declined your invitation to join the - #{link_to member_source.human_name, member_source.web_url} #{member_source.model_name.singular}. diff --git a/app/views/notify/member_invite_declined_email.text.erb b/app/views/notify/member_invite_declined_email.text.erb deleted file mode 100644 index 8bc305910c4..00000000000 --- a/app/views/notify/member_invite_declined_email.text.erb +++ /dev/null @@ -1,3 +0,0 @@ -<%= @invite_email %> has declined your invitation to join the <%= member_source.human_name %> <%= member_source.model_name.singular %>. - -<%= member_source.web_url %> diff --git a/app/views/notify/member_invited_email.html.haml b/app/views/notify/member_invited_email.html.haml deleted file mode 100644 index b8b75da3f2f..00000000000 --- a/app/views/notify/member_invited_email.html.haml +++ /dev/null @@ -1,13 +0,0 @@ -%p - You have been invited - - if member.created_by - by - = link_to member.created_by.name, user_url(member.created_by) - to join the - = link_to member_source.human_name, member_source.web_url - #{member_source.model_name.singular} as #{member.human_access}. - -%p - = link_to 'Accept invitation', invite_url(@token) - or - = link_to 'decline', decline_invite_url(@token) diff --git a/app/views/notify/member_invited_email.text.erb b/app/views/notify/member_invited_email.text.erb deleted file mode 100644 index 0a6393355be..00000000000 --- a/app/views/notify/member_invited_email.text.erb +++ /dev/null @@ -1,4 +0,0 @@ -You have been invited <%= "by #{member.created_by.name} " if member.created_by %>to join the <%= member_source.human_name %> <%= member_source.model_name.singular %> as <%= member.human_access %>. - -Accept invitation: <%= invite_url(@token) %> -Decline invitation: <%= decline_invite_url(@token) %> diff --git a/app/views/notify/project_access_granted_email.html.haml b/app/views/notify/project_access_granted_email.html.haml new file mode 100644 index 00000000000..dfc30a2d360 --- /dev/null +++ b/app/views/notify/project_access_granted_email.html.haml @@ -0,0 +1,5 @@ +%p + = "You have been granted #{@project_member.human_access} access to project" +%p + = link_to namespace_project_url(@project.namespace, @project) do + = @project.name_with_namespace diff --git a/app/views/notify/project_access_granted_email.text.erb b/app/views/notify/project_access_granted_email.text.erb new file mode 100644 index 00000000000..68eb1611ba7 --- /dev/null +++ b/app/views/notify/project_access_granted_email.text.erb @@ -0,0 +1,4 @@ + +You have been granted <%= @project_member.human_access %> access to project <%= @project.name_with_namespace %> + +<%= url_for(namespace_project_url(@project.namespace, @project)) %> diff --git a/app/views/notify/project_invite_accepted_email.html.haml b/app/views/notify/project_invite_accepted_email.html.haml new file mode 100644 index 00000000000..7e58d30b10a --- /dev/null +++ b/app/views/notify/project_invite_accepted_email.html.haml @@ -0,0 +1,6 @@ +%p + #{@project_member.invite_email}, now known as + #{link_to @project_member.user.name, user_url(@project_member.user)}, + has accepted your invitation to join project + #{link_to @project.name_with_namespace, namespace_project_url(@project.namespace, @project)}. + diff --git a/app/views/notify/project_invite_accepted_email.text.erb b/app/views/notify/project_invite_accepted_email.text.erb new file mode 100644 index 00000000000..fcbe752114d --- /dev/null +++ b/app/views/notify/project_invite_accepted_email.text.erb @@ -0,0 +1,3 @@ +<%= @project_member.invite_email %>, now known as <%= @project_member.user.name %>, has accepted your invitation to join project <%= @project.name_with_namespace %>. + +<%= namespace_project_url(@project.namespace, @project) %> diff --git a/app/views/notify/project_invite_declined_email.html.haml b/app/views/notify/project_invite_declined_email.html.haml new file mode 100644 index 00000000000..c2d7e6f6e3a --- /dev/null +++ b/app/views/notify/project_invite_declined_email.html.haml @@ -0,0 +1,5 @@ +%p + #{@invite_email} + has declined your invitation to join project + #{link_to @project.name_with_namespace, namespace_project_url(@project.namespace, @project)}. + diff --git a/app/views/notify/project_invite_declined_email.text.erb b/app/views/notify/project_invite_declined_email.text.erb new file mode 100644 index 00000000000..484687fa51c --- /dev/null +++ b/app/views/notify/project_invite_declined_email.text.erb @@ -0,0 +1,3 @@ +<%= @invite_email %> has declined your invitation to join project <%= @project.name_with_namespace %>. + +<%= namespace_project_url(@project.namespace, @project) %> diff --git a/app/views/notify/project_member_invited_email.html.haml b/app/views/notify/project_member_invited_email.html.haml new file mode 100644 index 00000000000..79eb89616de --- /dev/null +++ b/app/views/notify/project_member_invited_email.html.haml @@ -0,0 +1,13 @@ +%p + You have been invited + - if inviter = @project_member.created_by + by + = link_to inviter.name, user_url(inviter) + to join project + = link_to @project.name_with_namespace, namespace_project_url(@project.namespace, @project) + as #{@project_member.human_access}. + +%p + = link_to 'Accept invitation', invite_url(@token) + or + = link_to 'decline', decline_invite_url(@token) diff --git a/app/views/notify/project_member_invited_email.text.erb b/app/views/notify/project_member_invited_email.text.erb new file mode 100644 index 00000000000..e0706272115 --- /dev/null +++ b/app/views/notify/project_member_invited_email.text.erb @@ -0,0 +1,4 @@ +You have been invited <%= "by #{@project_member.created_by.name} " if @project_member.created_by %>to join project <%= @project.name_with_namespace %> as <%= @project_member.human_access %>. + +Accept invitation: <%= invite_url(@token) %> +Decline invitation: <%= decline_invite_url(@token) %> diff --git a/app/views/profiles/notifications/_group_settings.html.haml b/app/views/profiles/notifications/_group_settings.html.haml index f0cf82afe83..89ae7ffda2b 100644 --- a/app/views/profiles/notifications/_group_settings.html.haml +++ b/app/views/profiles/notifications/_group_settings.html.haml @@ -1,7 +1,7 @@ %li.notification-list-item %span.notification.fa.fa-holder.append-right-5 - if setting.global? - = notification_icon(current_user.global_notification_setting.level) + = notification_icon(current_user.notification_level) - else = notification_icon(setting.level) diff --git a/app/views/profiles/notifications/_project_settings.html.haml b/app/views/profiles/notifications/_project_settings.html.haml index e0fad555c09..17c097154da 100644 --- a/app/views/profiles/notifications/_project_settings.html.haml +++ b/app/views/profiles/notifications/_project_settings.html.haml @@ -1,7 +1,7 @@ %li.notification-list-item %span.notification.fa.fa-holder.append-right-5 - if setting.global? - = notification_icon(current_user.global_notification_setting.level) + = notification_icon(current_user.notification_level) - else = notification_icon(setting.level) diff --git a/app/views/profiles/notifications/show.html.haml b/app/views/profiles/notifications/show.html.haml index f2659ac14b5..7696f112bb3 100644 --- a/app/views/profiles/notifications/show.html.haml +++ b/app/views/profiles/notifications/show.html.haml @@ -26,7 +26,33 @@ = f.select :notification_email, @user.all_emails, { include_blank: false }, class: "select2" .form-group = f.label :notification_level, class: 'label-light' - = notification_level_radio_buttons + .radio + = f.label :notification_level, value: :disabled do + = f.radio_button :notification_level, :disabled + .level-title + Disabled + %p You will not get any notifications via email + + .radio + = f.label :notification_level, value: :mention do + = f.radio_button :notification_level, :mention + .level-title + On Mention + %p You will receive notifications only for comments in which you were @mentioned + + .radio + = f.label :notification_level, value: :participating do + = f.radio_button :notification_level, :participating + .level-title + Participating + %p You will only receive notifications from related resources (e.g. from your commits or assigned issues) + + .radio + = f.label :notification_level, value: :watch do + = f.radio_button :notification_level, :watch + .level-title + Watch + %p You will receive notifications for any activity .prepend-top-default = f.submit 'Update settings', class: "btn btn-create" diff --git a/app/views/profiles/two_factor_auths/show.html.haml b/app/views/profiles/two_factor_auths/show.html.haml index 593be2617c1..ce76cb73c9c 100644 --- a/app/views/profiles/two_factor_auths/show.html.haml +++ b/app/views/profiles/two_factor_auths/show.html.haml @@ -51,9 +51,9 @@ %p Use a hardware device to add the second factor of authentication. %p - As U2F devices are only supported by a few browsers, we require that you set up a - two-factor authentication app before a U2F device. That way you'll always be able to - log in - even when you're using an unsupported browser. + As U2F devices are only supported by a few browsers, it's recommended that you set up a + two-factor authentication app as well as a U2F device so you'll always be able to log in + using an unsupported browser. .col-lg-9 %p - if @registration_key_handles.present? diff --git a/app/views/projects/_home_panel.html.haml b/app/views/projects/_home_panel.html.haml index 2b19ee93eea..f5bc1b4e409 100644 --- a/app/views/projects/_home_panel.html.haml +++ b/app/views/projects/_home_panel.html.haml @@ -29,13 +29,10 @@ .project-clone-holder = render "shared/clone_panel" - .project-repo-buttons.project-right-buttons - - if current_user - = render 'shared/members/access_request_buttons', source: @project - .btn-group - = render "projects/buttons/download" - = render 'projects/buttons/dropdown' - = render 'projects/buttons/notifications' + .project-repo-buttons.btn-group.project-right-buttons + = render "projects/buttons/download" + = render 'projects/buttons/dropdown' + = render 'projects/buttons/notifications' :javascript new Star(); diff --git a/app/views/projects/builds/_sidebar.html.haml b/app/views/projects/builds/_sidebar.html.haml index cab21f0cf19..5d931389dfb 100644 --- a/app/views/projects/builds/_sidebar.html.haml +++ b/app/views/projects/builds/_sidebar.html.haml @@ -11,33 +11,19 @@ %p.build-detail-row #{@build.coverage}% - - if can?(current_user, :read_build, @project) && (@build.artifacts? || @build.artifacts_expired?) + - if can?(current_user, :read_build, @project) && @build.artifacts? .block{ class: ("block-first" if !@build.coverage) } .title Build artifacts - - if @build.artifacts_expired? - %p.build-detail-row - The artifacts were removed - #{time_ago_with_tooltip(@build.artifacts_expire_at)} - - elsif @build.artifacts_expire_at - %p.build-detail-row - The artifacts will be removed in - %span.js-artifacts-remove= @build.artifacts_expire_at + .btn-group.btn-group-justified{ role: :group } + = link_to download_namespace_project_build_artifacts_path(@project.namespace, @project, @build), class: 'btn btn-sm btn-default' do + Download - - if @build.artifacts? - .btn-group.btn-group-justified{ role: :group } - - if @build.artifacts_expire_at - = link_to keep_namespace_project_build_artifacts_path(@project.namespace, @project, @build), class: 'btn btn-sm btn-default', method: :post do - Keep + - if @build.artifacts_metadata? + = link_to browse_namespace_project_build_artifacts_path(@project.namespace, @project, @build), class: 'btn btn-sm btn-default' do + Browse - = link_to download_namespace_project_build_artifacts_path(@project.namespace, @project, @build), class: 'btn btn-sm btn-default' do - Download - - - if @build.artifacts_metadata? - = link_to browse_namespace_project_build_artifacts_path(@project.namespace, @project, @build), class: 'btn btn-sm btn-default' do - Browse - - .block{ class: ("block-first" if !@build.coverage && !(can?(current_user, :read_build, @project) && (@build.artifacts? || @build.artifacts_expired?))) } + .block{ class: ("block-first" if !@build.coverage && !(can?(current_user, :read_build, @project) && @build.artifacts?)) } .title Build details - if @build.retryable? diff --git a/app/views/projects/buttons/_notifications.html.haml b/app/views/projects/buttons/_notifications.html.haml index a7a97181096..3b97dc9328f 100644 --- a/app/views/projects/buttons/_notifications.html.haml +++ b/app/views/projects/buttons/_notifications.html.haml @@ -1,7 +1,7 @@ - if @notification_setting = form_for @notification_setting, url: namespace_project_notification_setting_path(@project.namespace.becomes(Namespace), @project), method: :patch, remote: true, html: { class: 'inline', id: 'notification-form' } do |f| = f.hidden_field :level - .dropdown.hidden-sm + .dropdown %button.btn.btn-default.notifications-btn#notifications-button{ data: { toggle: "dropdown" }, aria: { haspopup: "true", expanded: "false" } } = icon('bell') = notification_title(@notification_setting.level) diff --git a/app/views/projects/buttons/_star.html.haml b/app/views/projects/buttons/_star.html.haml index 71cf5582a4c..02dbb2985a4 100644 --- a/app/views/projects/buttons/_star.html.haml +++ b/app/views/projects/buttons/_star.html.haml @@ -1,5 +1,5 @@ - if current_user - = link_to toggle_star_namespace_project_path(@project.namespace, @project), { class: 'btn star-btn toggle-star has-tooltip', method: :post, remote: true, title: current_user.starred?(@project) ? 'Unstar project' : 'Star project' } do + = link_to toggle_star_namespace_project_path(@project.namespace, @project), class: 'btn star-btn toggle-star has-tooltip', method: :post, remote: true, title: "Star project" do - if current_user.starred?(@project) = icon('star fw') %span.starred Unstar diff --git a/app/views/projects/ci/pipelines/_pipeline.html.haml b/app/views/projects/ci/pipelines/_pipeline.html.haml index b8d8758fd2b..a0ffa065067 100644 --- a/app/views/projects/ci/pipelines/_pipeline.html.haml +++ b/app/views/projects/ci/pipelines/_pipeline.html.haml @@ -60,7 +60,7 @@ %li = link_to download_namespace_project_build_artifacts_path(@project.namespace, @project, build), rel: 'nofollow' do = icon("download") - %span Download '#{build.name}' artifacts + %span #{build.name} - if can?(current_user, :update_pipeline, @project) - if pipeline.retryable? diff --git a/app/views/projects/commit/_change.html.haml b/app/views/projects/commit/_change.html.haml index d9b800a4ded..44ef1fdbbe3 100644 --- a/app/views/projects/commit/_change.html.haml +++ b/app/views/projects/commit/_change.html.haml @@ -17,7 +17,7 @@ .form-group.branch = label_tag 'target_branch', target_label, class: 'control-label' .col-sm-10 - = select_tag "target_branch", project_branches, class: "select2 select2-sm js-target-branch" + = select_tag "target_branch", grouped_options_refs, class: "select2 select2-sm js-target-branch" - if can?(current_user, :push_code, @project) .js-create-merge-request-container .checkbox diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml index a959b34a539..367027182b6 100644 --- a/app/views/projects/commits/_commit.html.haml +++ b/app/views/projects/commits/_commit.html.haml @@ -9,30 +9,26 @@ = cache(cache_key) do %li.commit.js-toggle-container{ id: "commit-#{commit.short_id}" } - = commit_author_avatar(commit, size: 36) .commit-row-title %span.item-title = link_to_gfm commit.title, namespace_project_commit_path(project.namespace, project, commit.id), class: "commit-row-message" - %span.commit-row-message.visible-xs-inline - · - = commit.short_id - - if commit.status - = render_commit_status(commit, cssclass: 'visible-xs-inline') - if commit.description? - %a.text-expander.hidden-xs.js-toggle-button ... + %a.text-expander.js-toggle-button ... - .commit-actions.hidden-xs + .pull-right - if commit.status - = render_commit_status(commit, cssclass: 'btn btn-transparent') - = clipboard_button_with_class({ clipboard_text: commit.id }, css_class: 'btn-transparent') - = link_to commit.short_id, namespace_project_commit_path(project.namespace, project, commit), class: "commit-short-id btn btn-transparent" - = link_to_browse_code(project, commit) + = render_commit_status(commit) + = clipboard_button(clipboard_text: commit.id) + = link_to commit.short_id, namespace_project_commit_path(project.namespace, project, commit), class: "commit_short_id" - if commit.description? - %pre.commit-row-description.js-toggle-content - = preserve(markdown(escape_once(commit.description), pipeline: :single_line, author: commit.author)) + .commit-row-description.js-toggle-content + %pre + = preserve(markdown(escape_once(commit.description), pipeline: :single_line, author: commit.author)) .commit-row-info - = commit_author_link(commit, avatar: false, size: 24) - authored - #{time_ago_with_tooltip(commit.committed_date)} + by + = commit_author_link(commit, avatar: true, size: 24) + .committed_ago + #{time_ago_with_tooltip(commit.committed_date)} + = link_to_browse_code(project, commit) diff --git a/app/views/projects/commits/_commits.html.haml b/app/views/projects/commits/_commits.html.haml index dd12eae8f7e..7283a78a64e 100644 --- a/app/views/projects/commits/_commits.html.haml +++ b/app/views/projects/commits/_commits.html.haml @@ -4,11 +4,18 @@ - commits, hidden = limited_commits(@commits) - commits.chunk { |c| c.committed_date.in_time_zone.to_date }.each do |day, commits| - %li.commit-header= "#{day.strftime('%d %b, %Y')} #{pluralize(commits.count, 'commit')}" - %li.commits-row - %ul.list-unstyled.commit-list - = render commits, project: project + .row.commits-row + .col-md-2.hidden-xs.hidden-sm + %h5.commits-row-date + %i.fa.fa-calendar + %span= day.strftime('%d %b, %Y') + .light + = pluralize(commits.count, 'commit') + .col-md-10.col-sm-12 + %ul.content-list + = render commits, project: project + %hr.lists-separator - if hidden > 0 - %li.alert.alert-warning + .alert.alert-warning #{number_with_delimiter(hidden)} additional commits have been omitted to prevent performance issues. diff --git a/app/views/projects/commits/_head.html.haml b/app/views/projects/commits/_head.html.haml index c8aa849c217..a72e8ba73ad 100644 --- a/app/views/projects/commits/_head.html.haml +++ b/app/views/projects/commits/_head.html.haml @@ -1,6 +1,6 @@ .scrolling-tabs-container - .nav-links.sub-nav.scrolling-tabs - %ul{ class: (container_class) } + %ul.nav-links.sub-nav.scrolling-tabs + %div{ class: (container_class) } .fade-left = nav_link(controller: %w(tree blob blame edit_tree new_tree find_file)) do = link_to project_files_path(@project) do diff --git a/app/views/projects/commits/show.html.haml b/app/views/projects/commits/show.html.haml index 51ca4eb903e..76ba0bea36d 100644 --- a/app/views/projects/commits/show.html.haml +++ b/app/views/projects/commits/show.html.haml @@ -23,18 +23,21 @@ Create Merge Request .control - = form_tag(namespace_project_commits_path(@project.namespace, @project, @id), method: :get, class: 'commits-search-form') do - = search_field_tag :search, params[:search], { placeholder: 'Filter by commit message', id: 'commits-search', class: 'form-control search-text-input input-short', spellcheck: false } + = form_tag(namespace_project_commits_path(@project.namespace, @project, @id), method: :get, class: 'pull-left commits-search-form') do + = search_field_tag :search, params[:search], { placeholder: 'Filter by commit message', id: 'commits-search', class: 'form-control search-text-input', spellcheck: false } + - if current_user && current_user.private_token .control = link_to namespace_project_commits_path(@project.namespace, @project, @ref, {format: :atom, private_token: current_user.private_token}), title: "Commits Feed", class: 'btn' do = icon("rss") + + %ul.breadcrumb.repo-breadcrumb = commits_breadcrumbs %div{id: dom_id(@project)} - %ol#commits-list.list-unstyled.content_list - = render "commits", project: @project + #commits-list.content_list= render "commits", project: @project + .clear = spinner :javascript diff --git a/app/views/projects/container_registry/_tag.html.haml b/app/views/projects/container_registry/_tag.html.haml index f35faa6afb5..4e9f936539b 100644 --- a/app/views/projects/container_registry/_tag.html.haml +++ b/app/views/projects/container_registry/_tag.html.haml @@ -9,19 +9,11 @@ - else \- %td - - if tag.total_size - = number_to_human_size(tag.total_size) - · - = pluralize(tag.layers.size, "layer") - - else - .light - \- + = number_to_human_size(tag.total_size) + · + = pluralize(tag.layers.size, "layer") %td - - if tag.created_at - = time_ago_in_words(tag.created_at) - - else - .light - \- + = time_ago_in_words(tag.created_at) - if can?(current_user, :update_container_image, @project) %td.content .controls.hidden-xs.pull-right diff --git a/app/views/projects/deployments/_commit.html.haml b/app/views/projects/deployments/_commit.html.haml deleted file mode 100644 index 0f9d9512d88..00000000000 --- a/app/views/projects/deployments/_commit.html.haml +++ /dev/null @@ -1,12 +0,0 @@ -%div.branch-commit - - if deployment.ref - = link_to deployment.ref, namespace_project_commits_path(@project.namespace, @project, deployment.ref), class: "monospace" - · - = link_to deployment.short_sha, namespace_project_commit_path(@project.namespace, @project, deployment.sha), class: "commit-id monospace" - - %p.commit-title - %span - - if commit_title = deployment.commit_title - = link_to_gfm commit_title, namespace_project_commit_path(@project.namespace, @project, deployment.sha), class: "commit-row-message" - - else - Cant find HEAD commit for this branch diff --git a/app/views/projects/deployments/_deployment.html.haml b/app/views/projects/deployments/_deployment.html.haml deleted file mode 100644 index d08dd92f1f6..00000000000 --- a/app/views/projects/deployments/_deployment.html.haml +++ /dev/null @@ -1,23 +0,0 @@ -%tr.deployment - %td - %strong= "##{deployment.iid}" - - %td - = render 'projects/deployments/commit', deployment: deployment - - %td - - if deployment.deployable - = link_to namespace_project_build_path(@project.namespace, @project, deployment.deployable) do - = "#{deployment.deployable.name} (##{deployment.deployable.id})" - - %td - #{time_ago_with_tooltip(deployment.created_at)} - - %td - - if can?(current_user, :create_deployment, deployment) && deployment.deployable - .pull-right - = link_to retry_namespace_project_build_path(@project.namespace, @project, deployment.deployable), method: :post, class: 'btn btn-build' do - - if deployment.last? - Retry - - else - Rollback diff --git a/app/views/projects/diffs/_diffs.html.haml b/app/views/projects/diffs/_diffs.html.haml index f18bc8c41b3..d9c4b410d32 100644 --- a/app/views/projects/diffs/_diffs.html.haml +++ b/app/views/projects/diffs/_diffs.html.haml @@ -11,8 +11,6 @@ = commit_diff_whitespace_link(@project, @commit, class: 'hidden-xs') - elsif current_controller?(:merge_requests) = diff_merge_request_whitespace_link(@project, @merge_request, class: 'hidden-xs') - - elsif current_controller?(:compare) - = diff_compare_whitespace_link(@project, params[:from], params[:to], class: 'hidden-xs') .btn-group = inline_diff_btn = parallel_diff_btn @@ -26,7 +24,6 @@ - diff_commit = commit_for_diff(diff_file) - blob = project.repository.blob_for_diff(diff_commit, diff_file) - next unless blob - - blob.load_all_data!(project.repository) unless blob.only_display_raw? = render 'projects/diffs/file', i: index, project: project, diff_file: diff_file, diff_commit: diff_commit, blob: blob, diff_refs: diff_refs diff --git a/app/views/projects/diffs/_file.html.haml b/app/views/projects/diffs/_file.html.haml index 2395ea3c275..e5983c58039 100644 --- a/app/views/projects/diffs/_file.html.haml +++ b/app/views/projects/diffs/_file.html.haml @@ -49,8 +49,6 @@ = render "projects/diffs/parallel_view", diff_file: diff_file, project: project, blob: blob, index: i - else = render "projects/diffs/text_file", diff_file: diff_file, index: i - - elsif blob.only_display_raw? - .nothing-here-block This file is too large to display. - elsif blob.image? - old_file = project.repository.prev_blob_for_diff(diff_commit, diff_file) = render "projects/diffs/image", diff_file: diff_file, old_file: old_file, file: blob, index: i, diff_refs: diff_refs diff --git a/app/views/projects/environments/_environment.html.haml b/app/views/projects/environments/_environment.html.haml deleted file mode 100644 index eafa246d05f..00000000000 --- a/app/views/projects/environments/_environment.html.haml +++ /dev/null @@ -1,17 +0,0 @@ -- last_deployment = environment.last_deployment - -%tr.environment - %td - %strong - = link_to environment.name, namespace_project_environment_path(@project.namespace, @project, environment) - - %td - - if last_deployment - = render 'projects/deployments/commit', deployment: last_deployment - - else - %p.commit-title - No deployments yet - - %td - - if last_deployment - #{time_ago_with_tooltip(last_deployment.created_at)} diff --git a/app/views/projects/environments/_form.html.haml b/app/views/projects/environments/_form.html.haml deleted file mode 100644 index c07f4bd510c..00000000000 --- a/app/views/projects/environments/_form.html.haml +++ /dev/null @@ -1,7 +0,0 @@ -= form_for @environment, url: namespace_project_environments_path(@project.namespace, @project), html: { class: 'col-lg-9' } do |f| - = form_errors(@environment) - .form-group - = f.label :name, 'Name', class: 'label-light' - = f.text_field :name, required: true, class: 'form-control' - = f.submit 'Create environment', class: 'btn btn-create' - = link_to 'Cancel', namespace_project_environments_path(@project.namespace, @project), class: 'btn btn-cancel' diff --git a/app/views/projects/environments/_header_title.html.haml b/app/views/projects/environments/_header_title.html.haml deleted file mode 100644 index e056fccad5d..00000000000 --- a/app/views/projects/environments/_header_title.html.haml +++ /dev/null @@ -1 +0,0 @@ -- header_title project_title(@project, "Environments", project_environments_path(@project)) diff --git a/app/views/projects/environments/index.html.haml b/app/views/projects/environments/index.html.haml deleted file mode 100644 index ae9e77e7d89..00000000000 --- a/app/views/projects/environments/index.html.haml +++ /dev/null @@ -1,23 +0,0 @@ -- @no_container = true -- page_title "Environments" -= render "projects/pipelines/head" - -%div{ class: (container_class) } - - if can?(current_user, :create_environment, @project) - .top-area - .nav-controls - = link_to new_namespace_project_environment_path(@project.namespace, @project), class: 'btn btn-create' do - New environment - - - if @environments.blank? - %ul.content-list.environments - %li.nothing-here-block - No environments to show - - else - .table-holder - %table.table.environments - %tbody - %th Environment - %th Last deployment - %th Date - = render @environments diff --git a/app/views/projects/environments/new.html.haml b/app/views/projects/environments/new.html.haml deleted file mode 100644 index 54465828ba9..00000000000 --- a/app/views/projects/environments/new.html.haml +++ /dev/null @@ -1,9 +0,0 @@ -- page_title 'New Environment' - -.row.prepend-top-default.append-bottom-default - .col-lg-3 - %h4.prepend-top-0 - New Environment - %p Environments allow you to track deployments of your application - - = render 'form' diff --git a/app/views/projects/environments/show.html.haml b/app/views/projects/environments/show.html.haml deleted file mode 100644 index 069b77b5adf..00000000000 --- a/app/views/projects/environments/show.html.haml +++ /dev/null @@ -1,33 +0,0 @@ -- @no_container = true -- page_title "Environments" -= render "projects/pipelines/head" - -%div{ class: (container_class) } - .top-area - .col-md-9 - %h3.page-title= @environment.name.titleize - - .col-md-3 - .nav-controls - - if can?(current_user, :update_environment, @environment) - = link_to 'Destroy', namespace_project_environment_path(@project.namespace, @project, @environment), data: { confirm: 'Are you sure you want to delete this environment?' }, class: 'btn btn-danger', method: :delete - - - if @deployments.blank? - %ul.content-list.environments - %li.nothing-here-block - No deployments for - %strong= @environment.name - - else - .table-holder - %table.table.environments - %thead - %tr - %th ID - %th Commit - %th Build - %th Date - %th - - = render @deployments - - = paginate @deployments, theme: 'gitlab' diff --git a/app/views/projects/issues/_head.html.haml b/app/views/projects/issues/_head.html.haml index 403adb7426b..166dae248b6 100644 --- a/app/views/projects/issues/_head.html.haml +++ b/app/views/projects/issues/_head.html.haml @@ -1,5 +1,5 @@ -.nav-links.sub-nav - %ul{ class: (container_class) } +%ul.nav-links.sub-nav + %div{ class: (container_class) } - if project_nav_tab?(:issues) && !current_controller?(:merge_requests) = nav_link(controller: :issues) do = link_to url_for_project_issues(@project, only_path: true), title: 'Issues' do diff --git a/app/views/projects/issues/_merge_requests.html.haml b/app/views/projects/issues/_merge_requests.html.haml index d8075371853..75f36579b11 100644 --- a/app/views/projects/issues/_merge_requests.html.haml +++ b/app/views/projects/issues/_merge_requests.html.haml @@ -24,6 +24,8 @@ MERGED - elsif merge_request.closed? CLOSED + %li + = render partial: 'projects/issues/closed_by_box', locals: {merge_request_count: @merge_requests.count} - if @closed_by_merge_requests.present? %li = render partial: 'projects/issues/closed_by_box', locals: {merge_request_count: @merge_requests.count} diff --git a/app/views/projects/issues/_related_branches.html.haml b/app/views/projects/issues/_related_branches.html.haml index c6fc499a7b8..b9bb6fe559d 100644 --- a/app/views/projects/issues/_related_branches.html.haml +++ b/app/views/projects/issues/_related_branches.html.haml @@ -6,7 +6,7 @@ %li - sha = @project.repository.find_branch(branch).target - pipeline = @project.pipeline(sha, branch) if sha - - if pipeline + - if ci_copipelinemmit %span.related-branch-ci-status = render_pipeline_status(pipeline) %span.related-branch-info diff --git a/app/views/projects/issues/index.atom.builder b/app/views/projects/issues/index.atom.builder index 36957560de0..7ad7c9c87e8 100644 --- a/app/views/projects/issues/index.atom.builder +++ b/app/views/projects/issues/index.atom.builder @@ -4,7 +4,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear xml.link href: namespace_project_issues_url(@project.namespace, @project, format: :atom, private_token: current_user.try(:private_token)), rel: "self", type: "application/atom+xml" xml.link href: namespace_project_issues_url(@project.namespace, @project), rel: "alternate", type: "text/html" xml.id namespace_project_issues_url(@project.namespace, @project) - xml.updated @issues.first.created_at.xmlschema if @issues.reorder(nil).any? + xml.updated @issues.first.created_at.xmlschema if @issues.any? - xml << render(partial: 'issues/issue', collection: @issues) if @issues.reorder(nil).any? + xml << render(partial: 'issues/issue', collection: @issues) if @issues.any? end diff --git a/app/views/projects/labels/index.html.haml b/app/views/projects/labels/index.html.haml index aa4d69550ec..6e1baa46b05 100644 --- a/app/views/projects/labels/index.html.haml +++ b/app/views/projects/labels/index.html.haml @@ -4,10 +4,9 @@ = render "projects/issues/head" %div{ class: (container_class) } - .top-area.adjust + .top-area .nav-text - Labels can be applied to issues and merge requests. Star a label to make it a priority label. Order the prioritized labels to change their relative priority, by dragging. - + Labels can be applied to issues and merge requests. .nav-controls - if can?(current_user, :admin_label, @project) = link_to new_namespace_project_label_path(@project.namespace, @project), class: "btn btn-new" do @@ -20,9 +19,10 @@ .prioritized-labels{ class: ('hide' if hide) } %h5 Prioritized Labels %ul.content-list.manage-labels-list.js-prioritized-labels{ "data-url" => set_priorities_namespace_project_labels_path(@project.namespace, @project) } - %p.empty-message{ class: ('hidden' unless @prioritized_labels.empty?) } No prioritized labels yet - if @prioritized_labels.present? = render @prioritized_labels + - else + %p.empty-message No prioritized labels yet .other-labels - if can?(current_user, :admin_label, @project) %h5{ class: ('hide' if hide) } Other Labels diff --git a/app/views/projects/merge_requests/show/_commits.html.haml b/app/views/projects/merge_requests/show/_commits.html.haml index 0b05785430b..a8f09f855d4 100644 --- a/app/views/projects/merge_requests/show/_commits.html.haml +++ b/app/views/projects/merge_requests/show/_commits.html.haml @@ -2,5 +2,4 @@ = icon("sort-amount-desc") Most recent commits displayed first -%ol#commits-list.list-unstyled - = render "projects/commits/commits", project: @merge_request.project += render "projects/commits/commits", project: @merge_request.project diff --git a/app/views/projects/merge_requests/widget/_merged.html.haml b/app/views/projects/merge_requests/widget/_merged.html.haml index 19b5d0ff066..ec4beae9727 100644 --- a/app/views/projects/merge_requests/widget/_merged.html.haml +++ b/app/views/projects/merge_requests/widget/_merged.html.haml @@ -6,29 +6,46 @@ - if @merge_request.merge_event by #{link_to_member(@project, @merge_request.merge_event.author, avatar: true)} #{time_ago_with_tooltip(@merge_request.merge_event.created_at)} - - if !@merge_request.source_branch_exists? || (params[:delete_source] == 'true') - %p - The changes were merged into - #{link_to @merge_request.target_branch, namespace_project_commits_path(@project.namespace, @project, @merge_request.target_branch), class: "label-branch"}. - The source branch has been removed. - = render 'projects/merge_requests/widget/merged_buttons' - - elsif @merge_request.can_remove_source_branch?(current_user) - .remove_source_branch_widget + %div + - if !@merge_request.source_branch_exists? || (params[:delete_source] == 'true') %p The changes were merged into #{link_to @merge_request.target_branch, namespace_project_commits_path(@project.namespace, @project, @merge_request.target_branch), class: "label-branch"}. - You can remove the source branch now. - = render 'projects/merge_requests/widget/merged_buttons', source_branch_exists: true - .remove_source_branch_widget.failed.hide - %p - Failed to remove source branch '#{@merge_request.source_branch}'. + The source branch has been removed. + = render 'projects/merge_requests/widget/merged_buttons' + - elsif @merge_request.can_remove_source_branch?(current_user) + .remove_source_branch_widget + %p + The changes were merged into + #{link_to @merge_request.target_branch, namespace_project_commits_path(@project.namespace, @project, @merge_request.target_branch), class: "label-branch"}. + You can remove the source branch now. + = render 'projects/merge_requests/widget/merged_buttons', source_branch_exists: true + .remove_source_branch_widget.failed.hide + %p + Failed to remove source branch '#{@merge_request.source_branch}'. + + .remove_source_branch_in_progress.hide + %p + = icon('spinner spin') + Removing source branch '#{@merge_request.source_branch}'. Please wait, this page will be automatically reloaded. + + :javascript + $('.remove_source_branch').on('click', function() { + $('.remove_source_branch_widget').hide(); + $('.remove_source_branch_in_progress').show(); + }); - .remove_source_branch_in_progress.hide + $(".remove_source_branch").on("ajax:success", function (e, data, status, xhr) { + location.reload(); + }); + + $(".remove_source_branch").on("ajax:error", function (e, data, status, xhr) { + $('.remove_source_branch_widget').hide(); + $('.remove_source_branch_in_progress').hide(); + $('.remove_source_branch_widget.failed').show(); + }); + - else %p - = icon('spinner spin') - Removing source branch '#{@merge_request.source_branch}'. Please wait, this page will be automatically reloaded. - - else - %p - The changes were merged into - #{link_to @merge_request.target_branch, namespace_project_commits_path(@project.namespace, @project, @merge_request.target_branch), class: "label-branch"}. - = render 'projects/merge_requests/widget/merged_buttons' + The changes were merged into + #{link_to @merge_request.target_branch, namespace_project_commits_path(@project.namespace, @project, @merge_request.target_branch), class: "label-branch"}. + = render 'projects/merge_requests/widget/merged_buttons' diff --git a/app/views/projects/merge_requests/widget/_merged_buttons.haml b/app/views/projects/merge_requests/widget/_merged_buttons.haml index d836a253507..56167509af9 100644 --- a/app/views/projects/merge_requests/widget/_merged_buttons.haml +++ b/app/views/projects/merge_requests/widget/_merged_buttons.haml @@ -3,9 +3,9 @@ - mr_can_be_cherry_picked = @merge_request.can_be_cherry_picked? - if can_remove_source_branch || mr_can_be_reverted || mr_can_be_cherry_picked - .clearfix.merged-buttons + .btn-group - if can_remove_source_branch - = link_to namespace_project_branch_path(@merge_request.source_project.namespace, @merge_request.source_project, @merge_request.source_branch), remote: true, method: :delete, class: "btn btn-default btn-sm remove_source_branch" do + = link_to namespace_project_branch_path(@merge_request.source_project.namespace, @merge_request.source_project, @merge_request.source_branch), remote: true, method: :delete, class: "btn btn-default btn-grouped btn-sm remove_source_branch" do = icon('trash-o') Remove Source Branch - if mr_can_be_reverted diff --git a/app/views/projects/milestones/_form.html.haml b/app/views/projects/milestones/_form.html.haml index cbf1ba04170..f5e2b927da8 100644 --- a/app/views/projects/milestones/_form.html.haml +++ b/app/views/projects/milestones/_form.html.haml @@ -19,7 +19,6 @@ = f.label :due_date, "Due Date", class: "control-label" .col-sm-10 = f.text_field :due_date, class: "datepicker form-control", placeholder: "Select due date" - %a.inline.prepend-top-5.js-clear-due-date{ href: "#" } Clear due date .form-actions - if @milestone.new_record? @@ -28,3 +27,10 @@ -else = f.submit 'Save changes', class: "btn-save btn" = link_to "Cancel", namespace_project_milestone_path(@project.namespace, @project, @milestone), class: "btn btn-cancel" + + +:javascript + $(".datepicker").datepicker({ + dateFormat: "yy-mm-dd", + onSelect: function(dateText, inst) { $("#milestone_due_date").val(dateText) } + }).datepicker("setDate", $.datepicker.parseDate('yy-mm-dd', $('#milestone_due_date').val())); diff --git a/app/views/projects/network/show.html.haml b/app/views/projects/network/show.html.haml index e4ab064eda8..bf9baaea889 100644 --- a/app/views/projects/network/show.html.haml +++ b/app/views/projects/network/show.html.haml @@ -1,5 +1,4 @@ - page_title "Network", @ref -- page_specific_javascripts asset_path("network/application.js") = render "projects/commits/head" = render "head" %div{ class: (container_class) } @@ -15,5 +14,14 @@ = check_box_tag :filter_ref, 1, @options[:filter_ref] %span Begin with the selected commit - .network-graph{ data: { url: '#{escape_javascript(@url)}', commit_url: '#{escape_javascript(@commit_url)}', ref: '#{escape_javascript(@ref)}', commit_id: '#{escape_javascript(@commit.id)}' } } + .network-graph = spinner nil, true + +:javascript + network_graph = new Network({ + url: "#{escape_javascript(@url)}", + commit_url: "#{escape_javascript(@commit_url)}", + ref: "#{escape_javascript(@ref)}", + commit_id: '#{@commit.id}' + }) + new ShortcutsNetwork(network_graph.branch_graph) diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml index 7e8b8f83467..f9ac16b32f3 100644 --- a/app/views/projects/new.html.haml +++ b/app/views/projects/new.html.haml @@ -11,22 +11,26 @@ .project-edit-content = form_for @project, html: { class: 'new_project form-horizontal js-requires-input' } do |f| - .form-group + .form-group.project-name-holder = f.label :path, class: 'control-label' do - Project owner + Project path .col-sm-10 - = f.select :namespace_id, namespaces_options(:current_user), {}, {class: 'select2 js-select-namespace', tabindex: 1} - + .input-group + - if current_user.can_select_namespace? + .input-group-addon + = root_url + = f.select :namespace_id, namespaces_options(params[:namespace_id] || :current_user, display_path: true), {}, {class: 'select2 js-select-namespace', tabindex: 1} + .input-group-addon + \/ + - else + .input-group-addon + #{root_url}#{current_user.username}/ + = f.text_field :path, placeholder: "my-awesome-project", class: "form-control", tabindex: 2, autofocus: true, required: true + - if current_user.can_create_group? .help-block Want to house several dependent projects under the same namespace? = link_to "Create a group", new_group_path - - .form-group - = f.label :path, class: 'control-label' do - Project name - .col-sm-10 - = f.text_field :path, placeholder: "my-awesome-project", class: "form-control", tabindex: 2, autofocus: true, required: true - if import_sources_enabled? .project-import.js-toggle-container diff --git a/app/views/projects/pipelines/_head.html.haml b/app/views/projects/pipelines/_head.html.haml index d65faf86d4e..f278d4e0538 100644 --- a/app/views/projects/pipelines/_head.html.haml +++ b/app/views/projects/pipelines/_head.html.haml @@ -1,19 +1,15 @@ -.nav-links.sub-nav - %ul{ class: (container_class) } +%ul.nav-links.sub-nav + %div{ class: (container_class) } - if project_nav_tab? :pipelines = nav_link(controller: :pipelines) do = link_to project_pipelines_path(@project), title: 'Pipelines', class: 'shortcuts-pipelines' do %span Pipelines + %span.badge.count.ci_counter= number_with_delimiter(@project.pipelines.running_or_pending.count) - if project_nav_tab? :builds = nav_link(controller: %w(builds)) do = link_to project_builds_path(@project), title: 'Builds', class: 'shortcuts-builds' do %span Builds - - - if project_nav_tab? :environments - = nav_link(controller: %w(environments)) do - = link_to project_environments_path(@project), title: 'Environments', class: 'shortcuts-environments' do - %span - Environments + %span.badge.count.builds_counter= number_with_delimiter(@project.running_or_pending_build_count) diff --git a/app/views/projects/project_members/_group_members.html.haml b/app/views/projects/project_members/_group_members.html.haml index cb6136c215a..6671ee2c6d6 100644 --- a/app/views/projects/project_members/_group_members.html.haml +++ b/app/views/projects/project_members/_group_members.html.haml @@ -6,14 +6,11 @@ (#{members.count}) - if can?(current_user, :admin_group_member, @group) .controls - = link_to 'Manage group members', - group_group_members_path(@group), - class: 'btn' + = link_to group_group_members_path(@group), class: 'btn' do + Manage group members %ul.content-list - = render partial: 'shared/members/member', - collection: members.limit(20), - as: :member, - locals: { show_controls: false } - - if members.size > 20 + - members.limit(20).each do |member| + = render 'groups/group_members/group_member', member: member, show_controls: false + - if members.count > 20 %li and #{members.count - 20} more. For full list visit #{link_to 'group members page', group_group_members_path(@group)} diff --git a/app/views/projects/project_members/_new_project_member.html.haml b/app/views/projects/project_members/_new_project_member.html.haml index 82892a33358..f0f3bb3c177 100644 --- a/app/views/projects/project_members/_new_project_member.html.haml +++ b/app/views/projects/project_members/_new_project_member.html.haml @@ -9,7 +9,7 @@ .form-group = f.label :access_level, "Project Access", class: 'control-label' .col-sm-10 - = select_tag :access_level, options_for_select(ProjectMember.access_level_roles, @project_member.access_level), class: "project-access-select select2" + = select_tag :access_level, options_for_select(ProjectMember.access_roles, @project_member.access_level), class: "project-access-select select2" .help-block Read more about role permissions %strong= link_to "here", help_page_path("permissions", "permissions"), class: "vlink" diff --git a/app/views/projects/project_members/_project_member.html.haml b/app/views/projects/project_members/_project_member.html.haml new file mode 100644 index 00000000000..268f140d7db --- /dev/null +++ b/app/views/projects/project_members/_project_member.html.haml @@ -0,0 +1,55 @@ +- user = member.user +- return unless user || member.invite? + +%li{class: "#{dom_class(member)} js-toggle-container project_member_row access-#{member.human_access.downcase}", id: dom_id(member)} + %span.list-item-name + - if member.user + = image_tag avatar_icon(user, 24), class: "avatar s24", alt: '' + %strong + = link_to user.name, user_path(user) + %span.cgray= user.username + - if user == current_user + %span.label.label-success It's you + - if user.blocked? + %label.label.label-danger + %strong Blocked + - else + = image_tag avatar_icon(member.invite_email, 24), class: "avatar s24", alt: '' + %strong + = member.invite_email + %span.cgray + invited + - if member.created_by + by + = link_to member.created_by.name, user_path(member.created_by) + = time_ago_with_tooltip(member.created_at) + + - if can?(current_user, :admin_project_member, @project) + = link_to resend_invite_namespace_project_project_member_path(@project.namespace, @project, member), method: :post, class: "btn-xs btn", title: 'Resend invite' do + Resend invite + + - if can?(current_user, :admin_project_member, @project) + .pull-right + %strong= member.human_access + - if can?(current_user, :update_project_member, member) + = button_tag class: "btn-xs btn-grouped inline btn js-toggle-button", + title: 'Edit access level', type: 'button' do + = icon('pencil') + + - if can?(current_user, :destroy_project_member, member) + + - if current_user == user + = link_to leave_namespace_project_project_members_path(@project.namespace, @project), data: { confirm: leave_project_message(@project) }, method: :delete, class: "btn-xs btn btn-remove", title: 'Leave project' do + = icon("sign-out") + Leave + - else + = link_to namespace_project_project_member_path(@project.namespace, @project, member), data: { confirm: remove_from_project_team_message(@project, member) }, method: :delete, remote: true, class: "btn-xs btn btn-remove", title: 'Remove user from team' do + = icon('trash') + + .edit-member.hide.js-toggle-content + %br + = form_for member, as: :project_member, url: namespace_project_project_member_path(@project.namespace, @project, member), remote: true do |f| + .prepend-top-10 + = f.select :access_level, options_for_select(ProjectMember.access_roles, member.access_level), {}, class: 'form-control' + .prepend-top-10 + = f.submit 'Save', class: 'btn btn-save' diff --git a/app/views/projects/project_members/_shared_group_members.html.haml b/app/views/projects/project_members/_shared_group_members.html.haml index 952844acefc..ae13f8428f0 100644 --- a/app/views/projects/project_members/_shared_group_members.html.haml +++ b/app/views/projects/project_members/_shared_group_members.html.haml @@ -14,10 +14,8 @@ %i.fa.fa-pencil-square-o Edit group members %ul.content-list - = render partial: 'shared/members/member', - collection: shared_group.group_members.order(access_level: :desc).limit(20), - as: :member, - locals: { show_controls: false, show_roles: false } + - shared_group.group_members.order('access_level DESC').limit(20).each do |member| + = render 'groups/group_members/group_member', member: member, show_controls: false, show_roles: false - if shared_group_users_count > 20 %li and #{shared_group_users_count - 20} more. For full list visit #{link_to 'group members page', group_group_members_path(shared_group)} diff --git a/app/views/projects/project_members/_team.html.haml b/app/views/projects/project_members/_team.html.haml index 03207614258..e8dce30425f 100644 --- a/app/views/projects/project_members/_team.html.haml +++ b/app/views/projects/project_members/_team.html.haml @@ -11,7 +11,8 @@ = button_tag class: 'btn', title: 'Search' do = icon("search") %ul.content-list - = render partial: 'shared/members/member', collection: members, as: :member + - members.each do |project_member| + = render 'project_member', member: project_member :javascript $('form.member-search-form').on('submit', function (event) { diff --git a/app/views/projects/project_members/index.html.haml b/app/views/projects/project_members/index.html.haml index 357ccccaf1d..15dc064e7ea 100644 --- a/app/views/projects/project_members/index.html.haml +++ b/app/views/projects/project_members/index.html.haml @@ -13,9 +13,7 @@ Users with access to this project are listed below. = render "new_project_member" - = render 'shared/members/requests', membership_source: @project, members: @project_members.request - - = render 'team', members: @project_members.non_request + = render "team", members: @project_members - if @group = render "group_members", members: @group_members diff --git a/app/views/projects/project_members/update.js.haml b/app/views/projects/project_members/update.js.haml index 45f8ef89060..2fb3a41d541 100644 --- a/app/views/projects/project_members/update.js.haml +++ b/app/views/projects/project_members/update.js.haml @@ -1,2 +1,2 @@ :plain - $("##{dom_id(@project_member)}").replaceWith('#{escape_javascript(render('shared/members/member', member: @project_member))}'); + $("##{dom_id(@project_member)}").replaceWith('#{escape_javascript(render("project_member", member: @project_member))}'); diff --git a/app/views/shared/_label_row.html.haml b/app/views/shared/_label_row.html.haml index 77676454b57..478c04318c6 100644 --- a/app/views/shared/_label_row.html.haml +++ b/app/views/shared/_label_row.html.haml @@ -1,7 +1,5 @@ %span.label-row - if can?(current_user, :admin_label, @project) - .draggable-handler - = icon('bars') .js-toggle-priority.toggle-priority{ data: { url: remove_priority_namespace_project_label_path(@project.namespace, @project, label), dom_id: dom_id(label) } } %button.add-priority.btn.has-tooltip{ title: 'Prioritize', :'data-placement' => 'top' } diff --git a/app/views/shared/_merge_requests.html.haml b/app/views/shared/_merge_requests.html.haml index ca3178395c1..e74fc36c797 100644 --- a/app/views/shared/_merge_requests.html.haml +++ b/app/views/shared/_merge_requests.html.haml @@ -1,4 +1,4 @@ -- if @merge_requests.reorder(nil).any? +- if @merge_requests.any? - @merge_requests.group_by(&:target_project).each do |group| .panel.panel-default.panel-small - project = group[0] diff --git a/app/views/shared/groups/_group.html.haml b/app/views/shared/groups/_group.html.haml index 1ad95351005..a25365a94f2 100644 --- a/app/views/shared/groups/_group.html.haml +++ b/app/views/shared/groups/_group.html.haml @@ -9,7 +9,7 @@ = link_to edit_group_path(group), class: "btn" do = icon('cogs') - = link_to leave_group_group_members_path(group), data: { confirm: leave_confirmation_message(group) }, method: :delete, class: "btn", 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 c30bdb0ae91..17e2a7e9290 100644 --- a/app/views/shared/issuable/_form.html.haml +++ b/app/views/shared/issuable/_form.html.haml @@ -35,13 +35,13 @@ .clearfix .error-alert -- if issuable.is_a?(Issue) +- if issuable.is_a?(Issue) && !issuable.project.private? .form-group .col-sm-offset-2.col-sm-10 .checkbox = f.label :confidential do = f.check_box :confidential - This issue is confidential and should only be visible to team members with at least Reporter access. + This issue is confidential and should only be visible to team members - if can?(current_user, :"admin_#{issuable.to_ability_name}", issuable.project) - has_due_date = issuable.has_attribute?(:due_date) diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml index 210c9b9aab5..fb906de829a 100644 --- a/app/views/shared/issuable/_sidebar.html.haml +++ b/app/views/shared/issuable/_sidebar.html.haml @@ -1,21 +1,9 @@ -- todo = has_todo(issuable) %aside.right-sidebar{ class: sidebar_gutter_collapsed_class } .issuable-sidebar - can_edit_issuable = can?(current_user, :"admin_#{issuable.to_ability_name}", @project) .block.issuable-sidebar-header - - if current_user - %span.issuable-header-text.hide-collapsed.pull-left - Todo - %a.gutter-toggle.pull-right.js-sidebar-toggle{ role: "button", href: "#", aria: { label: "Toggle sidebar" } } + %a.gutter-toggle.pull-right.js-sidebar-toggle{href: '#'} = sidebar_gutter_toggle_icon - - if current_user - %button.btn.btn-default.issuable-header-btn.pull-right.js-issuable-todo{ type: "button", aria: { label: (todo.nil? ? "Add Todo" : "Mark Done") }, data: { todo_text: "Add Todo", mark_text: "Mark Done", id: (todo.id unless todo.nil?), issuable: issuable.id, issuable_type: issuable.class.name.underscore, url: namespace_project_todos_path(@project.namespace, @project) } } - %span.js-issuable-todo-text - - if todo.nil? - Add Todo - - else - Mark Done - = icon('spin spinner', class: 'hidden js-issuable-todo-loading') = form_for [@project.namespace.becomes(Namespace), @project, issuable], remote: true, format: :json, html: {class: 'issuable-context-form inline-update js-issuable-update'} do |f| .block.assignee @@ -29,21 +17,20 @@ = icon('spinner spin', class: 'block-loading') - if can_edit_issuable = link_to 'Edit', '#', class: 'edit-link pull-right' - .value.hide-collapsed + .value.bold.hide-collapsed - if issuable.assignee - = link_to_member(@project, issuable.assignee, size: 32, extra_class: 'bold') do + = link_to_member(@project, issuable.assignee, size: 32) do - if issuable.instance_of?(MergeRequest) && !issuable.can_be_merged_by?(issuable.assignee) %span.pull-right.cannot-be-merged{ data: { toggle: 'tooltip', placement: 'left' }, title: 'Not allowed to merge' } = icon('exclamation-triangle') %span.username = issuable.assignee.to_reference - else - %span.assign-yourself.no-value + %span.assign-yourself No assignee - if can_edit_issuable - \- %a.js-assign-yourself{ href: '#' } - assign yourself + \- assign yourself .selectbox.hide-collapsed = f.hidden_field 'assignee_id', value: issuable.assignee_id, id: 'issue_assignee_id' @@ -63,11 +50,13 @@ = icon('spinner spin', class: 'block-loading') - if can_edit_issuable = link_to 'Edit', '#', class: 'edit-link pull-right' - .value.hide-collapsed + .value.bold.hide-collapsed - if issuable.milestone - = link_to issuable.milestone.title, namespace_project_milestone_path(@project.namespace, @project, issuable.milestone), class: "bold has-tooltip", title: milestone_remaining_days(issuable.milestone), data: { container: "body", html: 1 } + = link_to namespace_project_milestone_path(@project.namespace, @project, issuable.milestone) do + %span.has-tooltip{title: milestone_remaining_days(issuable.milestone), data: {container: 'body', html: 1}} + = issuable.milestone.title - else - %span.no-value None + .light None .selectbox.hide-collapsed = f.hidden_field 'milestone_id', value: issuable.milestone_id, id: nil @@ -84,14 +73,14 @@ = icon('spinner spin', class: 'block-loading') - if can?(current_user, :"admin_#{issuable.to_ability_name}", @project) = link_to 'Edit', '#', class: 'edit-link pull-right' - .value.hide-collapsed + .value.bold.hide-collapsed %span.value-content - if issuable.due_date - %span.bold= issuable.due_date.to_s(:medium) + = issuable.due_date.to_s(:medium) - else - %span.no-value No due date + None - if can?(current_user, :"admin_#{issuable.to_ability_name}", @project) - %span.no-value.js-remove-due-date-holder{ class: ("hidden" if issuable.due_date.nil?) } + %span.light.js-remove-due-date-holder{ class: ("hidden" if issuable.due_date.nil?) } \- %a.js-remove-due-date{ href: "#", role: "button" } remove due date @@ -123,7 +112,7 @@ - issuable.labels_array.each do |label| = link_to_label(label, type: issuable.to_ability_name) - else - %span.no-value None + .light None .selectbox.hide-collapsed - issuable.labels_array.each do |label| = hidden_field_tag "#{issuable.to_ability_name}[label_names][]", label.id, id: nil diff --git a/app/views/shared/members/_access_request_buttons.html.haml b/app/views/shared/members/_access_request_buttons.html.haml deleted file mode 100644 index ed0a6ebcf84..00000000000 --- a/app/views/shared/members/_access_request_buttons.html.haml +++ /dev/null @@ -1,12 +0,0 @@ -- member = source.members.find_by(user_id: current_user.id) - -- if member - - if member.request? - = link_to 'Withdraw Access Request', polymorphic_path([:leave, source, :members]), - method: :delete, - data: { confirm: remove_member_message(member) }, - class: 'btn access-request-button hidden-xs' -- else - = link_to 'Request Access', polymorphic_path([:request_access, source, :members]), - method: :post, - class: 'btn access-request-button hidden-xs' diff --git a/app/views/shared/members/_member.html.haml b/app/views/shared/members/_member.html.haml deleted file mode 100644 index 0191814849a..00000000000 --- a/app/views/shared/members/_member.html.haml +++ /dev/null @@ -1,78 +0,0 @@ -- default_show_roles = can?(current_user, action_member_permission(:update, member), member) || can?(current_user, action_member_permission(:destroy, member), member) -- show_roles = local_assigns.fetch(:show_roles, default_show_roles) -- show_controls = local_assigns.fetch(:show_controls, true) -- user = member.user - -%li.js-toggle-container{ class: dom_class(member), id: dom_id(member) } - %span{ class: ("list-item-name" if show_controls) } - - if user - = image_tag avatar_icon(user, 24), class: "avatar s24", alt: '' - %strong - = link_to user.name, user_path(user) - %span.cgray= user.username - - - if user == current_user - %span.label.label-success It's you - - - if user.blocked? - %label.label.label-danger - %strong Blocked - - - if member.request? - %span.cgray - – Requested - = time_ago_with_tooltip(member.requested_at) - - else - = image_tag avatar_icon(member.invite_email, 24), class: "avatar s24", alt: '' - %strong= member.invite_email - %span.cgray - – Invited - - if member.created_by - by - = link_to member.created_by.name, user_path(member.created_by) - = time_ago_with_tooltip(member.created_at) - - - if show_controls && can?(current_user, action_member_permission(:admin, member), member.source) - = link_to 'Resend invite', polymorphic_path([:resend_invite, member]), - method: :post, - class: 'btn-xs btn' - - - if show_roles - %span.pull-right - %strong= member.human_access - - if show_controls - - if can?(current_user, action_member_permission(:update, member), member) - = button_tag icon('pencil'), - type: 'button', - class: 'btn-xs btn btn-grouped inline js-toggle-button', - title: 'Edit access level' - - - if member.request? - - = link_to icon('check inverse'), polymorphic_path([:approve_access_request, member]), - method: :post, - class: 'btn-xs btn btn-success', - title: 'Grant access' - - - if can?(current_user, action_member_permission(:destroy, member), member) - - - if current_user == user - = link_to icon('sign-out', text: 'Leave'), polymorphic_path([:leave, member.source, :members]), - method: :delete, - data: { confirm: leave_confirmation_message(member.source) }, - class: 'btn-xs btn btn-remove' - - else - = link_to icon('trash'), member, - remote: true, - method: :delete, - data: { confirm: remove_member_message(member) }, - class: 'btn-xs btn btn-remove', - title: remove_member_title(member) - - .edit-member.hide.js-toggle-content - %br - = form_for member, remote: true do |f| - .prepend-top-10 - = f.select :access_level, options_for_select(member.class.access_level_roles, member.access_level), {}, class: 'form-control' - .prepend-top-10 - = f.submit 'Save', class: 'btn btn-save btn-sm' diff --git a/app/views/shared/members/_requests.html.haml b/app/views/shared/members/_requests.html.haml deleted file mode 100644 index b5963876034..00000000000 --- a/app/views/shared/members/_requests.html.haml +++ /dev/null @@ -1,8 +0,0 @@ -- if members.any? - .panel.panel-default - .panel-heading - %strong= membership_source.name - access requests - %small= "(#{members.size})" - %ul.content-list - = render partial: 'shared/members/member', collection: members, as: :member diff --git a/app/views/shared/milestones/_merge_requests_tab.haml b/app/views/shared/milestones/_merge_requests_tab.haml index 9c193f901e2..c29d8ee6737 100644 --- a/app/views/shared/milestones/_merge_requests_tab.haml +++ b/app/views/shared/milestones/_merge_requests_tab.haml @@ -3,10 +3,10 @@ .row.prepend-top-default .col-md-3 - = render 'shared/milestones/issuables', args.merge(title: 'Work in progress (open and unassigned)', issuables: merge_requests.opened.unassigned, id: 'unassigned', show_counter: true) + = render 'shared/milestones/issuables', args.merge(title: 'Work in progress (open and unassigned)', issuables: merge_requests.opened.unassigned, id: 'unassigned') .col-md-3 - = render 'shared/milestones/issuables', args.merge(title: 'Waiting for merge (open and assigned)', issuables: merge_requests.opened.assigned, id: 'ongoing', show_counter: true) + = render 'shared/milestones/issuables', args.merge(title: 'Waiting for merge (open and assigned)', issuables: merge_requests.opened.assigned, id: 'ongoing') .col-md-3 - = render 'shared/milestones/issuables', args.merge(title: 'Rejected (closed)', issuables: merge_requests.closed, id: 'closed', show_counter: true) + = render 'shared/milestones/issuables', args.merge(title: 'Rejected (closed)', issuables: merge_requests.closed, id: 'closed') .col-md-3 - = render 'shared/milestones/issuables', args.merge(title: 'Merged', issuables: merge_requests.merged, id: 'merged', primary: true, show_counter: true) + = render 'shared/milestones/issuables', args.merge(title: 'Merged', issuables: merge_requests.merged, id: 'merged', primary: true) diff --git a/app/views/u2f/_register.html.haml b/app/views/u2f/_register.html.haml index cbb8dfb7829..46af591fc43 100644 --- a/app/views/u2f/_register.html.haml +++ b/app/views/u2f/_register.html.haml @@ -4,18 +4,11 @@ %p Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer). %script#js-register-u2f-setup{ type: "text/template" } - - if current_user.two_factor_otp_enabled? - .row.append-bottom-10 - .col-md-3 - %button#js-setup-u2f-device.btn.btn-info Setup New U2F Device - .col-md-9 - %p Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left. - - else - .row.append-bottom-10 - .col-md-3 - %button#js-setup-u2f-device.btn.btn-info{ disabled: true } Setup New U2F Device - .col-md-9 - %p.text-warning You need to register a two-factor authentication app before you can set up a U2F device. + .row.append-bottom-10 + .col-md-3 + %a#js-setup-u2f-device.btn.btn-info{ href: 'javascript:void(0)' } Setup New U2F Device + .col-md-9 + %p Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left. %script#js-register-u2f-in-progress{ type: "text/template" } %p Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now. diff --git a/app/workers/expire_build_artifacts_worker.rb b/app/workers/expire_build_artifacts_worker.rb deleted file mode 100644 index c64ea108d52..00000000000 --- a/app/workers/expire_build_artifacts_worker.rb +++ /dev/null @@ -1,13 +0,0 @@ -class ExpireBuildArtifactsWorker - include Sidekiq::Worker - - def perform - Rails.logger.info 'Cleaning old build artifacts' - - builds = Ci::Build.with_expired_artifacts - builds.find_each(batch_size: 50).each do |build| - Rails.logger.debug "Removing artifacts build #{build.id}..." - build.erase_artifacts! - end - end -end diff --git a/app/workers/stuck_ci_builds_worker.rb b/app/workers/stuck_ci_builds_worker.rb index 6828013b377..ca594e77e7c 100644 --- a/app/workers/stuck_ci_builds_worker.rb +++ b/app/workers/stuck_ci_builds_worker.rb @@ -6,7 +6,7 @@ class StuckCiBuildsWorker def perform Rails.logger.info 'Cleaning stuck builds' - builds = Ci::Build.joins(:project).running_or_pending.where('ci_builds.updated_at < ?', BUILD_STUCK_TIMEOUT.ago) + builds = Ci::Build.running_or_pending.where('updated_at < ?', BUILD_STUCK_TIMEOUT.ago) builds.find_each(batch_size: 50).each do |build| Rails.logger.debug "Dropping stuck #{build.status} build #{build.id} for runner #{build.runner_id}" build.drop |