diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-02-01 21:17:05 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-02-01 21:17:05 +0300 |
commit | 143a33345cf3607ad35ec31130cec4922bc1113c (patch) | |
tree | 33b0a2658928f06d4ab20f8ec7d3aeadfbdd08d9 /app | |
parent | 3bdc719293f08ed357ef452f3e2a11a9b29531e7 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
15 files changed, 100 insertions, 50 deletions
diff --git a/app/assets/javascripts/diffs/components/app.vue b/app/assets/javascripts/diffs/components/app.vue index 45f8676a1d2..a8ca17ab4dd 100644 --- a/app/assets/javascripts/diffs/components/app.vue +++ b/app/assets/javascripts/diffs/components/app.vue @@ -524,7 +524,7 @@ export default { if ( window.gon?.features?.diffsVirtualScrolling || - window.gon?.features?.diffSearchingUsageData + window.gon?.features?.usageDataDiffSearches ) { let keydownTime; Mousetrap.bind(['mod+f', 'mod+g'], () => { @@ -540,7 +540,7 @@ export default { if (delta >= 0 && delta < 1000) { this.disableVirtualScroller(); - if (window.gon?.features?.diffSearchingUsageData) { + if (window.gon?.features?.usageDataDiffSearches) { api.trackRedisHllUserEvent('i_code_review_user_searches_diff'); api.trackRedisCounterEvent('diff_searches'); } diff --git a/app/assets/javascripts/groups/components/transfer_group_form.vue b/app/assets/javascripts/groups/components/transfer_group_form.vue index ba8de2b0203..2d0d6b41c99 100644 --- a/app/assets/javascripts/groups/components/transfer_group_form.vue +++ b/app/assets/javascripts/groups/components/transfer_group_form.vue @@ -43,9 +43,6 @@ export default { }; }, computed: { - selectedNamespaceId() { - return this.selectedId; - }, disableSubmitButton() { return this.isPaidGroup || !this.selectedId; }, diff --git a/app/assets/javascripts/groups/init_transfer_group_form.js b/app/assets/javascripts/groups/init_transfer_group_form.js index c60255e6ec3..c9a1e46de72 100644 --- a/app/assets/javascripts/groups/init_transfer_group_form.js +++ b/app/assets/javascripts/groups/init_transfer_group_form.js @@ -4,6 +4,10 @@ import { parseBoolean } from '~/lib/utils/common_utils'; import TransferGroupForm, { i18n } from './components/transfer_group_form.vue'; const prepareGroups = (rawGroups) => { + if (!rawGroups) { + return { group: [] }; + } + const group = JSON.parse(rawGroups).map(({ id, text: humanName }) => ({ id, humanName, @@ -22,7 +26,7 @@ export default () => { targetFormId = null, buttonText: confirmButtonText = '', groupName = '', - parentGroups = [], + parentGroups, isPaidGroup, } = el.dataset; diff --git a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue index 6f61afe6e68..11de58aa344 100644 --- a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue +++ b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue @@ -578,7 +578,7 @@ export default { :endpoint="mr.accessibilityReportPath" /> - <div class="mr-widget-section"> + <div class="mr-widget-section" data-qa-selector="mr_widget_content"> <component :is="componentName" :mr="mr" :service="service" /> <ready-to-merge v-if="isRestructuredMrWidgetEnabled && mr.commitsCount" diff --git a/app/assets/javascripts/vue_shared/components/namespace_select/namespace_select.vue b/app/assets/javascripts/vue_shared/components/namespace_select/namespace_select.vue index 806212f0f2e..3d5baca5338 100644 --- a/app/assets/javascripts/vue_shared/components/namespace_select/namespace_select.vue +++ b/app/assets/javascripts/vue_shared/components/namespace_select/namespace_select.vue @@ -16,8 +16,13 @@ export const i18n = { USERS: __('Users'), }; -const filterByName = (data, searchTerm = '') => - data.filter((d) => d.humanName.toLowerCase().includes(searchTerm)); +const filterByName = (data, searchTerm = '') => { + if (!searchTerm) { + return data; + } + + return data.filter((d) => d.humanName.toLowerCase().includes(searchTerm.toLowerCase())); +}; export default { name: 'NamespaceSelect', @@ -85,7 +90,15 @@ export default { }, filteredEmptyNamespaceTitle() { const { includeEmptyNamespace, emptyNamespaceTitle, searchTerm } = this; - return includeEmptyNamespace && emptyNamespaceTitle.toLowerCase().includes(searchTerm); + + if (!includeEmptyNamespace) { + return ''; + } + if (!searchTerm) { + return emptyNamespaceTitle; + } + + return emptyNamespaceTitle.toLowerCase().includes(searchTerm.toLowerCase()); }, }, methods: { diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index bb951a54aeb..9007db05431 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -47,7 +47,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo # Usage data feature flags push_frontend_feature_flag(:users_expanding_widgets_usage_data, @project, default_enabled: :yaml) push_frontend_feature_flag(:diff_settings_usage_data, default_enabled: :yaml) - push_frontend_feature_flag(:diff_searching_usage_data, @project, default_enabled: :yaml) + push_frontend_feature_flag(:usage_data_diff_searches, @project, default_enabled: :yaml) end around_action :allow_gitaly_ref_name_caching, only: [:index, :show, :discussions] diff --git a/app/graphql/mutations/work_items/delete.rb b/app/graphql/mutations/work_items/delete.rb new file mode 100644 index 00000000000..6a3e651bdd5 --- /dev/null +++ b/app/graphql/mutations/work_items/delete.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +module Mutations + module WorkItems + class Delete < BaseMutation + description "Deletes a work item." \ + " Available only when feature flag `work_items` is enabled. The feature is experimental and is subject to change without notice." + + graphql_name 'WorkItemDelete' + + authorize :delete_work_item + + argument :id, ::Types::GlobalIDType[::WorkItem], + required: true, + description: 'Global ID of the work item.' + + field :project, Types::ProjectType, + null: true, + description: 'Project the deleted work item belonged to.' + + def resolve(id:) + work_item = authorized_find!(id: id) + + unless Feature.enabled?(:work_items, work_item.project) + return { errors: ['`work_items` feature flag disabled for this project'] } + end + + result = ::WorkItems::DeleteService.new( + project: work_item.project, + current_user: current_user + ).execute(work_item) + + { + project: result.success? ? work_item.project : nil, + errors: result.errors + } + end + + private + + def find_object(id:) + # TODO: Remove coercion when working on https://gitlab.com/gitlab-org/gitlab/-/issues/257883 + id = ::Types::GlobalIDType[::WorkItem].coerce_isolated_input(id) + GitlabSchema.find_by_gid(id) + end + end + end +end diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb index 021a023cb88..bcf64b79a85 100644 --- a/app/graphql/types/mutation_type.rb +++ b/app/graphql/types/mutation_type.rb @@ -126,6 +126,7 @@ module Types mount_mutation Mutations::Packages::DestroyFile mount_mutation Mutations::Echo mount_mutation Mutations::WorkItems::Create, feature_flag: :work_items + mount_mutation Mutations::WorkItems::Delete mount_mutation Mutations::WorkItems::Update end end diff --git a/app/policies/work_item_policy.rb b/app/policies/work_item_policy.rb index 9cacd495e6c..7ba5102a406 100644 --- a/app/policies/work_item_policy.rb +++ b/app/policies/work_item_policy.rb @@ -2,4 +2,11 @@ class WorkItemPolicy < BasePolicy delegate { @subject.project } + + desc 'User is author of the work item' + condition(:author) do + @user && @user == @subject.author + end + + rule { can?(:owner_access) | author }.enable :delete_work_item end diff --git a/app/services/projects/destroy_service.rb b/app/services/projects/destroy_service.rb index 5f777a74adb..733a4b45cb2 100644 --- a/app/services/projects/destroy_service.rb +++ b/app/services/projects/destroy_service.rb @@ -139,10 +139,7 @@ module Projects destroy_web_hooks! destroy_project_bots! destroy_ci_records! - - if ::Feature.enabled?(:extract_mr_diff_commit_deletions, default_enabled: :yaml) - destroy_mr_diff_commits! - end + destroy_mr_diff_commits! # Rails attempts to load all related records into memory before # destroying: https://github.com/rails/rails/issues/22510 diff --git a/app/services/work_items/delete_service.rb b/app/services/work_items/delete_service.rb new file mode 100644 index 00000000000..1093a403a1c --- /dev/null +++ b/app/services/work_items/delete_service.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module WorkItems + class DeleteService < Issuable::DestroyService + def execute(work_item) + unless current_user.can?(:delete_work_item, work_item) + return ::ServiceResponse.error(message: 'User not authorized to delete work item') + end + + if super + ::ServiceResponse.success + else + ::ServiceResponse.error(message: work_item.errors.full_messages) + end + end + end +end diff --git a/app/views/projects/_merge_request_merge_checks_settings.html.haml b/app/views/projects/_merge_request_merge_checks_settings.html.haml index b9ddb93c664..4f9af40f711 100644 --- a/app/views/projects/_merge_request_merge_checks_settings.html.haml +++ b/app/views/projects/_merge_request_merge_checks_settings.html.haml @@ -8,9 +8,7 @@ = form.label :only_allow_merge_if_pipeline_succeeds, class: 'form-check-label' do = s_('ProjectSettings|Pipelines must succeed') .text-secondary - - configuring_pipelines_for_merge_requests_help_link_url = help_page_path('ci/pipelines/merge_request_pipelines.md', anchor: 'prerequisites') - - configuring_pipelines_for_merge_requests_help_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: configuring_pipelines_for_merge_requests_help_link_url } - = s_('ProjectSettings|To enable this feature, configure pipelines. %{link_start}How to configure merge request pipelines?%{link_end}').html_safe % { link_start: configuring_pipelines_for_merge_requests_help_link_start, link_end: '</a>'.html_safe } + = s_("ProjectSettings|Merge requests can't be merged if the latest pipeline did not succeed or is still running.") .form-check.mb-2 .gl-pl-6 = form.check_box :allow_merge_on_skipped_pipeline, class: 'form-check-input' diff --git a/app/views/projects/notes/_actions.html.haml b/app/views/projects/notes/_actions.html.haml index d11b61466e2..31c14aaad50 100644 --- a/app/views/projects/notes/_actions.html.haml +++ b/app/views/projects/notes/_actions.html.haml @@ -6,36 +6,6 @@ - elsif note.contributor? %span{ class: 'note-role user-access-role has-tooltip', title: _("This user has previously committed to the %{name} project.") % { name: note.project_name } }= _("Contributor") -- if note.resolvable? - - can_resolve = can?(current_user, :resolve_note, note) - %resolve-btn{ "project-path" => project_path(note.project), - "discussion-id" => note.discussion_id(@noteable), - ":note-id" => note.id, - ":resolved" => note.resolved?, - ":can-resolve" => can_resolve, - ":author-name" => "'#{j(note.author.name)}'", - "author-avatar" => note.author.avatar_url, - ":note-truncated" => "'#{j(truncate(note.note, length: 17))}'", - ":resolved-by" => "'#{j(note.resolved_by.try(:name))}'", - "v-show" => "#{can_resolve || note.resolved?}", - "inline-template" => true, - "ref" => "note_#{note.id}" } - - .note-actions-item - %button.note-action-button.line-resolve-btn{ type: "button", - class: ("is-disabled" unless can_resolve), - ":class" => "{ 'is-active': isResolved }", - ":aria-label" => "buttonText", - "@click" => "resolve", - ":title" => "buttonText", - ":ref" => "'button'" } - - %div - %template{ 'v-if' => 'isResolved' } - = render 'shared/icons/icon_status_success_solid.svg' - %template{ 'v-else' => '' } - = render 'shared/icons/icon_resolve_discussion.svg' - - if can?(current_user, :award_emoji, note) - if note.emoji_awardable? .note-actions-item diff --git a/app/views/shared/icons/_icon_resolve_discussion.svg b/app/views/shared/icons/_icon_resolve_discussion.svg deleted file mode 100644 index 845562e9320..00000000000 --- a/app/views/shared/icons/_icon_resolve_discussion.svg +++ /dev/null @@ -1 +0,0 @@ -<svg width="14" height="14" viewBox="0 0 14 14" xmlns="http://www.w3.org/2000/svg"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill-rule="evenodd"/><path d="M6.278 7.697L5.045 6.464a.296.296 0 0 0-.42-.002l-.613.614a.298.298 0 0 0 .002.42l1.91 1.909a.5.5 0 0 0 .703.005l.265-.265L9.997 6.04a.291.291 0 0 0-.009-.408l-.614-.614a.29.29 0 0 0-.408-.009L6.278 7.697z"/></svg> diff --git a/app/views/shared/icons/_icon_status_success_solid.svg b/app/views/shared/icons/_icon_status_success_solid.svg deleted file mode 100644 index 0aac6d933e1..00000000000 --- a/app/views/shared/icons/_icon_status_success_solid.svg +++ /dev/null @@ -1 +0,0 @@ -<svg width="14" height="14" viewBox="0 0 14 14" xmlns="http://www.w3.org/2000/svg"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z M6.278 7.697L5.045 6.464a.296.296 0 0 0-.42-.002l-.613.614a.298.298 0 0 0 .002.42l1.91 1.909a.5.5 0 0 0 .703.005l.265-.265L9.997 6.04a.291.291 0 0 0-.009-.408l-.614-.614a.29.29 0 0 0-.408-.009L6.278 7.697z" fill-rule="evenodd"/></svg> |