summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/cycle_analytics/components/stage_review_component.vue5
-rw-r--r--app/assets/javascripts/persistent_user_callouts.js1
-rw-r--r--app/controllers/dashboard/todos_controller.rb2
-rw-r--r--app/models/event.rb7
-rw-r--r--app/models/wiki_page.rb5
-rw-r--r--app/services/event_create_service.rb55
-rw-r--r--app/services/git/wiki_push_service.rb7
-rw-r--r--app/services/git/wiki_push_service/change.rb4
-rw-r--r--app/services/wiki_pages/base_service.rb8
-rw-r--r--app/services/wiki_pages/destroy_service.rb4
-rw-r--r--app/services/wiki_pages/event_create_service.rb4
-rw-r--r--app/views/projects/merge_requests/_merge_request.html.haml4
-rw-r--r--app/views/projects/services/alerts/_top.html.haml2
-rw-r--r--app/views/projects/services/prometheus/_top.html.haml2
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.')