Skip to content
Snippets Groups Projects
Commit 33795139 authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent c7e385e2
No related branches found
No related tags found
No related merge requests found
Showing
with 441 additions and 57 deletions
Loading
Loading
@@ -110,14 +110,6 @@ export default {
board.name.toLowerCase().includes(this.filterTerm.toLowerCase()),
);
},
reload: {
get() {
return this.state.reload;
},
set(newValue) {
this.state.reload = newValue;
},
},
board() {
return this.state.currentBoard;
},
Loading
Loading
@@ -142,16 +134,6 @@ export default {
this.scrollFadeInitialized = false;
this.$nextTick(this.setScrollFade);
},
reload() {
if (this.reload) {
this.boards = [];
this.recentBoards = [];
this.loading = true;
this.reload = false;
this.loadBoards(false);
}
},
},
created() {
boardsStore.setCurrentBoard(this.currentBoard);
Loading
Loading
Loading
Loading
@@ -30,7 +30,6 @@ const boardsStore = {
labels: [],
},
currentPage: '',
reload: false,
endpoints: {},
},
detail: {
Loading
Loading
@@ -61,7 +60,6 @@ const boardsStore = {
};
},
showPage(page) {
this.state.reload = false;
this.state.currentPage = page;
},
addList(listObj, defaultAvatar) {
Loading
Loading
Loading
Loading
@@ -371,8 +371,11 @@
}
 
.btn-loading {
&:not(.disabled) .fa {
display: none;
&:not(.disabled) {
.fa,
.spinner {
display: none;
}
}
 
.fa {
Loading
Loading
# frozen_string_literal: true
module MilestoneEventable
extend ActiveSupport::Concern
included do
has_many :resource_milestone_events
end
end
# frozen_string_literal: true
module ResourceEventTools
extend ActiveSupport::Concern
included do
belongs_to :user
validates :user, presence: { unless: :importing? }, on: :create
validate :exactly_one_issuable
scope :created_after, ->(time) { where('created_at > ?', time) }
end
def exactly_one_issuable
issuable_count = self.class.issuable_attrs.count { |attr| self["#{attr}_id"] }
return true if issuable_count == 1
# if none of issuable IDs is set, check explicitly if nested issuable
# object is set, this is used during project import
if issuable_count == 0 && importing?
issuable_count = self.class.issuable_attrs.count { |attr| self.public_send(attr) } # rubocop:disable GitlabSecurity/PublicSend
return true if issuable_count == 1
end
errors.add(:base, "Exactly one of #{self.class.issuable_attrs.join(', ')} is required")
end
end
Loading
Loading
@@ -15,6 +15,7 @@ class Issue < ApplicationRecord
include ThrottledTouch
include LabelEventable
include IgnorableColumns
include MilestoneEventable
 
DueDateStruct = Struct.new(:title, :name).freeze
NoDueDate = DueDateStruct.new('No Due Date', '0').freeze
Loading
Loading
Loading
Loading
@@ -18,6 +18,7 @@ class MergeRequest < ApplicationRecord
include DeprecatedAssignee
include ShaAttribute
include IgnorableColumns
include MilestoneEventable
 
sha_attribute :squash_commit_sha
 
Loading
Loading
# frozen_string_literal: true
class MilestoneNote < ::Note
attr_accessor :resource_parent, :event, :milestone
def self.from_event(event, resource: nil, resource_parent: nil)
resource ||= event.resource
attrs = {
system: true,
author: event.user,
created_at: event.created_at,
noteable: resource,
milestone: event.milestone,
event: event,
system_note_metadata: ::SystemNoteMetadata.new(action: 'milestone'),
resource_parent: resource_parent
}
if resource_parent.is_a?(Project)
attrs[:project_id] = resource_parent.id
end
MilestoneNote.new(attrs)
end
def note
@note ||= note_text
end
def note_html
@note_html ||= Banzai::Renderer.cacheless_render_field(self, :note, { group: group, project: project })
end
def project
resource_parent if resource_parent.is_a?(Project)
end
def group
resource_parent if resource_parent.is_a?(Group)
end
private
def note_text(html: false)
format = milestone&.group_milestone? ? :name : :iid
milestone.nil? ? 'removed milestone' : "changed milestone to #{milestone.to_reference(project, format: format)}"
end
end
Loading
Loading
@@ -4,20 +4,17 @@ class ResourceLabelEvent < ApplicationRecord
include Importable
include Gitlab::Utils::StrongMemoize
include CacheMarkdownField
include ResourceEventTools
 
cache_markdown_field :reference
 
belongs_to :user
belongs_to :issue
belongs_to :merge_request
belongs_to :label
 
scope :created_after, ->(time) { where('created_at > ?', time) }
scope :inc_relations, -> { includes(:label, :user) }
 
validates :user, presence: { unless: :importing? }, on: :create
validates :label, presence: { unless: :importing? }, on: :create
validate :exactly_one_issuable
 
after_save :expire_etag_cache
after_destroy :expire_etag_cache
Loading
Loading
@@ -94,22 +91,6 @@ class ResourceLabelEvent < ApplicationRecord
end
end
 
def exactly_one_issuable
issuable_count = self.class.issuable_attrs.count { |attr| self["#{attr}_id"] }
return true if issuable_count == 1
# if none of issuable IDs is set, check explicitly if nested issuable
# object is set, this is used during project import
if issuable_count == 0 && importing?
issuable_count = self.class.issuable_attrs.count { |attr| self.public_send(attr) } # rubocop:disable GitlabSecurity/PublicSend
return true if issuable_count == 1
end
errors.add(:base, "Exactly one of #{self.class.issuable_attrs.join(', ')} is required")
end
def expire_etag_cache
issuable.expire_note_etag_cache
end
Loading
Loading
# frozen_string_literal: true
class ResourceMilestoneEvent < ApplicationRecord
include Gitlab::Utils::StrongMemoize
include Importable
include ResourceEventTools
belongs_to :issue
belongs_to :merge_request
belongs_to :milestone
scope :by_issue, ->(issue) { where(issue_id: issue.id) }
scope :by_merge_request, ->(merge_request) { where(merge_request_id: merge_request.id) }
enum action: {
add: 1,
remove: 2
}
# state is used for issue and merge request states.
enum state: Issue.available_states.merge(MergeRequest.available_states)
def self.issuable_attrs
%i(issue merge_request).freeze
end
def resource
issue || merge_request
end
end
Loading
Loading
@@ -19,6 +19,7 @@ module Issuable
 
copy_resource_label_events
copy_resource_weight_events
copy_resource_milestone_events
end
 
private
Loading
Loading
@@ -65,6 +66,23 @@ module Issuable
end
end
 
def copy_resource_milestone_events
entity_key = new_entity.class.name.underscore.foreign_key
copy_events(ResourceMilestoneEvent.table_name, original_entity.resource_milestone_events) do |event|
matching_destination_milestone = matching_milestone(event.milestone.title)
if matching_destination_milestone.present?
event.attributes
.except('id', 'reference', 'reference_html')
.merge(entity_key => new_entity.id,
'milestone_id' => matching_destination_milestone.id,
'action' => ResourceMilestoneEvent.actions[event.action],
'state' => ResourceMilestoneEvent.states[event.state])
end
end
end
def copy_events(table_name, events_to_copy)
events_to_copy.find_in_batches do |batch|
events = batch.map do |event|
Loading
Loading
Loading
Loading
@@ -22,13 +22,17 @@ module Issuable
end
 
create_due_date_note if issuable.previous_changes.include?('due_date')
create_milestone_note if issuable.previous_changes.include?('milestone_id')
create_milestone_note if has_milestone_changes?
create_labels_note(old_labels) if old_labels && issuable.labels != old_labels
end
end
 
private
 
def has_milestone_changes?
issuable.previous_changes.include?('milestone_id')
end
def handle_time_tracking_note
if issuable.previous_changes.include?('time_estimate')
create_time_estimate_note
Loading
Loading
@@ -95,7 +99,16 @@ module Issuable
end
 
def create_milestone_note
SystemNoteService.change_milestone(issuable, issuable.project, current_user, issuable.milestone)
if milestone_changes_tracking_enabled?
# Creates a synthetic note
ResourceEvents::ChangeMilestoneService.new(resource: issuable, user: current_user).execute
else
SystemNoteService.change_milestone(issuable, issuable.project, current_user, issuable.milestone)
end
end
def milestone_changes_tracking_enabled?
::Feature.enabled?(:track_resource_milestone_change_events, issuable.project)
end
 
def create_due_date_note
Loading
Loading
# frozen_string_literal: true
module ResourceEvents
class ChangeMilestoneService
attr_reader :resource, :user, :event_created_at, :resource_args
def initialize(resource:, user:, created_at: Time.now)
@resource = resource
@user = user
@event_created_at = created_at
@resource_args = {
user_id: user.id,
created_at: event_created_at
}
end
def execute
args = build_resource_args
action = if milestone.nil?
:remove
else
:add
end
record = args.merge(milestone_id: milestone&.id, action: ResourceMilestoneEvent.actions[action])
create_event(record)
end
private
def milestone
resource&.milestone
end
def create_event(record)
ResourceMilestoneEvent.create(record)
resource.expire_note_etag_cache
end
def build_resource_args
key = resource.class.name.underscore.foreign_key
resource_args.merge(key => resource.id, state: ResourceMilestoneEvent.states[resource.state])
end
end
end
Loading
Loading
@@ -9,6 +9,11 @@ module ResourceEvents
class MergeIntoNotesService
include Gitlab::Utils::StrongMemoize
 
SYNTHETIC_NOTE_BUILDER_SERVICES = [
SyntheticLabelNotesBuilderService,
SyntheticMilestoneNotesBuilderService
].freeze
attr_reader :resource, :current_user, :params
 
def initialize(resource, current_user, params = {})
Loading
Loading
@@ -24,7 +29,9 @@ module ResourceEvents
private
 
def synthetic_notes
SyntheticLabelNotesBuilderService.new(resource, current_user, params).execute
SYNTHETIC_NOTE_BUILDER_SERVICES.flat_map do |service|
service.new(resource, current_user, params).execute
end
end
end
end
Loading
Loading
# frozen_string_literal: true
# We store events about resource milestone changes in a separate table,
# but we still want to display notes about milestone changes
# as classic system notes in UI. This service generates "synthetic" notes for
# milestone event changes.
module ResourceEvents
class SyntheticMilestoneNotesBuilderService < BaseSyntheticNotesBuilderService
private
def synthetic_notes
return [] unless tracking_enabled?
milestone_change_events.map do |event|
MilestoneNote.from_event(event, resource: resource, resource_parent: resource_parent)
end
end
def milestone_change_events
return [] unless resource.respond_to?(:resource_milestone_events)
events = resource.resource_milestone_events.includes(user: :status) # rubocop: disable CodeReuse/ActiveRecord
since_fetch_at(events)
end
def tracking_enabled?
::Feature.enabled?(:track_resource_milestone_change_events, resource.project)
end
end
end
Loading
Loading
@@ -48,14 +48,14 @@
 
- if todo.pending?
.todo-actions
= link_to dashboard_todo_path(todo), method: :delete, class: 'btn btn-loading js-done-todo', data: { href: dashboard_todo_path(todo) } do
= link_to dashboard_todo_path(todo), method: :delete, class: 'btn btn-loading d-flex align-items-center js-done-todo', data: { href: dashboard_todo_path(todo) } do
Done
= icon('spinner spin')
= link_to restore_dashboard_todo_path(todo), method: :patch, class: 'btn btn-loading js-undo-todo hidden', data: { href: restore_dashboard_todo_path(todo) } do
%span.spinner.ml-1
= link_to restore_dashboard_todo_path(todo), method: :patch, class: 'btn btn-loading d-flex align-items-center js-undo-todo hidden', data: { href: restore_dashboard_todo_path(todo) } do
Undo
= icon('spinner spin')
%span.spinner.ml-1
- else
.todo-actions
= link_to restore_dashboard_todo_path(todo), method: :patch, class: 'btn btn-loading js-add-todo', data: { href: restore_dashboard_todo_path(todo) } do
= link_to restore_dashboard_todo_path(todo), method: :patch, class: 'btn btn-loading d-flex align-items-center js-add-todo', data: { href: restore_dashboard_todo_path(todo) } do
Add a To Do
= icon('spinner spin')
%span.spinner.ml-1
Loading
Loading
@@ -26,12 +26,12 @@
.nav-controls
- if @todos.any?(&:pending?)
.append-right-default
= link_to destroy_all_dashboard_todos_path(todos_filter_params), class: 'btn btn-loading js-todos-mark-all', method: :delete, data: { href: destroy_all_dashboard_todos_path(todos_filter_params) } do
= link_to destroy_all_dashboard_todos_path(todos_filter_params), class: 'btn btn-loading d-flex align-items-center js-todos-mark-all', method: :delete, data: { href: destroy_all_dashboard_todos_path(todos_filter_params) } do
Mark all as done
= icon('spinner spin')
= link_to bulk_restore_dashboard_todos_path, class: 'btn btn-loading js-todos-undo-all hidden', method: :patch , data: { href: bulk_restore_dashboard_todos_path(todos_filter_params) } do
%span.spinner.ml-1
= link_to bulk_restore_dashboard_todos_path, class: 'btn btn-loading d-flex align-items-center js-todos-undo-all hidden', method: :patch , data: { href: bulk_restore_dashboard_todos_path(todos_filter_params) } do
Undo mark all as done
= icon('spinner spin')
%span.spinner.ml-1
 
.todos-filters
.issues-details-filters.row-content-block.second-block
Loading
Loading
# frozen_string_literal: true
 
class AdminEmailWorker
class AdminEmailWorker # rubocop:disable Scalability/IdempotentWorker
include ApplicationWorker
# rubocop:disable Scalability/CronWorkerContext
# This worker does not perform work scoped to a context
Loading
Loading
This diff is collapsed.
# frozen_string_literal: true
 
class ArchiveTraceWorker
class ArchiveTraceWorker # rubocop:disable Scalability/IdempotentWorker
include ApplicationWorker
include PipelineBackgroundQueue
 
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment