diff options
Diffstat (limited to 'app')
-rw-r--r-- | app/assets/javascripts/cycle_analytics/components/stage_review_component.vue | 5 | ||||
-rw-r--r-- | app/assets/javascripts/persistent_user_callouts.js | 1 | ||||
-rw-r--r-- | app/controllers/dashboard/todos_controller.rb | 2 | ||||
-rw-r--r-- | app/models/event.rb | 7 | ||||
-rw-r--r-- | app/models/wiki_page.rb | 5 | ||||
-rw-r--r-- | app/services/event_create_service.rb | 55 | ||||
-rw-r--r-- | app/services/git/wiki_push_service.rb | 7 | ||||
-rw-r--r-- | app/services/git/wiki_push_service/change.rb | 4 | ||||
-rw-r--r-- | app/services/wiki_pages/base_service.rb | 8 | ||||
-rw-r--r-- | app/services/wiki_pages/destroy_service.rb | 4 | ||||
-rw-r--r-- | app/services/wiki_pages/event_create_service.rb | 4 | ||||
-rw-r--r-- | app/views/projects/merge_requests/_merge_request.html.haml | 4 | ||||
-rw-r--r-- | app/views/projects/services/alerts/_top.html.haml | 2 | ||||
-rw-r--r-- | app/views/projects/services/prometheus/_top.html.haml | 2 |
14 files changed, 66 insertions, 44 deletions
diff --git a/app/assets/javascripts/cycle_analytics/components/stage_review_component.vue b/app/assets/javascripts/cycle_analytics/components/stage_review_component.vue index d61e6995551..2348e0719ca 100644 --- a/app/assets/javascripts/cycle_analytics/components/stage_review_component.vue +++ b/app/assets/javascripts/cycle_analytics/components/stage_review_component.vue @@ -3,6 +3,7 @@ import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar import limitWarning from './limit_warning_component.vue'; import totalTime from './total_time_component.vue'; import icon from '../../vue_shared/components/icon.vue'; +import { GlIcon } from '@gitlab/ui'; export default { components: { @@ -10,6 +11,7 @@ export default { totalTime, limitWarning, icon, + GlIcon, }, props: { items: { @@ -52,7 +54,8 @@ export default { </span> <template v-if="mergeRequest.state === 'closed'"> <span class="merge-request-state"> - <i class="fa fa-ban" aria-hidden="true"> </i> {{ mergeRequest.state.toUpperCase() }} + <gl-icon name="cancel" class="gl-vertical-align-text-bottom" /> + {{ __('CLOSED') }} </span> </template> <template v-else> diff --git a/app/assets/javascripts/persistent_user_callouts.js b/app/assets/javascripts/persistent_user_callouts.js index f4fe605f0a2..ef4d5338046 100644 --- a/app/assets/javascripts/persistent_user_callouts.js +++ b/app/assets/javascripts/persistent_user_callouts.js @@ -5,7 +5,6 @@ const PERSISTENT_USER_CALLOUTS = [ '.js-users-over-license-callout', '.js-admin-licensed-user-count-threshold', '.js-buy-pipeline-minutes-notification-callout', - '.js-alerts-moved-alert', '.js-token-expiry-callout', ]; diff --git a/app/controllers/dashboard/todos_controller.rb b/app/controllers/dashboard/todos_controller.rb index db40b0bed77..e4e7b26720d 100644 --- a/app/controllers/dashboard/todos_controller.rb +++ b/app/controllers/dashboard/todos_controller.rb @@ -9,7 +9,7 @@ class Dashboard::TodosController < Dashboard::ApplicationController before_action :authorize_read_group!, only: :index before_action :find_todos, only: [:index, :destroy_all] - track_unique_visits :index, target_id: 'u_analytics_todos' + track_unique_visits :index, target_id: 'u_todos' def index @sort = params[:sort] diff --git a/app/models/event.rb b/app/models/event.rb index 56d7742c51a..92609144576 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -8,6 +8,7 @@ class Event < ApplicationRecord include CreatedAtFilterable include Gitlab::Utils::StrongMemoize include UsageStatistics + include ShaAttribute default_scope { reorder(nil) } # rubocop:disable Cop/DefaultScope @@ -48,6 +49,8 @@ class Event < ApplicationRecord RESET_PROJECT_ACTIVITY_INTERVAL = 1.hour REPOSITORY_UPDATED_AT_INTERVAL = 5.minutes + sha_attribute :fingerprint + enum action: ACTIONS, _suffix: true delegate :name, :email, :public_email, :username, to: :author, prefix: true, allow_nil: true @@ -82,6 +85,10 @@ class Event < ApplicationRecord scope :recent, -> { reorder(id: :desc) } scope :for_wiki_page, -> { where(target_type: 'WikiPage::Meta') } scope :for_design, -> { where(target_type: 'DesignManagement::Design') } + scope :for_fingerprint, ->(fingerprint) do + fingerprint.present? ? where(fingerprint: fingerprint) : none + end + scope :for_action, ->(action) { where(action: action) } scope :with_associations, -> do # We're using preload for "push_event_payload" as otherwise the association diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb index 6a4b4472a03..3dc5caf6119 100644 --- a/app/models/wiki_page.rb +++ b/app/models/wiki_page.rb @@ -98,6 +98,7 @@ class WikiPage def slug attributes[:slug].presence || wiki.wiki.preview_slug(title, format) end + alias_method :id, :slug # required to use build_stubbed alias_method :to_param, :slug @@ -265,8 +266,8 @@ class WikiPage '../shared/wikis/wiki_page' end - def id - page.version.to_s + def sha + page.version&.sha end def title_changed? diff --git a/app/services/event_create_service.rb b/app/services/event_create_service.rb index ad36fe70b3a..abbb68aaf94 100644 --- a/app/services/event_create_service.rb +++ b/app/services/event_create_service.rb @@ -100,25 +100,21 @@ class EventCreateService # @param [WikiPage::Meta] wiki_page_meta The event target # @param [User] author The event author # @param [Symbol] action One of the Event::WIKI_ACTIONS + # @param [String] fingerprint The de-duplication fingerprint # - # @return a tuple of event and either :found or :created - def wiki_event(wiki_page_meta, author, action) + # The fingerprint, if provided, should be sufficient to find duplicate events. + # Suitable values would be, for example, the current page SHA. + # + # @return [Event] the event + def wiki_event(wiki_page_meta, author, action, fingerprint) raise IllegalActionError, action unless Event::WIKI_ACTIONS.include?(action) - if duplicate = existing_wiki_event(wiki_page_meta, action) - return duplicate - end - - event = create_record_event(wiki_page_meta, author, action) - # Ensure that the event is linked in time to the metadata, for non-deletes - unless event.destroyed_action? - time_stamp = wiki_page_meta.updated_at - event.update_columns(updated_at: time_stamp, created_at: time_stamp) - end - Gitlab::UsageDataCounters::TrackUniqueActions.track_action(event_action: action, event_target: wiki_page_meta.class, author_id: author.id) - event + duplicate = Event.for_wiki_meta(wiki_page_meta).for_fingerprint(fingerprint).first + return duplicate if duplicate.present? + + create_record_event(wiki_page_meta, author, action, fingerprint.presence) end def approve_mr(merge_request, current_user) @@ -127,44 +123,37 @@ class EventCreateService private - def existing_wiki_event(wiki_page_meta, action) - if Event.actions.fetch(action) == Event.actions[:destroyed] - most_recent = Event.for_wiki_meta(wiki_page_meta).recent.first - return most_recent if most_recent.present? && Event.actions[most_recent.action] == Event.actions[action] - else - Event.for_wiki_meta(wiki_page_meta).created_at(wiki_page_meta.updated_at).first - end - end - - def create_record_event(record, current_user, status) + def create_record_event(record, current_user, status, fingerprint = nil) create_event(record.resource_parent, current_user, status, - target_id: record.id, target_type: record.class.name) + fingerprint: fingerprint, + target_id: record.id, + target_type: record.class.name) end # If creating several events, this method will insert them all in a single # statement # - # @param [[Eventable, Symbol]] a list of pairs of records and a valid status + # @param [[Eventable, Symbol, String]] a list of tuples of records, a valid status, and fingerprint # @param [User] the author of the event - def create_record_events(pairs, current_user) + def create_record_events(tuples, current_user) base_attrs = { created_at: Time.now.utc, updated_at: Time.now.utc, author_id: current_user.id } - attribute_sets = pairs.map do |record, status| + attribute_sets = tuples.map do |record, status, fingerprint| action = Event.actions[status] raise IllegalActionError, "#{status} is not a valid status" if action.nil? parent_attrs(record.resource_parent) .merge(base_attrs) - .merge(action: action, target_id: record.id, target_type: record.class.name) + .merge(action: action, fingerprint: fingerprint, target_id: record.id, target_type: record.class.name) end result = Event.insert_all(attribute_sets, returning: %w[id]) - pairs.each do |record, status| + tuples.each do |record, status, _| Gitlab::UsageDataCounters::TrackUniqueActions.track_action(event_action: status, event_target: record.class, author_id: current_user.id) end @@ -198,7 +187,11 @@ class EventCreateService ) attributes.merge!(parent_attrs(resource_parent)) - Event.create!(attributes) + if attributes[:fingerprint].present? + Event.safe_find_or_create_by!(attributes) + else + Event.create!(attributes) + end end def parent_attrs(resource_parent) diff --git a/app/services/git/wiki_push_service.rb b/app/services/git/wiki_push_service.rb index b3937a10a70..f9de72f2d5f 100644 --- a/app/services/git/wiki_push_service.rb +++ b/app/services/git/wiki_push_service.rb @@ -41,7 +41,12 @@ module Git end def create_event_for(change) - event_service.execute(change.last_known_slug, change.page, change.event_action) + event_service.execute( + change.last_known_slug, + change.page, + change.event_action, + change.sha + ) end def event_service diff --git a/app/services/git/wiki_push_service/change.rb b/app/services/git/wiki_push_service/change.rb index 14e622dd147..562c43487e9 100644 --- a/app/services/git/wiki_push_service/change.rb +++ b/app/services/git/wiki_push_service/change.rb @@ -33,6 +33,10 @@ module Git strip_extension(raw_change.old_path || raw_change.new_path) end + def sha + change[:newrev] + end + private attr_reader :raw_change, :change, :wiki diff --git a/app/services/wiki_pages/base_service.rb b/app/services/wiki_pages/base_service.rb index 2967684f7bc..fd234630633 100644 --- a/app/services/wiki_pages/base_service.rb +++ b/app/services/wiki_pages/base_service.rb @@ -44,7 +44,9 @@ module WikiPages end def create_wiki_event(page) - response = WikiPages::EventCreateService.new(current_user).execute(slug_for_page(page), page, event_action) + response = WikiPages::EventCreateService + .new(current_user) + .execute(slug_for_page(page), page, event_action, fingerprint(page)) log_error(response.message) if response.error? end @@ -52,6 +54,10 @@ module WikiPages def slug_for_page(page) page.slug end + + def fingerprint(page) + page.sha + end end end diff --git a/app/services/wiki_pages/destroy_service.rb b/app/services/wiki_pages/destroy_service.rb index d59c27bb92a..ab5abe1c82b 100644 --- a/app/services/wiki_pages/destroy_service.rb +++ b/app/services/wiki_pages/destroy_service.rb @@ -21,5 +21,9 @@ module WikiPages def event_action :destroyed end + + def fingerprint(page) + page.wiki.repository.head_commit.sha + end end end diff --git a/app/services/wiki_pages/event_create_service.rb b/app/services/wiki_pages/event_create_service.rb index 0453c90d693..ebfc2414f9e 100644 --- a/app/services/wiki_pages/event_create_service.rb +++ b/app/services/wiki_pages/event_create_service.rb @@ -9,11 +9,11 @@ module WikiPages @author = author end - def execute(slug, page, action) + def execute(slug, page, action, event_fingerprint) event = Event.transaction do wiki_page_meta = WikiPage::Meta.find_or_create(slug, page) - ::EventCreateService.new.wiki_event(wiki_page_meta, author, action) + ::EventCreateService.new.wiki_event(wiki_page_meta, author, action, event_fingerprint) end ServiceResponse.success(payload: { event: event }) diff --git a/app/views/projects/merge_requests/_merge_request.html.haml b/app/views/projects/merge_requests/_merge_request.html.haml index d3e98bac7f9..567dbbcd498 100644 --- a/app/views/projects/merge_requests/_merge_request.html.haml +++ b/app/views/projects/merge_requests/_merge_request.html.haml @@ -45,13 +45,13 @@ = _('MERGED') - elsif merge_request.closed? %li.issuable-status.d-none.d-sm-inline-block - = icon('ban') + = sprite_icon('cancel', size: 16, css_class: 'gl-vertical-align-text-bottom') = _('CLOSED') = render 'shared/merge_request_pipeline_status', merge_request: merge_request - if merge_request.open? && merge_request.broken? %li.issuable-pipeline-broken.d-none.d-sm-flex = link_to merge_request_path(merge_request), class: "has-tooltip", title: _('Cannot be merged automatically') do - = icon('exclamation-triangle') + = sprite_icon('warning-solid', size: 16) - if merge_request.assignees.any? %li.d-flex = render 'shared/issuable/assignees', project: merge_request.project, issuable: merge_request diff --git a/app/views/projects/services/alerts/_top.html.haml b/app/views/projects/services/alerts/_top.html.haml index ebc93978832..ff903864370 100644 --- a/app/views/projects/services/alerts/_top.html.haml +++ b/app/views/projects/services/alerts/_top.html.haml @@ -1,6 +1,6 @@ .row .col-lg-12 - .gl-alert.gl-alert-info.js-alerts-moved-alert{ role: 'alert' } + .gl-alert.gl-alert-info{ role: 'alert' } = sprite_icon('information-o', size: 16, css_class: 'gl-icon gl-alert-icon gl-alert-icon-no-title') .gl-alert-body = _('You can now manage alert endpoint configuration in the Alerts section on the Operations settings page. Fields on this page have been deprecated.') diff --git a/app/views/projects/services/prometheus/_top.html.haml b/app/views/projects/services/prometheus/_top.html.haml index 338414be5ab..56dfa951804 100644 --- a/app/views/projects/services/prometheus/_top.html.haml +++ b/app/views/projects/services/prometheus/_top.html.haml @@ -2,7 +2,7 @@ .row .col-lg-12 - .gl-alert.gl-alert-info.js-alerts-moved-alert{ role: 'alert' } + .gl-alert.gl-alert-info{ role: 'alert' } = sprite_icon('information-o', size: 16, css_class: 'gl-icon gl-alert-icon gl-alert-icon-no-title') .gl-alert-body = s_('AlertSettings|You can now set up alert endpoints for manually configured Prometheus instances in the Alerts section on the Operations settings page. Alert endpoint fields on this page have been deprecated.') |