diff options
Diffstat (limited to 'app')
33 files changed, 224 insertions, 128 deletions
diff --git a/app/assets/javascripts/behaviors/autosize.js b/app/assets/javascripts/behaviors/autosize.js index 3bea460dcc6..e00af4b2fa8 100644 --- a/app/assets/javascripts/behaviors/autosize.js +++ b/app/assets/javascripts/behaviors/autosize.js @@ -1,23 +1,8 @@ import autosize from 'vendor/autosize'; -$(() => { - const $fields = $('.js-autosize'); +document.addEventListener('DOMContentLoaded', () => { + const autosizeEls = document.querySelectorAll('.js-autosize'); - $fields.on('autosize:resized', function resized() { - const $field = $(this); - $field.data('height', $field.outerHeight()); - }); - - $fields.on('resize.autosize', function resize() { - const $field = $(this); - if ($field.data('height') !== $field.outerHeight()) { - $field.data('height', $field.outerHeight()); - autosize.destroy($field); - $field.css('max-height', window.outerHeight); - } - }); - - autosize($fields); - autosize.update($fields); - $fields.css('resize', 'vertical'); + autosize(autosizeEls); + autosize.update(autosizeEls); }); diff --git a/app/assets/javascripts/monitoring/components/monitoring_column.vue b/app/assets/javascripts/monitoring/components/monitoring_column.vue index 4f4792877ee..e933634643b 100644 --- a/app/assets/javascripts/monitoring/components/monitoring_column.vue +++ b/app/assets/javascripts/monitoring/components/monitoring_column.vue @@ -104,7 +104,7 @@ } this.data = query.result[0].values; this.unitOfDisplay = query.unit || 'N/A'; - this.yAxisLabel = this.columnData.y_axis || 'Values'; + this.yAxisLabel = this.columnData.y_label || 'Values'; this.legendTitle = query.legend || 'Average'; this.graphWidth = this.$refs.baseSvg.clientWidth - this.margin.left - this.margin.right; diff --git a/app/assets/javascripts/users_select.js b/app/assets/javascripts/users_select.js index 46efdcf4202..5728afb4c59 100644 --- a/app/assets/javascripts/users_select.js +++ b/app/assets/javascripts/users_select.js @@ -206,8 +206,6 @@ function UsersSelect(currentUser, els) { return $dropdown.glDropdown({ showMenuAbove: showMenuAbove, data: function(term, callback) { - var isAuthorFilter; - isAuthorFilter = $('.js-author-search'); return _this.users(term, options, function(users) { // GitLabDropdownFilter returns this.instance // GitLabDropdownRemote returns this.options.instance diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb index ca483c105b6..54f108353cd 100644 --- a/app/controllers/projects/issues_controller.rb +++ b/app/controllers/projects/issues_controller.rb @@ -227,7 +227,7 @@ class Projects::IssuesController < Projects::ApplicationController def issue return @issue if defined?(@issue) # The Sortable default scope causes performance issues when used with find_by - @noteable = @issue ||= @project.issues.where(iid: params[:id]).reorder(nil).take! + @noteable = @issue ||= @project.issues.find_by!(iid: params[:id]) return render_404 unless can?(current_user, :read_issue, @issue) diff --git a/app/finders/labels_finder.rb b/app/finders/labels_finder.rb index 042d792dada..ce432ddbfe6 100644 --- a/app/finders/labels_finder.rb +++ b/app/finders/labels_finder.rb @@ -83,7 +83,12 @@ class LabelsFinder < UnionFinder def projects return @projects if defined?(@projects) - @projects = skip_authorization ? Project.all : ProjectsFinder.new(current_user: current_user).execute + @projects = if skip_authorization + Project.all + else + ProjectsFinder.new(params: { non_archived: true }, current_user: current_user).execute + end + @projects = @projects.in_namespace(params[:group_id]) if group? @projects = @projects.where(id: params[:project_ids]) if projects? @projects = @projects.reorder(nil) diff --git a/app/finders/users_finder.rb b/app/finders/users_finder.rb index dbd50d1db7c..07deceb827b 100644 --- a/app/finders/users_finder.rb +++ b/app/finders/users_finder.rb @@ -60,13 +60,13 @@ class UsersFinder end def by_external_identity(users) - return users unless current_user.admin? && params[:extern_uid] && params[:provider] + return users unless current_user&.admin? && params[:extern_uid] && params[:provider] users.joins(:identities).merge(Identity.with_extern_uid(params[:provider], params[:extern_uid])) end def by_external(users) - return users = users.where.not(external: true) unless current_user.admin? + return users = users.where.not(external: true) unless current_user&.admin? return users unless params[:external] users.external diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 7be8e3b96cf..1c165700b19 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -298,10 +298,6 @@ module ApplicationHelper end end - def can_toggle_new_nav? - Rails.env.development? - end - def show_new_nav? cookies["new_nav"] == "true" end diff --git a/app/helpers/form_helper.rb b/app/helpers/form_helper.rb index 8ceb5c36bda..9247b1f72de 100644 --- a/app/helpers/form_helper.rb +++ b/app/helpers/form_helper.rb @@ -16,8 +16,8 @@ module FormHelper end end - def issue_dropdown_options(issuable, has_multiple_assignees = true) - options = { + def issue_assignees_dropdown_options + { toggle_class: 'js-user-search js-assignee-search js-multiselect js-save-user-data', title: 'Select assignee', filter: true, @@ -27,8 +27,8 @@ module FormHelper first_user: current_user&.username, null_user: true, current_user: true, - project_id: issuable.project.try(:id), - field_name: "#{issuable.class.model_name.param_key}[assignee_ids][]", + project_id: @project.id, + field_name: 'issue[assignee_ids][]', default_label: 'Unassigned', 'max-select': 1, 'dropdown-header': 'Assignee', @@ -38,13 +38,5 @@ module FormHelper current_user_info: current_user.to_json(only: [:id, :name]) } } - - if has_multiple_assignees - options[:title] = 'Select assignee(s)' - options[:data][:'dropdown-header'] = 'Assignee(s)' - options[:data].delete(:'max-select') - end - - options end end diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb index af0b3e9c5bc..8cd61f738e1 100644 --- a/app/helpers/groups_helper.rb +++ b/app/helpers/groups_helper.rb @@ -58,6 +58,11 @@ module GroupsHelper IssuesFinder.new(current_user, group_id: group.id).execute end + def remove_group_message(group) + _("You are going to remove %{group_name}.\nRemoved groups CANNOT be restored!\nAre you ABSOLUTELY sure?") % + { group_name: group.name } + end + private def group_title_link(group, hidable: false) diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb index 8f15904f068..f39a3bb55a8 100644 --- a/app/helpers/search_helper.rb +++ b/app/helpers/search_helper.rb @@ -126,6 +126,18 @@ module SearchHelper search_path(options) end + def search_filter_input_options(type) + { + id: "filtered-search-#{type}", + placeholder: 'Search or filter results...', + data: { + 'project-id' => @project.id, + 'username-params' => @users.to_json(only: [:id, :username]), + 'base-endpoint' => namespace_project_path(@project.namespace, @project) + } + } + end + # Sanitize a HTML field for search display. Most tags are stripped out and the # maximum length is set to 200 characters. def search_md_sanitize(object, field) diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index a300536532b..2e7a80d308b 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -176,9 +176,12 @@ module Ci # * Lowercased # * Anything not matching [a-z0-9-] is replaced with a - # * Maximum length is 63 bytes + # * First/Last Character is not a hyphen def ref_slug - slugified = ref.to_s.downcase - slugified.gsub(/[^a-z0-9]/, '-')[0..62] + ref.to_s + .downcase + .gsub(/[^a-z0-9]/, '-')[0..62] + .gsub(/(\A-+|-+\z)/, '') end # Variables whose value does not depend on environment diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb index d178ee4422b..41c8b525273 100644 --- a/app/models/concerns/issuable.rb +++ b/app/models/concerns/issuable.rb @@ -102,6 +102,14 @@ module Issuable def locking_enabled? title_changed? || description_changed? end + + def allows_multiple_assignees? + false + end + + def has_multiple_assignees? + assignees.count > 1 + end end module ClassMethods diff --git a/app/models/concerns/sortable.rb b/app/models/concerns/sortable.rb index a155a064032..fdacfa5a194 100644 --- a/app/models/concerns/sortable.rb +++ b/app/models/concerns/sortable.rb @@ -5,6 +5,25 @@ module Sortable extend ActiveSupport::Concern + module DropDefaultScopeOnFinders + # Override these methods to drop the `ORDER BY id DESC` default scope. + # See http://dba.stackexchange.com/a/110919 for why we do this. + %i[find find_by find_by!].each do |meth| + define_method meth do |*args, &block| + return super(*args, &block) if block + + unordered_relation = unscope(:order) + + # We cannot simply call `meth` on `unscope(:order)`, since that is also + # an instance of the same relation class this module is included into, + # which means we'd get infinite recursion. + # We explicitly use the original implementation to prevent this. + original_impl = method(__method__).super_method.unbind + original_impl.bind(unordered_relation).call(*args) + end + end + end + included do # By default all models should be ordered # by created_at field starting from newest @@ -18,6 +37,10 @@ module Sortable scope :order_updated_asc, -> { reorder(updated_at: :asc) } scope :order_name_asc, -> { reorder(name: :asc) } scope :order_name_desc, -> { reorder(name: :desc) } + + # All queries (relations) on this model are instances of this `relation_klass`. + relation_klass = relation_delegate_class(ActiveRecord::Relation) + relation_klass.prepend DropDefaultScopeOnFinders end module ClassMethods diff --git a/app/models/forked_project_link.rb b/app/models/forked_project_link.rb index 36cf7ad6a28..8d35864eff6 100644 --- a/app/models/forked_project_link.rb +++ b/app/models/forked_project_link.rb @@ -1,4 +1,4 @@ class ForkedProjectLink < ActiveRecord::Base - belongs_to :forked_to_project, class_name: 'Project' - belongs_to :forked_from_project, class_name: 'Project' + belongs_to :forked_to_project, -> { where.not(pending_delete: true) }, class_name: 'Project' + belongs_to :forked_from_project, -> { where.not(pending_delete: true) }, class_name: 'Project' end diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index c099d731082..808212c780c 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -197,11 +197,19 @@ class MergeRequest < ActiveRecord::Base } end - # This method is needed for compatibility with issues to not mess view and other code + # These method are needed for compatibility with issues to not mess view and other code def assignees Array(assignee) end + def assignee_ids + Array(assignee_id) + end + + def assignee_ids=(ids) + write_attribute(:assignee_id, ids.last) + end + def assignee_or_author?(user) author_id == user.id || assignee_id == user.id end diff --git a/app/models/project.rb b/app/models/project.rb index 241e7e60dd2..8e9e42d28ab 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -815,7 +815,7 @@ class Project < ActiveRecord::Base end def ci_service - @ci_service ||= ci_services.reorder(nil).find_by(active: true) + @ci_service ||= ci_services.find_by(active: true) end def deployment_services @@ -823,7 +823,7 @@ class Project < ActiveRecord::Base end def deployment_service - @deployment_service ||= deployment_services.reorder(nil).find_by(active: true) + @deployment_service ||= deployment_services.find_by(active: true) end def monitoring_services @@ -831,7 +831,7 @@ class Project < ActiveRecord::Base end def monitoring_service - @monitoring_service ||= monitoring_services.reorder(nil).find_by(active: true) + @monitoring_service ||= monitoring_services.find_by(active: true) end def jira_tracker? diff --git a/app/policies/base_policy.rb b/app/policies/base_policy.rb index 191c2e78a08..a605a3457c8 100644 --- a/app/policies/base_policy.rb +++ b/app/policies/base_policy.rb @@ -1,6 +1,8 @@ require_dependency 'declarative_policy' class BasePolicy < DeclarativePolicy::Base + include Gitlab::CurrentSettings + desc "User is an instance admin" with_options scope: :user, score: 0 condition(:admin) { @user&.admin? } @@ -10,4 +12,9 @@ class BasePolicy < DeclarativePolicy::Base with_options scope: :user, score: 0 condition(:can_create_group) { @user&.can_create_group } + + desc "The application is restricted from public visibility" + condition(:restricted_public_level, scope: :global) do + current_application_settings.restricted_visibility_levels.include?(Gitlab::VisibilityLevel::PUBLIC) + end end diff --git a/app/policies/global_policy.rb b/app/policies/global_policy.rb index 535faa922dd..55eefa76d3f 100644 --- a/app/policies/global_policy.rb +++ b/app/policies/global_policy.rb @@ -11,10 +11,16 @@ class GlobalPolicy < BasePolicy with_options scope: :user, score: 0 condition(:access_locked) { @user.access_locked? } - rule { anonymous }.prevent_all + rule { anonymous }.policy do + prevent :log_in + prevent :access_api + prevent :access_git + prevent :receive_notifications + prevent :use_quick_actions + prevent :create_group + end rule { default }.policy do - enable :read_users_list enable :log_in enable :access_api enable :access_git @@ -37,4 +43,8 @@ class GlobalPolicy < BasePolicy rule { access_locked }.policy do prevent :log_in end + + rule { ~restricted_public_level }.policy do + enable :read_users_list + end end diff --git a/app/policies/user_policy.rb b/app/policies/user_policy.rb index 0181ddf85e0..0905ddd9b38 100644 --- a/app/policies/user_policy.rb +++ b/app/policies/user_policy.rb @@ -1,11 +1,4 @@ class UserPolicy < BasePolicy - include Gitlab::CurrentSettings - - desc "The application is restricted from public visibility" - condition(:restricted_public_level, scope: :global) do - current_application_settings.restricted_visibility_levels.include?(Gitlab::VisibilityLevel::PUBLIC) - end - desc "The current user is the user in question" condition(:user_is_self, score: 0) { @subject == @user } diff --git a/app/services/delete_merged_branches_service.rb b/app/services/delete_merged_branches_service.rb index 3b611588466..5c9e2a16c71 100644 --- a/app/services/delete_merged_branches_service.rb +++ b/app/services/delete_merged_branches_service.rb @@ -10,6 +10,8 @@ class DeleteMergedBranchesService < BaseService branches = branches.select { |branch| project.repository.merged_to_root_ref?(branch) } # Prevent deletion of branches relevant to open merge requests branches -= merge_request_branch_names + # Prevent deletion of protected branches + branches -= project.protected_branches.pluck(:name) branches.each do |branch| DeleteBranchService.new(project, current_user).execute(branch) diff --git a/app/services/merge_requests/merge_service.rb b/app/services/merge_requests/merge_service.rb index b247cb89e5e..bc846e07f24 100644 --- a/app/services/merge_requests/merge_service.rb +++ b/app/services/merge_requests/merge_service.rb @@ -61,8 +61,12 @@ module MergeRequests MergeRequests::PostMergeService.new(project, current_user).execute(merge_request) if params[:should_remove_source_branch].present? || @merge_request.force_remove_source_branch? - DeleteBranchService.new(@merge_request.source_project, branch_deletion_user) - .execute(merge_request.source_branch) + # Verify again that the source branch can be removed, since branch may be protected, + # or the source branch may have been updated. + if @merge_request.can_remove_source_branch?(branch_deletion_user) + DeleteBranchService.new(@merge_request.source_project, branch_deletion_user) + .execute(merge_request.source_branch) + end end end diff --git a/app/services/quick_actions/interpret_service.rb b/app/services/quick_actions/interpret_service.rb index 6816b137361..e4dfe87e614 100644 --- a/app/services/quick_actions/interpret_service.rb +++ b/app/services/quick_actions/interpret_service.rb @@ -92,9 +92,12 @@ module QuickActions desc 'Assign' explanation do |users| - "Assigns #{users.first.to_reference}." if users.any? + users = issuable.allows_multiple_assignees? ? users : users.take(1) + "Assigns #{users.map(&:to_reference).to_sentence}." + end + params do + issuable.allows_multiple_assignees? ? '@user1 @user2' : '@user' end - params '@user' condition do current_user.can?(:"admin_#{issuable.to_ability_name}", project) end @@ -104,28 +107,69 @@ module QuickActions command :assign do |users| next if users.empty? - if issuable.is_a?(Issue) - @updates[:assignee_ids] = [users.last.id] + @updates[:assignee_ids] = + if issuable.allows_multiple_assignees? + issuable.assignees.pluck(:id) + users.map(&:id) + else + [users.last.id] + end + end + + desc do + if issuable.allows_multiple_assignees? + 'Remove all or specific assignee(s)' else - @updates[:assignee_id] = users.last.id + 'Remove assignee' end end - - desc 'Remove assignee' explanation do - "Removes assignee #{issuable.assignees.first.to_reference}." + "Removes #{'assignee'.pluralize(issuable.assignees.size)} #{issuable.assignees.map(&:to_reference).to_sentence}." + end + params do + issuable.allows_multiple_assignees? ? '@user1 @user2' : '' end condition do issuable.persisted? && issuable.assignees.any? && current_user.can?(:"admin_#{issuable.to_ability_name}", project) end - command :unassign do - if issuable.is_a?(Issue) - @updates[:assignee_ids] = [] - else - @updates[:assignee_id] = nil - end + parse_params do |unassign_param| + # When multiple users are assigned, all will be unassigned if multiple assignees are no longer allowed + extract_users(unassign_param) if issuable.allows_multiple_assignees? + end + command :unassign do |users = nil| + @updates[:assignee_ids] = + if users&.any? + issuable.assignees.pluck(:id) - users.map(&:id) + else + [] + end + end + + desc do + "Change assignee#{'(s)' if issuable.allows_multiple_assignees?}" + end + explanation do |users| + users = issuable.allows_multiple_assignees? ? users : users.take(1) + "Change #{'assignee'.pluralize(users.size)} to #{users.map(&:to_reference).to_sentence}." + end + params do + issuable.allows_multiple_assignees? ? '@user1 @user2' : '@user' + end + condition do + issuable.persisted? && + current_user.can?(:"admin_#{issuable.to_ability_name}", project) + end + parse_params do |assignee_param| + extract_users(assignee_param) + end + command :reassign do |users| + @updates[:assignee_ids] = + if issuable.allows_multiple_assignees? + users.map(&:id) + else + [users.last.id] + end end desc 'Set milestone' diff --git a/app/views/groups/edit.html.haml b/app/views/groups/edit.html.haml index 7d5add3cc1c..9ebb3894c55 100644 --- a/app/views/groups/edit.html.haml +++ b/app/views/groups/edit.html.haml @@ -45,10 +45,13 @@ .panel.panel-danger .panel-heading Remove group .panel-body - %p - Removing group will cause all child projects and resources to be removed. - %br - %strong Removed group can not be restored! + = form_tag(@group, method: :delete) do + %p + Removing group will cause all child projects and resources to be removed. + %br + %strong Removed group can not be restored! - .form-actions - = link_to 'Remove group', @group, data: {confirm: 'Removed group can not be restored! Are you sure?'}, method: :delete, class: "btn btn-remove" + .form-actions + = button_to 'Remove group', '#', class: "btn btn-remove js-confirm-danger", data: { "confirm-danger-message" => remove_group_message(@group) } + += render 'shared/confirm_modal', phrase: @group.path diff --git a/app/views/layouts/header/_default.html.haml b/app/views/layouts/header/_default.html.haml index 8cbc3f6105f..7e8b9cb9ad0 100644 --- a/app/views/layouts/header/_default.html.haml +++ b/app/views/layouts/header/_default.html.haml @@ -74,9 +74,8 @@ = link_to "Profile", current_user, class: 'profile-link', data: { user: current_user.username } %li = link_to "Settings", profile_path - - if can_toggle_new_nav? - %li - = link_to "Turn on new nav", profile_preferences_path(anchor: "new-navigation") + %li + = link_to "Turn on new nav", profile_preferences_path(anchor: "new-navigation") %li.divider %li = link_to "Sign out", destroy_user_session_path, method: :delete, class: "sign-out-link" diff --git a/app/views/profiles/preferences/show.html.haml b/app/views/profiles/preferences/show.html.haml index a089aeb2447..2dd938f8379 100644 --- a/app/views/profiles/preferences/show.html.haml +++ b/app/views/profiles/preferences/show.html.haml @@ -16,25 +16,22 @@ .preview= image_tag "#{scheme.css_class}-scheme-preview.png" = f.radio_button :color_scheme_id, scheme.id = scheme.name - - if can_toggle_new_nav? - .col-sm-12 - %hr - .col-lg-3.profile-settings-sidebar#new-navigation - %h4.prepend-top-0 - New Navigation - %p - This setting allows you to turn on or off the new upcoming navigation concept. - = succeed '.' do - = link_to 'Learn more', '', target: '_blank' - .col-lg-9.syntax-theme - = label_tag do - .preview= image_tag "old_nav.png" - %input.js-experiment-feature-toggle{ type: "radio", value: "false", name: "new_nav", checked: !show_new_nav? } - Old - = label_tag do - .preview= image_tag "new_nav.png" - %input.js-experiment-feature-toggle{ type: "radio", value: "true", name: "new_nav", checked: show_new_nav? } - New + .col-sm-12 + %hr + .col-lg-3.profile-settings-sidebar#new-navigation + %h4.prepend-top-0 + New Navigation + %p + This setting allows you to turn on or off the new upcoming navigation concept. + .col-lg-9.syntax-theme + = label_tag do + .preview= image_tag "old_nav.png" + %input.js-experiment-feature-toggle{ type: "radio", value: "false", name: "new_nav", checked: !show_new_nav? } + Old + = label_tag do + .preview= image_tag "new_nav.png" + %input.js-experiment-feature-toggle{ type: "radio", value: "true", name: "new_nav", checked: show_new_nav? } + New .col-sm-12 %hr .col-lg-4.profile-settings-sidebar diff --git a/app/views/projects/boards/components/sidebar/_assignee.html.haml b/app/views/projects/boards/components/sidebar/_assignee.html.haml index e8db868f49b..c314573bdea 100644 --- a/app/views/projects/boards/components/sidebar/_assignee.html.haml +++ b/app/views/projects/boards/components/sidebar/_assignee.html.haml @@ -19,10 +19,11 @@ ":data-name" => "assignee.name", ":data-username" => "assignee.username" } .dropdown - %button.dropdown-menu-toggle.js-user-search.js-author-search.js-multiselect.js-save-user-data.js-issue-board-sidebar{ type: "button", ref: "assigneeDropdown", data: { toggle: "dropdown", field_name: "issue[assignee_ids][]", first_user: (current_user.username if current_user), current_user: "true", project_id: @project.id, null_user: "true", multi_select: "true", 'max-select' => 1, dropdown: { header: 'Assignee' } }, + - dropdown_options = issue_assignees_dropdown_options + %button.dropdown-menu-toggle.js-user-search.js-author-search.js-multiselect.js-save-user-data.js-issue-board-sidebar{ type: 'button', ref: 'assigneeDropdown', data: { toggle: 'dropdown', field_name: 'issue[assignee_ids][]', first_user: current_user&.username, current_user: 'true', project_id: @project.id, null_user: 'true', multi_select: 'true', 'dropdown-header': dropdown_options[:data][:'dropdown-header'], 'max-select': dropdown_options[:data][:'max-select'] }, ":data-issuable-id" => "issue.id", ":data-issue-update" => "'#{namespace_project_issues_path(@project.namespace, @project)}/' + issue.id + '.json'" } - Select assignee + = dropdown_options[:title] = icon("chevron-down") .dropdown-menu.dropdown-select.dropdown-menu-user.dropdown-menu-selectable.dropdown-menu-author = dropdown_title("Assign to") diff --git a/app/views/projects/pipelines/charts.html.haml b/app/views/projects/pipelines/charts.html.haml index 8ffddfe6154..78002e8cd64 100644 --- a/app/views/projects/pipelines/charts.html.haml +++ b/app/views/projects/pipelines/charts.html.haml @@ -1,5 +1,5 @@ - @no_container = true -- page_title "Charts", "Pipelines" +- page_title _("Charts"), _("Pipelines") - content_for :page_specific_javascripts do = page_specific_javascript_bundle_tag('common_d3') = page_specific_javascript_bundle_tag('graphs') @@ -8,7 +8,7 @@ %div{ class: container_class } .sub-header-block .oneline - A collection of graphs for Continuous Integration + = _("A collection of graphs regarding Continuous Integration") #charts.ci-charts .row diff --git a/app/views/projects/pipelines/charts/_overall.haml b/app/views/projects/pipelines/charts/_overall.haml index 93083397d5b..66786c7ff59 100644 --- a/app/views/projects/pipelines/charts/_overall.haml +++ b/app/views/projects/pipelines/charts/_overall.haml @@ -1,15 +1,15 @@ -%h4 Overall stats +%h4= s_("PipelineCharts|Overall statistics") %ul %li - Total: - %strong= pluralize @counts[:total], 'pipeline' + = s_("PipelineCharts|Total:") + %strong= n_("1 pipeline", "%d pipelines", @counts[:total]) % @counts[:total] %li - Successful: - %strong= pluralize @counts[:success], 'pipeline' + = s_("PipelineCharts|Successful:") + %strong= n_("1 pipeline", "%d pipelines", @counts[:success]) % @counts[:success] %li - Failed: - %strong= pluralize @counts[:failed], 'pipeline' + = s_("PipelineCharts|Failed:") + %strong= n_("1 pipeline", "%d pipelines", @counts[:failed]) % @counts[:failed] %li - Success ratio: + = s_("PipelineCharts|Success ratio:") %strong #{success_ratio(@counts)}% diff --git a/app/views/projects/pipelines/charts/_pipeline_times.haml b/app/views/projects/pipelines/charts/_pipeline_times.haml index aee7c5492aa..1292f580a81 100644 --- a/app/views/projects/pipelines/charts/_pipeline_times.haml +++ b/app/views/projects/pipelines/charts/_pipeline_times.haml @@ -1,6 +1,6 @@ %div %p.light - Commit duration in minutes for last 30 commits + = _("Commit duration in minutes for last 30 commits") %canvas#build_timesChart{ height: 200 } diff --git a/app/views/projects/pipelines/charts/_pipelines.haml b/app/views/projects/pipelines/charts/_pipelines.haml index b6f453b9736..be884448087 100644 --- a/app/views/projects/pipelines/charts/_pipelines.haml +++ b/app/views/projects/pipelines/charts/_pipelines.haml @@ -1,29 +1,29 @@ -%h4 Pipelines charts +%h4= _("Pipelines charts") %p %span.cgreen = icon("circle") - success + = s_("Pipeline|success") %span.cgray = icon("circle") - all + = s_("Pipeline|all") .prepend-top-default %p.light - Jobs for last week + = _("Jobs for last week") (#{date_from_to(Date.today - 7.days, Date.today)}) %canvas#weekChart{ height: 200 } .prepend-top-default %p.light - Jobs for last month + = _("Jobs for last month") (#{date_from_to(Date.today - 30.days, Date.today)}) %canvas#monthChart{ height: 200 } .prepend-top-default %p.light - Jobs for last year + = _("Jobs for last year") %canvas#yearChart.padded{ height: 250 } - [:week, :month, :year].each do |scope| diff --git a/app/views/shared/issuable/_search_bar.html.haml b/app/views/shared/issuable/_search_bar.html.haml index d3d290692a2..ae890567225 100644 --- a/app/views/shared/issuable/_search_bar.html.haml +++ b/app/views/shared/issuable/_search_bar.html.haml @@ -23,7 +23,7 @@ .scroll-container %ul.tokens-container.list-unstyled %li.input-token - %input.form-control.filtered-search{ id: "filtered-search-#{type.to_s}", placeholder: 'Search or filter results...', data: { 'project-id' => @project.id, 'username-params' => @users.to_json(only: [:id, :username]), 'base-endpoint' => namespace_project_path(@project.namespace, @project) } } + %input.form-control.filtered-search{ search_filter_input_options(type) } = icon('filter') #js-dropdown-hint.filtered-search-input-dropdown-menu.dropdown-menu.hint-dropdown %ul{ data: { dropdown: true } } diff --git a/app/views/shared/issuable/_sidebar_assignees.html.haml b/app/views/shared/issuable/_sidebar_assignees.html.haml index 2ea5eb960c0..57392cd7fbb 100644 --- a/app/views/shared/issuable/_sidebar_assignees.html.haml +++ b/app/views/shared/issuable/_sidebar_assignees.html.haml @@ -37,19 +37,20 @@ - issuable.assignees.each do |assignee| = hidden_field_tag "#{issuable.to_ability_name}[assignee_ids][]", assignee.id, id: nil, data: { avatar_url: assignee.avatar_url, name: assignee.name, username: assignee.username } - - options = { toggle_class: 'js-user-search js-author-search', title: 'Assign to', filter: true, dropdown_class: 'dropdown-menu-user dropdown-menu-selectable dropdown-menu-author', placeholder: 'Search users', data: { first_user: (current_user.username if current_user), current_user: true, project_id: (@project.id if @project), author_id: issuable.author_id, field_name: "#{issuable.to_ability_name}[assignee_ids][]", issue_update: issuable_json_path(issuable), ability_name: issuable.to_ability_name, null_user: true } } - + - options = { toggle_class: 'js-user-search js-author-search', title: 'Assign to', filter: true, dropdown_class: 'dropdown-menu-user dropdown-menu-selectable dropdown-menu-author', placeholder: 'Search users', data: { first_user: current_user&.username, current_user: true, project_id: @project&.id, author_id: issuable.author_id, field_name: "#{issuable.to_ability_name}[assignee_ids][]", issue_update: issuable_json_path(issuable), ability_name: issuable.to_ability_name, null_user: true } } - title = 'Select assignee' - if issuable.is_a?(Issue) - unless issuable.assignees.any? = hidden_field_tag "#{issuable.to_ability_name}[assignee_ids][]", 0, id: nil + - dropdown_options = issue_assignees_dropdown_options + - title = dropdown_options[:title] - options[:toggle_class] += ' js-multiselect js-save-user-data' - data = { field_name: "#{issuable.to_ability_name}[assignee_ids][]" } - data[:multi_select] = true - data['dropdown-title'] = title - - data['dropdown-header'] = 'Assignee' - - data['max-select'] = 1 + - data['dropdown-header'] = dropdown_options[:data][:'dropdown-header'] + - data['max-select'] = dropdown_options[:data][:'max-select'] - options[:data].merge!(data) = dropdown_tag(title, options: options) diff --git a/app/views/shared/issuable/form/_metadata_issue_assignee.html.haml b/app/views/shared/issuable/form/_metadata_issue_assignee.html.haml index 77175c839a6..567cde764e2 100644 --- a/app/views/shared/issuable/form/_metadata_issue_assignee.html.haml +++ b/app/views/shared/issuable/form/_metadata_issue_assignee.html.haml @@ -7,5 +7,5 @@ - if issuable.assignees.length === 0 = hidden_field_tag "#{issuable.to_ability_name}[assignee_ids][]", 0, id: nil, data: { meta: '' } - = dropdown_tag(users_dropdown_label(issuable.assignees), options: issue_dropdown_options(issuable,false)) + = dropdown_tag(users_dropdown_label(issuable.assignees), options: issue_assignees_dropdown_options) = link_to 'Assign to me', '#', class: "assign-to-me-link #{'hide' if issuable.assignees.include?(current_user)}" |