diff options
Diffstat (limited to 'app')
22 files changed, 171 insertions, 107 deletions
diff --git a/app/assets/javascripts/notes/components/discussion_actions.vue b/app/assets/javascripts/notes/components/discussion_actions.vue index 8ab31ef3448..251199f1778 100644 --- a/app/assets/javascripts/notes/components/discussion_actions.vue +++ b/app/assets/javascripts/notes/components/discussion_actions.vue @@ -73,7 +73,7 @@ export default { v-if="discussion.resolvable && shouldShowJumpToNextDiscussion" class="btn-group discussion-actions ml-sm-2" > - <jump-to-next-discussion-button /> + <jump-to-next-discussion-button :from-discussion-id="discussion.id" /> </div> </div> </template> diff --git a/app/assets/javascripts/notes/components/discussion_counter.vue b/app/assets/javascripts/notes/components/discussion_counter.vue index 70e22db364b..515d513e3ee 100644 --- a/app/assets/javascripts/notes/components/discussion_counter.vue +++ b/app/assets/javascripts/notes/components/discussion_counter.vue @@ -39,7 +39,11 @@ export default { </script> <template> - <div v-if="resolvableDiscussionsCount > 0" class="line-resolve-all-container full-width-mobile"> + <div + v-if="resolvableDiscussionsCount > 0" + ref="discussionCounter" + class="line-resolve-all-container full-width-mobile" + > <div class="full-width-mobile d-flex d-sm-block"> <div :class="{ 'has-next-btn': hasNextButton }" class="line-resolve-all"> <span diff --git a/app/assets/javascripts/notes/components/discussion_jump_to_next_button.vue b/app/assets/javascripts/notes/components/discussion_jump_to_next_button.vue index 630d4fd89b1..e66abcfddbb 100644 --- a/app/assets/javascripts/notes/components/discussion_jump_to_next_button.vue +++ b/app/assets/javascripts/notes/components/discussion_jump_to_next_button.vue @@ -12,6 +12,12 @@ export default { GlTooltip: GlTooltipDirective, }, mixins: [discussionNavigation], + props: { + fromDiscussionId: { + type: String, + required: true, + }, + }, }; </script> @@ -22,7 +28,7 @@ export default { v-gl-tooltip class="btn btn-default discussion-next-btn" :title="s__('MergeRequests|Jump to next unresolved thread')" - @click="jumpToNextDiscussion" + @click="jumpToNextRelativeDiscussion(fromDiscussionId)" > <icon name="comment-next" /> </button> diff --git a/app/assets/javascripts/notes/mixins/discussion_navigation.js b/app/assets/javascripts/notes/mixins/discussion_navigation.js index e5066695403..08c7efd69a6 100644 --- a/app/assets/javascripts/notes/mixins/discussion_navigation.js +++ b/app/assets/javascripts/notes/mixins/discussion_navigation.js @@ -2,6 +2,86 @@ import { mapGetters, mapActions, mapState } from 'vuex'; import { scrollToElement } from '~/lib/utils/common_utils'; import eventHub from '../../notes/event_hub'; +/** + * @param {string} selector + * @returns {boolean} + */ +function scrollTo(selector) { + const el = document.querySelector(selector); + + if (el) { + scrollToElement(el); + return true; + } + + return false; +} + +/** + * @param {object} self Component instance with mixin applied + * @param {string} id Discussion id we are jumping to + */ +function diffsJump({ expandDiscussion }, id) { + const selector = `ul.notes[data-discussion-id="${id}"]`; + eventHub.$once('scrollToDiscussion', () => scrollTo(selector)); + expandDiscussion({ discussionId: id }); +} + +/** + * @param {object} self Component instance with mixin applied + * @param {string} id Discussion id we are jumping to + * @returns {boolean} + */ +function discussionJump({ expandDiscussion }, id) { + const selector = `div.discussion[data-discussion-id="${id}"]`; + expandDiscussion({ discussionId: id }); + return scrollTo(selector); +} + +/** + * @param {object} self Component instance with mixin applied + * @param {string} id Discussion id we are jumping to + */ +function switchToDiscussionsTabAndJumpTo(self, id) { + window.mrTabs.eventHub.$once('MergeRequestTabChange', () => { + setTimeout(() => discussionJump(self, id), 0); + }); + + window.mrTabs.tabShown('show'); +} + +/** + * @param {object} self Component instance with mixin applied + * @param {object} discussion Discussion we are jumping to + */ +function jumpToDiscussion(self, discussion) { + const { id, diff_discussion: isDiffDiscussion } = discussion; + if (id) { + const activeTab = window.mrTabs.currentAction; + + if (activeTab === 'diffs' && isDiffDiscussion) { + diffsJump(self, id); + } else if (activeTab === 'show') { + discussionJump(self, id); + } else { + switchToDiscussionsTabAndJumpTo(self, id); + } + } +} + +/** + * @param {object} self Component instance with mixin applied + * @param {function} fn Which function used to get the target discussion's id + * @param {string} [discussionId=this.currentDiscussionId] Current discussion id, will be null if discussions have not been traversed yet + */ +function handleDiscussionJump(self, fn, discussionId = self.currentDiscussionId) { + const isDiffView = window.mrTabs.currentAction === 'diffs'; + const targetId = fn(discussionId, isDiffView); + const discussion = self.getDiscussion(targetId); + jumpToDiscussion(self, discussion); + self.setCurrentDiscussionId(targetId); +} + export default { computed: { ...mapGetters([ @@ -16,76 +96,20 @@ export default { methods: { ...mapActions(['expandDiscussion', 'setCurrentDiscussionId']), - diffsJump(id) { - const selector = `ul.notes[data-discussion-id="${id}"]`; - - eventHub.$once('scrollToDiscussion', () => { - const el = document.querySelector(selector); - - if (el) { - scrollToElement(el); - - return true; - } - - return false; - }); - - this.expandDiscussion({ discussionId: id }); - }, - discussionJump(id) { - const selector = `div.discussion[data-discussion-id="${id}"]`; - - const el = document.querySelector(selector); - - this.expandDiscussion({ discussionId: id }); - - if (el) { - scrollToElement(el); - - return true; - } - - return false; - }, - - switchToDiscussionsTabAndJumpTo(id) { - window.mrTabs.eventHub.$once('MergeRequestTabChange', () => { - setTimeout(() => this.discussionJump(id), 0); - }); - - window.mrTabs.tabShown('show'); - }, - - jumpToDiscussion(discussion) { - const { id, diff_discussion: isDiffDiscussion } = discussion; - if (id) { - const activeTab = window.mrTabs.currentAction; - - if (activeTab === 'diffs' && isDiffDiscussion) { - this.diffsJump(id); - } else if (activeTab === 'show') { - this.discussionJump(id); - } else { - this.switchToDiscussionsTabAndJumpTo(id); - } - } - }, - jumpToNextDiscussion() { - this.handleDiscussionJump(this.nextUnresolvedDiscussionId); + handleDiscussionJump(this, this.nextUnresolvedDiscussionId); }, jumpToPreviousDiscussion() { - this.handleDiscussionJump(this.previousUnresolvedDiscussionId); + handleDiscussionJump(this, this.previousUnresolvedDiscussionId); }, - handleDiscussionJump(fn) { - const isDiffView = window.mrTabs.currentAction === 'diffs'; - const targetId = fn(this.currentDiscussionId, isDiffView); - const discussion = this.getDiscussion(targetId); - this.jumpToDiscussion(discussion); - this.setCurrentDiscussionId(targetId); + /** + * Go to the next discussion from the given discussionId + * @param {String} discussionId The id we are jumping from + */ + jumpToNextRelativeDiscussion(discussionId) { + handleDiscussionJump(this, this.nextUnresolvedDiscussionId, discussionId); }, }, }; diff --git a/app/assets/javascripts/registry/explorer/pages/details.vue b/app/assets/javascripts/registry/explorer/pages/details.vue index bc613db8672..bfb9b0f4688 100644 --- a/app/assets/javascripts/registry/explorer/pages/details.vue +++ b/app/assets/javascripts/registry/explorer/pages/details.vue @@ -199,10 +199,7 @@ export default { </script> <template> - <div - v-gl-resize-observer="handleResize" - class="my-3 position-absolute w-100 slide-enter-to-element" - > + <div v-gl-resize-observer="handleResize" class="my-3 w-100 slide-enter-to-element"> <div class="d-flex my-3 align-items-center"> <h4> <gl-sprintf :message="s__('ContainerRegistry|%{imageName} tags')"> diff --git a/app/assets/javascripts/registry/explorer/pages/index.vue b/app/assets/javascripts/registry/explorer/pages/index.vue index deefbfc40e0..19ae3bee640 100644 --- a/app/assets/javascripts/registry/explorer/pages/index.vue +++ b/app/assets/javascripts/registry/explorer/pages/index.vue @@ -3,7 +3,7 @@ export default {}; </script> <template> - <div class="position-relative"> + <div> <transition name="slide"> <router-view /> </transition> diff --git a/app/assets/javascripts/registry/explorer/pages/list.vue b/app/assets/javascripts/registry/explorer/pages/list.vue index 1dbc7cc2242..5f8f4d8df1e 100644 --- a/app/assets/javascripts/registry/explorer/pages/list.vue +++ b/app/assets/javascripts/registry/explorer/pages/list.vue @@ -78,7 +78,7 @@ export default { </script> <template> - <div class="position-absolute w-100 slide-enter-from-element"> + <div class="w-100 slide-enter-from-element"> <gl-empty-state v-if="config.characterError" :title="s__('ContainerRegistry|Docker connection error')" diff --git a/app/assets/stylesheets/framework/vue_transitions.scss b/app/assets/stylesheets/framework/vue_transitions.scss index a082cd25abe..1a536b97142 100644 --- a/app/assets/stylesheets/framework/vue_transitions.scss +++ b/app/assets/stylesheets/framework/vue_transitions.scss @@ -15,6 +15,7 @@ .slide-enter-from-element { &.slide-enter, &.slide-leave-to { + position: absolute; transform: translateX(-150%); } } @@ -22,6 +23,7 @@ .slide-enter-to-element { &.slide-enter, &.slide-leave-to { + position: absolute; transform: translateX(150%); } } diff --git a/app/controllers/explore/snippets_controller.rb b/app/controllers/explore/snippets_controller.rb index 61068df77d1..3a56a48e578 100644 --- a/app/controllers/explore/snippets_controller.rb +++ b/app/controllers/explore/snippets_controller.rb @@ -1,17 +1,15 @@ # frozen_string_literal: true class Explore::SnippetsController < Explore::ApplicationController - include PaginatedCollection include Gitlab::NoteableMetadata def index @snippets = SnippetsFinder.new(current_user, explore: true) .execute .page(params[:page]) + .without_count .inc_author - return if redirect_out_of_range(@snippets) - @noteable_meta_data = noteable_meta_data(@snippets, 'Snippet') end end diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index d61f0bbfb10..f79a5682963 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -531,6 +531,7 @@ module Ci .concat(persisted_variables) .concat(scoped_variables) .concat(job_variables) + .concat(environment_changed_page_variables) .concat(persisted_environment_variables) .to_runner_variables end @@ -569,6 +570,15 @@ module Ci end end + def environment_changed_page_variables + Gitlab::Ci::Variables::Collection.new.tap do |variables| + break variables unless environment_status + + variables.append(key: 'CI_MERGE_REQUEST_CHANGED_PAGE_PATHS', value: environment_status.changed_paths.join(',')) + variables.append(key: 'CI_MERGE_REQUEST_CHANGED_PAGE_URLS', value: environment_status.changed_urls.join(',')) + end + end + def deploy_token_variables Gitlab::Ci::Variables::Collection.new.tap do |variables| break variables unless gitlab_deploy_token @@ -970,6 +980,14 @@ module Ci options&.dig(:environment, :url) || persisted_environment&.external_url end + def environment_status + strong_memoize(:environment_status) do + if has_environment? && merge_request + EnvironmentStatus.new(project, persisted_environment, merge_request, pipeline.sha) + end + end + end + # The format of the retry option changed in GitLab 11.5: Before it was # integer only, after it is a hash. New builds are created with the new # format, but builds created before GitLab 11.5 and saved in database still diff --git a/app/models/environment_status.rb b/app/models/environment_status.rb index 5fdb5af2d9b..46e41c22139 100644 --- a/app/models/environment_status.rb +++ b/app/models/environment_status.rb @@ -62,9 +62,9 @@ class EnvironmentStatus end def changes - return [] unless has_route_map? - - changed_files.map { |file| build_change(file) }.compact + strong_memoize(:changes) do + has_route_map? ? changed_files.map { |file| build_change(file) }.compact : [] + end end def changed_files @@ -72,6 +72,14 @@ class EnvironmentStatus .merge_request_diff_files.where(deleted_file: false) end + def changed_paths + changes.map { |change| change[:path] } + end + + def changed_urls + changes.map { |change| change[:external_url] } + end + def has_route_map? project.route_map_for(sha).present? end diff --git a/app/models/pages_domain.rb b/app/models/pages_domain.rb index 814c970f745..37d45c5934d 100644 --- a/app/models/pages_domain.rb +++ b/app/models/pages_domain.rb @@ -68,6 +68,10 @@ class PagesDomain < ApplicationRecord scope :instance_serverless, -> { where(wildcard: true, scope: :instance, usage: :serverless) } + def self.find_by_domain_case_insensitive(domain) + find_by("LOWER(domain) = LOWER(?)", domain) + end + def verified? !!verified_at end diff --git a/app/models/project_services/chat_message/base_message.rb b/app/models/project_services/chat_message/base_message.rb index 49151ad24cb..bdd77a919e3 100644 --- a/app/models/project_services/chat_message/base_message.rb +++ b/app/models/project_services/chat_message/base_message.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'slack-notifier' - module ChatMessage class BaseMessage RELATIVE_LINK_REGEX = /!\[[^\]]*\]\((\/uploads\/[^\)]*)\)/.freeze @@ -59,7 +57,7 @@ module ChatMessage end def format(string) - Slack::Notifier::LinkFormatter.format(format_relative_links(string)) + Slack::Messenger::Util::LinkFormatter.format(format_relative_links(string)) end def format_relative_links(string) diff --git a/app/models/project_services/chat_message/pipeline_message.rb b/app/models/project_services/chat_message/pipeline_message.rb index 46fe894cfc3..52a26f6211a 100644 --- a/app/models/project_services/chat_message/pipeline_message.rb +++ b/app/models/project_services/chat_message/pipeline_message.rb @@ -1,5 +1,4 @@ # frozen_string_literal: true -require 'slack-notifier' module ChatMessage class PipelineMessage < BaseMessage @@ -98,7 +97,7 @@ module ChatMessage def failed_stages_field { title: s_("ChatMessage|Failed stage").pluralize(failed_stages.length), - value: Slack::Notifier::LinkFormatter.format(failed_stages_links), + value: Slack::Messenger::Util::LinkFormatter.format(failed_stages_links), short: true } end @@ -106,7 +105,7 @@ module ChatMessage def failed_jobs_field { title: s_("ChatMessage|Failed job").pluralize(failed_jobs.length), - value: Slack::Notifier::LinkFormatter.format(failed_jobs_links), + value: Slack::Messenger::Util::LinkFormatter.format(failed_jobs_links), short: true } end @@ -123,12 +122,12 @@ module ChatMessage fields = [ { title: ref_type == "tag" ? s_("ChatMessage|Tag") : s_("ChatMessage|Branch"), - value: Slack::Notifier::LinkFormatter.format(ref_link), + value: Slack::Messenger::Util::LinkFormatter.format(ref_link), short: true }, { title: s_("ChatMessage|Commit"), - value: Slack::Notifier::LinkFormatter.format(commit_link), + value: Slack::Messenger::Util::LinkFormatter.format(commit_link), short: true } ] diff --git a/app/models/project_services/chat_message/push_message.rb b/app/models/project_services/chat_message/push_message.rb index 41b0cbb2c4d..c8e70a69c88 100644 --- a/app/models/project_services/chat_message/push_message.rb +++ b/app/models/project_services/chat_message/push_message.rb @@ -48,7 +48,7 @@ module ChatMessage end def format(string) - Slack::Notifier::LinkFormatter.format(string) + Slack::Messenger::Util::LinkFormatter.format(string) end def commit_messages diff --git a/app/models/project_services/chat_notification_service.rb b/app/models/project_services/chat_notification_service.rb index 46c8260ab48..7bd011101dd 100644 --- a/app/models/project_services/chat_notification_service.rb +++ b/app/models/project_services/chat_notification_service.rb @@ -84,10 +84,10 @@ class ChatNotificationService < Service event_type = data[:event_type] || object_kind - channel_name = get_channel_field(event_type).presence || channel + channel_names = get_channel_field(event_type).presence || channel opts = {} - opts[:channel] = channel_name if channel_name + opts[:channel] = channel_names.split(',').map(&:strip) if channel_names opts[:username] = username if username return false unless notify(message, opts) diff --git a/app/models/project_services/slack_service.rb b/app/models/project_services/slack_service.rb index 7290964f442..6d567bb1383 100644 --- a/app/models/project_services/slack_service.rb +++ b/app/models/project_services/slack_service.rb @@ -13,18 +13,8 @@ class SlackService < ChatNotificationService 'slack' end - def help - 'This service sends notifications about projects events to Slack channels.<br /> - To set up this service: - <ol> - <li><a href="https://slack.com/apps/A0F7XDUAZ-incoming-webhooks">Add an incoming webhook</a> in your Slack team. The default channel can be overridden for each event.</li> - <li>Paste the <strong>Webhook URL</strong> into the field below.</li> - <li>Select events below to enable notifications. The <strong>Channel name</strong> and <strong>Username</strong> fields are optional.</li> - </ol>' - end - def default_channel_placeholder - "Channel name (e.g. general)" + _('Slack channels (e.g. general, development)') end def webhook_placeholder @@ -35,8 +25,8 @@ class SlackService < ChatNotificationService private def notify(message, opts) - # See https://github.com/stevenosloan/slack-notifier#custom-http-client - notifier = Slack::Notifier.new(webhook, opts.merge(http_client: HTTPClient)) + # See https://gitlab.com/gitlab-org/slack-notifier/#custom-http-client + notifier = Slack::Messenger.new(webhook, opts.merge(http_client: HTTPClient)) notifier.ping( message.pretext, diff --git a/app/models/project_services/slack_slash_commands_service.rb b/app/models/project_services/slack_slash_commands_service.rb index 6a454070fe2..01ded0495a7 100644 --- a/app/models/project_services/slack_slash_commands_service.rb +++ b/app/models/project_services/slack_slash_commands_service.rb @@ -29,6 +29,6 @@ class SlackSlashCommandsService < SlashCommandsService private def format(text) - Slack::Notifier::LinkFormatter.format(text) if text + Slack::Messenger::Util::LinkFormatter.format(text) if text end end diff --git a/app/models/snippet.rb b/app/models/snippet.rb index 745700b1c65..8f162f17ac5 100644 --- a/app/models/snippet.rb +++ b/app/models/snippet.rb @@ -17,7 +17,7 @@ class Snippet < ApplicationRecord include HasRepository extend ::Gitlab::Utils::Override - ignore_column :repository_storage, remove_with: '12.10', remove_after: '2020-04-22' + ignore_column :repository_storage, remove_with: '12.10', remove_after: '2020-03-22' cache_markdown_field :title, pipeline: :single_line cache_markdown_field :description diff --git a/app/views/projects/services/slack/_help.haml b/app/views/projects/services/slack/_help.haml new file mode 100644 index 00000000000..d7ea1b270f5 --- /dev/null +++ b/app/views/projects/services/slack/_help.haml @@ -0,0 +1,16 @@ +- webhooks_link_url = 'https://slack.com/apps/A0F7XDUAZ-incoming-webhooks' +- webhooks_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: webhooks_link_url } + +.info-well + .well-segment + %p= s_('SlackIntegration|This service send notifications about projects\' events to Slack channels. To set up this service:') + %ol + %li + = s_('SlackIntegration|%{webhooks_link_start}Add an incoming webhook%{webhooks_link_end} in your Slack team. The default channel can be overridden for each event.').html_safe % { webhooks_link_start: webhooks_link_start, webhooks_link_end: '</a>'.html_safe } + %li + = s_('SlackIntegration|Paste the <strong>Webhook URL</strong> into the field below.').html_safe + %li + = s_('SlackIntegration|Select events below to enable notifications. The <strong>Slack channel names</strong> and <strong>Slack username</strong> fields are optional.').html_safe + %p.mt-3.mb-0 + = s_('SlackIntegration|<strong>Note:</strong> Usernames and private channels are not supported.').html_safe + = link_to _('Learn more'), help_page_path('user/project/integrations/slack') diff --git a/app/views/shared/snippets/_list.html.haml b/app/views/shared/snippets/_list.html.haml index 766f48fff3d..ca3a291ae27 100644 --- a/app/views/shared/snippets/_list.html.haml +++ b/app/views/shared/snippets/_list.html.haml @@ -8,4 +8,4 @@ %ul.content-list = render partial: 'shared/snippets/snippet', collection: @snippets, locals: { link_project: link_project } - = paginate @snippets, theme: 'gitlab', remote: remote + = paginate_collection @snippets, remote: remote diff --git a/app/workers/concerns/waitable_worker.rb b/app/workers/concerns/waitable_worker.rb index 17946bbc5ca..f995aced542 100644 --- a/app/workers/concerns/waitable_worker.rb +++ b/app/workers/concerns/waitable_worker.rb @@ -9,7 +9,7 @@ module WaitableWorker # Short-circuit: it's more efficient to do small numbers of jobs inline return bulk_perform_inline(args_list) if args_list.size <= 3 - waiter = Gitlab::JobWaiter.new(args_list.size) + waiter = Gitlab::JobWaiter.new(args_list.size, worker_label: self.to_s) # Point all the bulk jobs at the same JobWaiter. Converts, [[1], [2], [3]] # into [[1, "key"], [2, "key"], [3, "key"]] |