diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-03-18 18:07:23 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-03-18 18:07:23 +0300 |
commit | 0b878def9bad1c36ea2b23380a77f9eedaaa6b83 (patch) | |
tree | eb44c34bf05b2dbb1371d8553a7bb7b3d8a1989d /app | |
parent | bdb1e64a7d620c203e5228717b7c464554b85f55 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
21 files changed, 165 insertions, 52 deletions
diff --git a/app/assets/javascripts/issues/list/components/issues_list_app.vue b/app/assets/javascripts/issues/list/components/issues_list_app.vue index a532fa5b771..5caac3402c2 100644 --- a/app/assets/javascripts/issues/list/components/issues_list_app.vue +++ b/app/assets/javascripts/issues/list/components/issues_list_app.vue @@ -260,6 +260,9 @@ export default { showCsvButtons() { return this.isProject && this.isSignedIn; }, + showIssuableByEmail() { + return this.initialEmail && this.isSignedIn; + }, showNewIssueDropdown() { return !this.isProject && this.hasAnyProjects; }, @@ -624,8 +627,9 @@ export default { </script> <template> - <div v-if="hasAnyIssues"> + <div> <issuable-list + v-if="hasAnyIssues" :namespace="fullPath" recent-searches-storage-key="issues" :search-input-placeholder="$options.i18n.searchPlaceholder" @@ -768,50 +772,50 @@ export default { </template> </issuable-list> - <issuable-by-email v-if="initialEmail" class="gl-text-center gl-pt-5 gl-pb-7" /> - </div> + <template v-else-if="isSignedIn"> + <gl-empty-state + :description="$options.i18n.noIssuesSignedInDescription" + :title="$options.i18n.noIssuesSignedInTitle" + :svg-path="emptyStateSvgPath" + > + <template #actions> + <gl-button v-if="showNewIssueLink" :href="newIssuePath" variant="confirm"> + {{ $options.i18n.newIssueLabel }} + </gl-button> + <csv-import-export-buttons + v-if="showCsvButtons" + class="gl-mr-3" + :export-csv-path="exportCsvPathWithQuery" + :issuable-count="currentTabCount" + /> + <new-issue-dropdown v-if="showNewIssueDropdown" /> + </template> + </gl-empty-state> + <hr /> + <p class="gl-text-center gl-font-weight-bold gl-mb-0"> + {{ $options.i18n.jiraIntegrationTitle }} + </p> + <p class="gl-text-center gl-mb-0"> + <gl-sprintf :message="$options.i18n.jiraIntegrationMessage"> + <template #jiraDocsLink="{ content }"> + <gl-link :href="jiraIntegrationPath">{{ content }}</gl-link> + </template> + </gl-sprintf> + </p> + <p class="gl-text-center gl-text-gray-500"> + {{ $options.i18n.jiraIntegrationSecondaryMessage }} + </p> + </template> - <div v-else-if="isSignedIn"> <gl-empty-state - :description="$options.i18n.noIssuesSignedInDescription" - :title="$options.i18n.noIssuesSignedInTitle" + v-else + :description="$options.i18n.noIssuesSignedOutDescription" + :title="$options.i18n.noIssuesSignedOutTitle" :svg-path="emptyStateSvgPath" - > - <template #actions> - <gl-button v-if="showNewIssueLink" :href="newIssuePath" variant="confirm"> - {{ $options.i18n.newIssueLabel }} - </gl-button> - <csv-import-export-buttons - v-if="showCsvButtons" - class="gl-mr-3" - :export-csv-path="exportCsvPathWithQuery" - :issuable-count="currentTabCount" - /> - <new-issue-dropdown v-if="showNewIssueDropdown" /> - </template> - </gl-empty-state> - <hr /> - <p class="gl-text-center gl-font-weight-bold gl-mb-0"> - {{ $options.i18n.jiraIntegrationTitle }} - </p> - <p class="gl-text-center gl-mb-0"> - <gl-sprintf :message="$options.i18n.jiraIntegrationMessage"> - <template #jiraDocsLink="{ content }"> - <gl-link :href="jiraIntegrationPath">{{ content }}</gl-link> - </template> - </gl-sprintf> - </p> - <p class="gl-text-center gl-text-gray-500"> - {{ $options.i18n.jiraIntegrationSecondaryMessage }} - </p> - </div> + :primary-button-text="$options.i18n.noIssuesSignedOutButtonText" + :primary-button-link="signInPath" + /> - <gl-empty-state - v-else - :description="$options.i18n.noIssuesSignedOutDescription" - :title="$options.i18n.noIssuesSignedOutTitle" - :svg-path="emptyStateSvgPath" - :primary-button-text="$options.i18n.noIssuesSignedOutButtonText" - :primary-button-link="signInPath" - /> + <issuable-by-email v-if="showIssuableByEmail" class="gl-text-center gl-pt-5 gl-pb-7" /> + </div> </template> diff --git a/app/assets/javascripts/issues/show/components/incidents/incident_tabs.vue b/app/assets/javascripts/issues/show/components/incidents/incident_tabs.vue index 04ddc7f3501..27cd1eadd53 100644 --- a/app/assets/javascripts/issues/show/components/incidents/incident_tabs.vue +++ b/app/assets/javascripts/issues/show/components/incidents/incident_tabs.vue @@ -52,7 +52,7 @@ export default { return this.$apollo.queries.alert.loading; }, incidentTabEnabled() { - return this.glFeatures.incidentTimelineEvents && this.glFeatures.incidentTimelineEventTab; + return this.glFeatures.incidentTimelineEvents && this.glFeatures.incidentTimeline; }, }, mounted() { diff --git a/app/assets/stylesheets/pages/settings.scss b/app/assets/stylesheets/pages/settings.scss index 5956368a977..0c7b74684cc 100644 --- a/app/assets/stylesheets/pages/settings.scss +++ b/app/assets/stylesheets/pages/settings.scss @@ -110,9 +110,14 @@ .bs-callout, .form-check:first-child, - .form-text.text-muted { + .form-check .form-text.text-muted, + .form-check + .form-text.text-muted { margin-top: 0; } + + .form-check .form-text.text-muted { + margin-bottom: $grid-size; + } } .settings-list-icon { diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index b53d9b1be04..2966adc0f23 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -218,6 +218,8 @@ class GroupsController < Groups::ApplicationController @has_projects = group_projects.exists? + set_sort_order + respond_to do |format| format.html end diff --git a/app/controllers/projects/incidents_controller.rb b/app/controllers/projects/incidents_controller.rb index 293581a6744..0c2f871a1f0 100644 --- a/app/controllers/projects/incidents_controller.rb +++ b/app/controllers/projects/incidents_controller.rb @@ -8,7 +8,7 @@ class Projects::IncidentsController < Projects::ApplicationController before_action :load_incident, only: [:show] before_action do push_frontend_feature_flag(:incident_escalations, @project) - push_frontend_feature_flag(:incident_timeline_event_tab, @project, default_enabled: :yaml) + push_frontend_feature_flag(:incident_timeline, @project, default_enabled: :yaml) push_licensed_feature(:incident_timeline_events) if @project.licensed_feature_available?(:incident_timeline_events) end diff --git a/app/graphql/mutations/saved_replies/base.rb b/app/graphql/mutations/saved_replies/base.rb index 468263b0f9d..59871df687f 100644 --- a/app/graphql/mutations/saved_replies/base.rb +++ b/app/graphql/mutations/saved_replies/base.rb @@ -5,7 +5,7 @@ module Mutations class Base < BaseMutation field :saved_reply, Types::SavedReplyType, null: true, - description: 'Updated saved reply.' + description: 'Saved reply after mutation.' private diff --git a/app/graphql/mutations/saved_replies/destroy.rb b/app/graphql/mutations/saved_replies/destroy.rb new file mode 100644 index 00000000000..7cd0f21ad45 --- /dev/null +++ b/app/graphql/mutations/saved_replies/destroy.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module Mutations + module SavedReplies + class Destroy < Base + graphql_name 'SavedReplyDestroy' + + authorize :destroy_saved_replies + + argument :id, Types::GlobalIDType[::Users::SavedReply], + required: true, + description: copy_field_description(Types::SavedReplyType, :id) + + def resolve(id:) + raise Gitlab::Graphql::Errors::ResourceNotAvailable, 'Feature disabled' unless feature_enabled? + + saved_reply = authorized_find!(id) + result = ::Users::SavedReplies::DestroyService.new(saved_reply: saved_reply).execute + present_result(result) + end + end + end +end diff --git a/app/graphql/mutations/saved_replies/update.rb b/app/graphql/mutations/saved_replies/update.rb index bacc6ceb39e..d9368de7547 100644 --- a/app/graphql/mutations/saved_replies/update.rb +++ b/app/graphql/mutations/saved_replies/update.rb @@ -23,7 +23,7 @@ module Mutations raise Gitlab::Graphql::Errors::ResourceNotAvailable, 'Feature disabled' unless feature_enabled? saved_reply = authorized_find!(id) - result = ::Users::SavedReplies::UpdateService.new(current_user: current_user, saved_reply: saved_reply, name: name, content: content).execute + result = ::Users::SavedReplies::UpdateService.new(saved_reply: saved_reply, name: name, content: content).execute present_result(result) end end diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb index e6072820eea..2297912ac35 100644 --- a/app/graphql/types/mutation_type.rb +++ b/app/graphql/types/mutation_type.rb @@ -131,6 +131,7 @@ module Types mount_mutation Mutations::WorkItems::Update mount_mutation Mutations::SavedReplies::Create mount_mutation Mutations::SavedReplies::Update + mount_mutation Mutations::SavedReplies::Destroy end end diff --git a/app/helpers/emails_helper.rb b/app/helpers/emails_helper.rb index b804efb9561..79b04ae0e2b 100644 --- a/app/helpers/emails_helper.rb +++ b/app/helpers/emails_helper.rb @@ -206,6 +206,23 @@ module EmailsHelper end end + def new_email_address_added_text(email) + _('A new email address has been added to your GitLab account: %{email}') % { email: email } + end + + def remove_email_address_text(format: nil) + url = profile_emails_url + + case format + when :html + settings_link_to = generate_link(_('email address settings'), url).html_safe + _("If you want to remove this email address, visit the %{settings_link_to} page.").html_safe % { settings_link_to: settings_link_to } + else + _('If you want to remove this email address, visit %{profile_link}') % + { profile_link: url } + end + end + def admin_changed_password_text(format: nil) url = Gitlab.config.gitlab.url diff --git a/app/mailers/emails/profile.rb b/app/mailers/emails/profile.rb index 28e51ba311b..31fcc7c15cb 100644 --- a/app/mailers/emails/profile.rb +++ b/app/mailers/emails/profile.rb @@ -141,6 +141,17 @@ module Emails end end + def new_email_address_added_email(user, email) + return unless user + + @user = user + @email = email + + Gitlab::I18n.with_locale(@user.preferred_language) do + mail(to: @user.notification_email_or_default, subject: subject(_("New email address added"))) + end + end + private def profile_email_with_layout(to:, subject:, layout: 'mailer') diff --git a/app/mailers/previews/notify_preview.rb b/app/mailers/previews/notify_preview.rb index 8e30eeee73f..e7c8964a733 100644 --- a/app/mailers/previews/notify_preview.rb +++ b/app/mailers/previews/notify_preview.rb @@ -181,6 +181,10 @@ class NotifyPreview < ActionMailer::Preview Notify.unknown_sign_in_email(user, '127.0.0.1', Time.current).message end + def new_email_address_added_email + Notify.new_email_address_added_email(user, 'someone@gitlab.com').message + end + def service_desk_new_note_email cleanup do note = create_note(noteable_type: 'Issue', noteable_id: issue.id, note: 'Issue note content') diff --git a/app/policies/user_policy.rb b/app/policies/user_policy.rb index de99cbffb6f..f62ccef826c 100644 --- a/app/policies/user_policy.rb +++ b/app/policies/user_policy.rb @@ -25,6 +25,7 @@ class UserPolicy < BasePolicy enable :update_user_status enable :create_saved_replies enable :update_saved_replies + enable :destroy_saved_replies enable :read_user_personal_access_tokens enable :read_group_count enable :read_user_groups diff --git a/app/services/concerns/members/bulk_create_users.rb b/app/services/concerns/members/bulk_create_users.rb index 3f8971dde74..3c57301cafc 100644 --- a/app/services/concerns/members/bulk_create_users.rb +++ b/app/services/concerns/members/bulk_create_users.rb @@ -53,7 +53,7 @@ module Members if users.present? # helps not have to perform another query per user id to see if the member exists later on when fetching - existing_members = source.members_and_requesters.where(user_id: users).index_by(&:user_id) # rubocop:disable CodeReuse/ActiveRecord + existing_members = source.members_and_requesters.with_user(users).index_by(&:user_id) end [emails, users, existing_members] diff --git a/app/services/emails/base_service.rb b/app/services/emails/base_service.rb index 58fc9799673..6f2b1018a6a 100644 --- a/app/services/emails/base_service.rb +++ b/app/services/emails/base_service.rb @@ -9,6 +9,10 @@ module Emails @params = params.dup @user = params.delete(:user) end + + def notification_service + NotificationService.new + end end end diff --git a/app/services/emails/create_service.rb b/app/services/emails/create_service.rb index 011978ba76a..d2d8b69559a 100644 --- a/app/services/emails/create_service.rb +++ b/app/services/emails/create_service.rb @@ -7,6 +7,7 @@ module Emails user.emails.create(params.merge(extra_params)).tap do |email| email&.confirm if skip_confirmation && current_user.admin? + notification_service.new_email_address_added(user, email.email) if email.persisted? && !email.user_primary_email? end end end diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb index aa7e636b8a4..aecf7cf99b9 100644 --- a/app/services/notification_service.rb +++ b/app/services/notification_service.rb @@ -109,6 +109,13 @@ class NotificationService mailer.unknown_sign_in_email(user, ip, time).deliver_later end + # Notify a user when a new email address is added to the their account + def new_email_address_added(user, email) + return unless user.can?(:receive_notifications) + + mailer.new_email_address_added_email(user, email).deliver_later + end + # When create an issue we should send an email to: # # * issue assignee if their notification level is not Disabled diff --git a/app/services/users/saved_replies/destroy_service.rb b/app/services/users/saved_replies/destroy_service.rb new file mode 100644 index 00000000000..ac08cddad0c --- /dev/null +++ b/app/services/users/saved_replies/destroy_service.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module Users + module SavedReplies + class DestroyService + def initialize(saved_reply:) + @saved_reply = saved_reply + end + + def execute + if saved_reply.destroy + ServiceResponse.success(payload: { saved_reply: saved_reply }) + else + ServiceResponse.error(message: saved_reply.errors.full_messages) + end + end + + private + + attr_reader :saved_reply + end + end +end diff --git a/app/services/users/saved_replies/update_service.rb b/app/services/users/saved_replies/update_service.rb index ab0a3eaf87d..80d3da8a0a3 100644 --- a/app/services/users/saved_replies/update_service.rb +++ b/app/services/users/saved_replies/update_service.rb @@ -3,8 +3,7 @@ module Users module SavedReplies class UpdateService - def initialize(current_user:, saved_reply:, name:, content:) - @current_user = current_user + def initialize(saved_reply:, name:, content:) @saved_reply = saved_reply @name = name @content = content @@ -20,7 +19,7 @@ module Users private - attr_reader :current_user, :saved_reply, :name, :content + attr_reader :saved_reply, :name, :content end end end diff --git a/app/views/notify/new_email_address_added_email.erb b/app/views/notify/new_email_address_added_email.erb new file mode 100644 index 00000000000..3af1953c902 --- /dev/null +++ b/app/views/notify/new_email_address_added_email.erb @@ -0,0 +1,5 @@ +<%= say_hi(@user) %> + +<%= new_email_address_added_text(@email) %> + +<%= remove_email_address_text %> diff --git a/app/views/notify/new_email_address_added_email.haml b/app/views/notify/new_email_address_added_email.haml new file mode 100644 index 00000000000..6d00aaedfd5 --- /dev/null +++ b/app/views/notify/new_email_address_added_email.haml @@ -0,0 +1,6 @@ +%p + = say_hi(@user) +%p + = new_email_address_added_text(@email) +%p + = remove_email_address_text(format: :html) |