summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/pages/search/show/search.js16
-rw-r--r--app/assets/stylesheets/pages/search.scss16
-rw-r--r--app/controllers/graphql_controller.rb4
-rw-r--r--app/graphql/mutations/award_emojis/base.rb7
-rw-r--r--app/graphql/mutations/design_management/move.rb2
-rw-r--r--app/graphql/mutations/metrics/dashboard/annotations/create.rb17
-rw-r--r--app/graphql/mutations/notes/base.rb5
-rw-r--r--app/graphql/mutations/notes/create/base.rb9
-rw-r--r--app/graphql/mutations/notes/destroy.rb6
-rw-r--r--app/graphql/mutations/todos/base.rb7
-rw-r--r--app/graphql/mutations/todos/restore_many.rb18
-rw-r--r--app/views/projects/merge_requests/_merge_request.html.haml3
-rw-r--r--app/views/search/_filter.html.haml24
-rw-r--r--app/views/search/_form.html.haml2
-rw-r--r--app/views/shared/issuable/_reviewers.html.haml11
15 files changed, 100 insertions, 47 deletions
diff --git a/app/assets/javascripts/pages/search/show/search.js b/app/assets/javascripts/pages/search/show/search.js
index 6ff74325a5e..2cd333f26e1 100644
--- a/app/assets/javascripts/pages/search/show/search.js
+++ b/app/assets/javascripts/pages/search/show/search.js
@@ -4,6 +4,7 @@ import { deprecatedCreateFlash as Flash } from '~/flash';
import Api from '~/api';
import { __ } from '~/locale';
import Project from '~/pages/projects/project';
+import { visitUrl } from '~/lib/utils/url_utility';
import refreshCounts from './refresh_counts';
import setHighlightClass from './highlight_blob_search_result';
@@ -86,6 +87,10 @@ export default class Search {
$(document)
.off('click', this.searchClear)
.on('click', this.searchClear, this.clearSearchField.bind(this));
+
+ $('a.js-search-clear')
+ .off('click', this.clearSearchFilter)
+ .on('click', this.clearSearchFilter);
}
static submitSearch() {
@@ -108,6 +113,17 @@ export default class Search {
.focus();
}
+ // We need to manually follow the link on the anchors
+ // that have this event bound, as their `click` default
+ // behavior is prevented by the toggle logic.
+ /* eslint-disable-next-line class-methods-use-this */
+ clearSearchFilter(ev) {
+ const $target = $(ev.currentTarget);
+
+ visitUrl($target.href);
+ ev.stopPropagation();
+ }
+
getProjectsData(term) {
return new Promise(resolve => {
if (this.groupId) {
diff --git a/app/assets/stylesheets/pages/search.scss b/app/assets/stylesheets/pages/search.scss
index 86caed329b4..a62e28a9b8a 100644
--- a/app/assets/stylesheets/pages/search.scss
+++ b/app/assets/stylesheets/pages/search.scss
@@ -198,6 +198,15 @@ input[type='checkbox']:hover {
}
}
+ .search-clear {
+ position: absolute;
+ right: 10px;
+ top: 9px;
+ padding: 0;
+ line-height: 0;
+ background: none;
+ border: 0;
+ }
.search-icon {
position: absolute;
@@ -247,14 +256,7 @@ input[type='checkbox']:hover {
}
.search-clear {
- position: absolute;
- right: 10px;
- top: 9px;
- padding: 0;
color: $gray-darkest;
- line-height: 0;
- background: none;
- border: 0;
&:hover,
&:focus {
diff --git a/app/controllers/graphql_controller.rb b/app/controllers/graphql_controller.rb
index 5edad410724..b5deed70380 100644
--- a/app/controllers/graphql_controller.rb
+++ b/app/controllers/graphql_controller.rb
@@ -48,6 +48,10 @@ class GraphqlController < ApplicationController
render_error(exception.message, status: :unprocessable_entity)
end
+ rescue_from ::GraphQL::CoercionError do |exception|
+ render_error(exception.message, status: :unprocessable_entity)
+ end
+
private
def set_user_last_activity
diff --git a/app/graphql/mutations/award_emojis/base.rb b/app/graphql/mutations/award_emojis/base.rb
index 583744c3884..df6b883529e 100644
--- a/app/graphql/mutations/award_emojis/base.rb
+++ b/app/graphql/mutations/award_emojis/base.rb
@@ -6,7 +6,7 @@ module Mutations
authorize :award_emoji
argument :awardable_id,
- GraphQL::ID_TYPE,
+ ::Types::GlobalIDType[::Awardable],
required: true,
description: 'The global id of the awardable resource'
@@ -23,7 +23,10 @@ module Mutations
private
def find_object(id:)
- GitlabSchema.object_from_id(id)
+ # TODO: remove this line when the compatibility layer is removed
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
+ id = ::Types::GlobalIDType[::Awardable].coerce_isolated_input(id)
+ GitlabSchema.find_by_gid(id)
end
# Called by mutations methods after performing an authorization check
diff --git a/app/graphql/mutations/design_management/move.rb b/app/graphql/mutations/design_management/move.rb
index 43e2e542408..aed4cfec0fd 100644
--- a/app/graphql/mutations/design_management/move.rb
+++ b/app/graphql/mutations/design_management/move.rb
@@ -38,7 +38,7 @@ module Mutations
# TODO: remove this line when the compatibility layer is removed
# See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
id = DesignID.coerce_isolated_input(id)
- GitlabSchema.object_from_id(id)
+ GitlabSchema.find_by_gid(id)
end
def not_found(gid)
diff --git a/app/graphql/mutations/metrics/dashboard/annotations/create.rb b/app/graphql/mutations/metrics/dashboard/annotations/create.rb
index 6f316e76e2a..b064f55825f 100644
--- a/app/graphql/mutations/metrics/dashboard/annotations/create.rb
+++ b/app/graphql/mutations/metrics/dashboard/annotations/create.rb
@@ -18,12 +18,12 @@ module Mutations
description: 'The created annotation'
argument :environment_id,
- GraphQL::ID_TYPE,
+ ::Types::GlobalIDType[::Environment],
required: false,
description: 'The global id of the environment to add an annotation to'
argument :cluster_id,
- GraphQL::ID_TYPE,
+ ::Types::GlobalIDType[::Clusters::Cluster],
required: false,
description: 'The global id of the cluster to add an annotation to'
@@ -84,7 +84,7 @@ module Mutations
end
def find_object(id:)
- GitlabSchema.object_from_id(id)
+ GitlabSchema.find_by_gid(id)
end
def annotation_create_params(args)
@@ -96,7 +96,16 @@ module Mutations
end
def annotation_source(args)
- annotation_source_id = args[:cluster_id] || args[:environment_id]
+ # TODO: remove these lines when the compatibility layer is removed
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
+ annotation_source_id = if args[:cluster_id]
+ ::Types::GlobalIDType[::Clusters::Cluster].coerce_isolated_input(args[:cluster_id])
+ else
+ ::Types::GlobalIDType[::Environment].coerce_isolated_input(args[:environment_id])
+ end
+
+ # TODO: uncomment following line once lines above are removed
+ # annotation_source_id = args[:cluster_id] || args[:environment_id]
authorized_find!(id: annotation_source_id)
end
end
diff --git a/app/graphql/mutations/notes/base.rb b/app/graphql/mutations/notes/base.rb
index 31dabc0a660..d6d5f1e760d 100644
--- a/app/graphql/mutations/notes/base.rb
+++ b/app/graphql/mutations/notes/base.rb
@@ -11,7 +11,10 @@ module Mutations
private
def find_object(id:)
- GitlabSchema.object_from_id(id)
+ # TODO: remove explicit coercion once compatibility layer has been removed
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
+ id = ::Types::GlobalIDType[::Note].coerce_isolated_input(id)
+ GitlabSchema.find_by_gid(id)
end
def check_object_is_noteable!(object)
diff --git a/app/graphql/mutations/notes/create/base.rb b/app/graphql/mutations/notes/create/base.rb
index f081eac368e..530c15f0c10 100644
--- a/app/graphql/mutations/notes/create/base.rb
+++ b/app/graphql/mutations/notes/create/base.rb
@@ -9,7 +9,7 @@ module Mutations
authorize :create_note
argument :noteable_id,
- GraphQL::ID_TYPE,
+ ::Types::GlobalIDType[::Noteable],
required: true,
description: 'The global id of the resource to add a note to'
@@ -42,6 +42,13 @@ module Mutations
private
+ def find_object(id:)
+ # TODO: remove explicit coercion once compatibility layer has been removed
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
+ id = ::Types::GlobalIDType[::Noteable].coerce_isolated_input(id)
+ GitlabSchema.find_by_gid(id)
+ end
+
def create_note_params(noteable, args)
{
noteable: noteable,
diff --git a/app/graphql/mutations/notes/destroy.rb b/app/graphql/mutations/notes/destroy.rb
index a81322bc9b7..83a91f07896 100644
--- a/app/graphql/mutations/notes/destroy.rb
+++ b/app/graphql/mutations/notes/destroy.rb
@@ -8,9 +8,9 @@ module Mutations
authorize :admin_note
argument :id,
- GraphQL::ID_TYPE,
- required: true,
- description: 'The global id of the note to destroy'
+ ::Types::GlobalIDType[::Note],
+ required: true,
+ description: 'The global id of the note to destroy'
def resolve(id:)
note = authorized_find!(id: id)
diff --git a/app/graphql/mutations/todos/base.rb b/app/graphql/mutations/todos/base.rb
index 2a72019fbac..6db863796bc 100644
--- a/app/graphql/mutations/todos/base.rb
+++ b/app/graphql/mutations/todos/base.rb
@@ -6,7 +6,10 @@ module Mutations
private
def find_object(id:)
- GitlabSchema.object_from_id(id)
+ # TODO: remove this line when the compatibility layer is removed
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
+ id = ::Types::GlobalIDType[::Todo].coerce_isolated_input(id)
+ GitlabSchema.find_by_gid(id)
end
def map_to_global_ids(ids)
@@ -16,7 +19,7 @@ module Mutations
end
def to_global_id(id)
- ::URI::GID.build(app: GlobalID.app, model_name: Todo.name, model_id: id, params: nil).to_s
+ Gitlab::GlobalId.as_global_id(id, model_name: Todo.name).to_s
end
end
end
diff --git a/app/graphql/mutations/todos/restore_many.rb b/app/graphql/mutations/todos/restore_many.rb
index c5e2750768c..ea5f5414134 100644
--- a/app/graphql/mutations/todos/restore_many.rb
+++ b/app/graphql/mutations/todos/restore_many.rb
@@ -8,7 +8,7 @@ module Mutations
MAX_UPDATE_AMOUNT = 50
argument :ids,
- [GraphQL::ID_TYPE],
+ [::Types::GlobalIDType[::Todo]],
required: true,
description: 'The global ids of the todos to restore (a maximum of 50 is supported at once)'
@@ -37,24 +37,18 @@ module Mutations
private
def gids_of(ids)
- ids.map { |id| ::URI::GID.build(app: GlobalID.app, model_name: Todo.name, model_id: id, params: nil).to_s }
+ ids.map { |id| Gitlab::GlobalId.as_global_id(id, model_name: Todo.name).to_s }
end
def model_ids_of(ids)
ids.map do |gid|
- parsed_gid = ::URI::GID.parse(gid)
- parsed_gid.model_id.to_i if accessible_todo?(parsed_gid)
+ # TODO: remove this line when the compatibility layer is removed
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
+ gid = ::Types::GlobalIDType[::Todo].coerce_isolated_input(gid)
+ gid.model_id.to_i
end.compact
end
- def accessible_todo?(gid)
- gid.app == GlobalID.app && todo?(gid)
- end
-
- def todo?(gid)
- GlobalID.parse(gid)&.model_class&.ancestors&.include?(Todo)
- end
-
def raise_too_many_todos_requested_error
raise Gitlab::Graphql::Errors::ArgumentError, 'Too many todos requested.'
end
diff --git a/app/views/projects/merge_requests/_merge_request.html.haml b/app/views/projects/merge_requests/_merge_request.html.haml
index ad0f4d03f9a..d55850b5673 100644
--- a/app/views/projects/merge_requests/_merge_request.html.haml
+++ b/app/views/projects/merge_requests/_merge_request.html.haml
@@ -55,6 +55,9 @@
- if merge_request.assignees.any?
%li.d-flex
= render 'shared/issuable/assignees', project: merge_request.project, issuable: merge_request
+ - if Feature.enabled?(:merge_request_reviewers, @project) && merge_request.reviewers.any?
+ %li.gl-display-flex.issuable-reviewers
+ = render 'shared/issuable/reviewers', project: merge_request.project, issuable: merge_request
= render 'projects/merge_requests/approvals_count', merge_request: merge_request
= render 'shared/issuable_meta_data', issuable: merge_request
diff --git a/app/views/search/_filter.html.haml b/app/views/search/_filter.html.haml
index bee4aff605f..e7febd4638b 100644
--- a/app/views/search/_filter.html.haml
+++ b/app/views/search/_filter.html.haml
@@ -2,15 +2,14 @@
= hidden_field_tag :group_id, params[:group_id]
- if params[:project_id].present?
= hidden_field_tag :project_id, params[:project_id]
-.dropdown.form-group.mb-lg-0.mx-lg-1
+.dropdown.form-group.mb-lg-0.mx-lg-1{ data: { testid: "group-filter" } }
%label.d-block{ for: "dashboard_search_group" }
= _("Group")
- %button.dropdown-menu-toggle.js-search-group-dropdown.mt-0{ type: "button", id: "dashboard_search_group", data: { toggle: "dropdown", group_id: params[:group_id] } }
- %span.dropdown-toggle-text
- - if @group.present?
- = @group.name
- - else
- = _("Any")
+ %button.dropdown-menu-toggle.gl-display-inline-flex.js-search-group-dropdown.gl-mt-0{ type: "button", id: "dashboard_search_group", data: { toggle: "dropdown", group_id: params[:group_id] } }
+ %span.dropdown-toggle-text.gl-flex-grow-1.str-truncated-100
+ = @group&.name || _("Any")
+ - if @group.present?
+ = link_to sprite_icon("clear"), url_for(safe_params.except(:project_id, :group_id)), class: 'search-clear js-search-clear has-tooltip', title: _('Clear')
= icon("chevron-down")
.dropdown-menu.dropdown-select.dropdown-menu-selectable.dropdown-menu-right
= dropdown_title(_("Filter results by group"))
@@ -21,12 +20,11 @@
.dropdown.project-filter.form-group.mb-lg-0.mx-lg-1
%label.d-block{ for: "dashboard_search_project" }
= _("Project")
- %button.dropdown-menu-toggle.js-search-project-dropdown.mt-0{ type: "button", id: "dashboard_search_project", data: { toggle: "dropdown"} }
- %span.dropdown-toggle-text
- - if @project.present?
- = @project.full_name
- - else
- = _("Any")
+ %button.dropdown-menu-toggle.gl-display-inline-flex.js-search-project-dropdown.gl-mt-0{ type: "button", id: "dashboard_search_project", data: { toggle: "dropdown", target: '.project-filter' } }
+ %span.dropdown-toggle-text.gl-flex-grow-1.str-truncated-100
+ = @project&.full_name || _("Any")
+ - if @project.present?
+ = link_to sprite_icon("clear"), url_for(safe_params.except(:project_id)), class: 'search-clear js-search-clear has-tooltip', title: _('Clear')
= icon("chevron-down")
.dropdown-menu.dropdown-select.dropdown-menu-selectable.dropdown-menu-right
= dropdown_title(_("Filter results by project"))
diff --git a/app/views/search/_form.html.haml b/app/views/search/_form.html.haml
index 30ca9d3f5ab..c8fa016662f 100644
--- a/app/views/search/_form.html.haml
+++ b/app/views/search/_form.html.haml
@@ -10,7 +10,7 @@
.position-relative
= search_field_tag :search, params[:search], placeholder: _("Search for projects, issues, etc."), class: "form-control search-text-input js-search-input", id: "dashboard_search", autofocus: true, spellcheck: false
= sprite_icon('search', css_class: 'search-icon')
- %button.search-clear.js-search-clear{ class: ("hidden" if !params[:search].present?), type: "button", tabindex: "-1" }
+ %button.search-clear.js-search-clear{ class: [("hidden" if params[:search].blank?), "has-tooltip"], type: "button", tabindex: "-1", title: _('Clear') }
= sprite_icon('clear')
%span.sr-only
= _("Clear search")
diff --git a/app/views/shared/issuable/_reviewers.html.haml b/app/views/shared/issuable/_reviewers.html.haml
new file mode 100644
index 00000000000..8e66135a20b
--- /dev/null
+++ b/app/views/shared/issuable/_reviewers.html.haml
@@ -0,0 +1,11 @@
+- max_render = 4
+- reviewers_rendering_overflow = issuable.reviewers.size > max_render
+- render_count = reviewers_rendering_overflow ? max_render - 1 : max_render
+- more_reviewers_count = issuable.reviewers.size - render_count
+
+- issuable.reviewers.take(render_count).each do |reviewer| # rubocop: disable CodeReuse/ActiveRecord
+ = link_to_member(@project, reviewer, name: false, title: _("Review requested from %{name}") % { name: reviewer.name})
+
+- if more_reviewers_count > 0
+ %span{ class: 'avatar-counter has-tooltip', data: { container: 'body', placement: 'bottom', 'line-type' => 'old' }, title: _("+%{more_reviewers_count} more reviewers") % { more_reviewers_count: more_reviewers_count} }
+ = _("+%{more_reviewers_count}") % { more_reviewers_count: more_reviewers_count}