提交 ce493944 编写于 作者: G GitLab Bot

Add latest changes from gitlab-org/gitlab@master

上级 e9ea5bbd
此差异已折叠。
......@@ -140,6 +140,7 @@ gem 'deckar01-task_list', '2.3.1'
gem 'gitlab-markup', '~> 1.7.1'
gem 'github-markup', '~> 1.7.0', require: 'github/markup'
gem 'commonmarker', '~> 0.20'
gem 'kramdown', '~> 2.2.1'
gem 'RedCloth', '~> 4.3.2'
gem 'rdoc', '~> 6.1.2'
gem 'org-ruby', '~> 0.9.12'
......
......@@ -575,7 +575,8 @@ GEM
kgio (2.11.3)
knapsack (1.17.0)
rake
kramdown (2.1.0)
kramdown (2.2.1)
rexml
kramdown-parser-gfm (1.1.0)
kramdown (~> 2.0)
kubeclient (4.6.0)
......@@ -1282,6 +1283,7 @@ DEPENDENCIES
jwt (~> 2.1.0)
kaminari (~> 1.0)
knapsack (~> 1.17)
kramdown (~> 2.2.1)
kubeclient (~> 4.6.0)
letter_opener_web (~> 1.3.4)
license_finder (~> 5.4)
......
import { isEmpty } from 'lodash';
import { mergeUrlParams } from './url_utility';
// We should probably not couple this utility to `gon.gitlab_url`
// Also, this would replace occurrences that aren't at the beginning of the string
const removeGitLabUrl = url => url.replace(gon.gitlab_url, '');
const getFullUrl = req => {
const url = removeGitLabUrl(req.url);
return mergeUrlParams(req.params || {}, url);
};
const setupAxiosStartupCalls = axios => {
const { startup_calls: startupCalls } = window.gl || {};
if (!startupCalls || isEmpty(startupCalls)) {
return;
}
// TODO: To save performance of future axios calls, we can
// remove this interceptor once the "startupCalls" have been loaded
axios.interceptors.request.use(req => {
const fullUrl = getFullUrl(req);
const existing = startupCalls[fullUrl];
if (existing) {
// eslint-disable-next-line no-param-reassign
req.adapter = () =>
existing.fetchCall.then(res =>
// eslint-disable-next-line promise/no-nesting
res.json().then(data => ({
data,
status: res.status,
statusText: res.statusText,
headers: res.headers,
config: req,
request: req,
})),
);
}
return req;
});
};
export default setupAxiosStartupCalls;
import axios from 'axios';
import csrf from './csrf';
import suppressAjaxErrorsDuringNavigation from './suppress_ajax_errors_during_navigation';
import setupAxiosStartupCalls from './axios_startup_calls';
axios.defaults.headers.common[csrf.headerKey] = csrf.token;
// Used by Rails to check if it is a valid XHR request
......@@ -14,6 +15,8 @@ axios.interceptors.request.use(config => {
return config;
});
setupAxiosStartupCalls(axios);
// Remove the global counter
axios.interceptors.response.use(
response => {
......
......@@ -329,13 +329,6 @@ class ApplicationController < ActionController::Base
end
end
def event_filter
@event_filter ||=
EventFilter.new(params[:event_filter].presence || cookies[:event_filter]).tap do |new_event_filter|
cookies[:event_filter] = new_event_filter.filter
end
end
# JSON for infinite scroll via Pager object
def pager_json(partial, count, locals = {})
html = render_to_string(
......
# frozen_string_literal: true
module FiltersEvents
def event_filter
@event_filter ||= new_event_filter.tap { |ef| cookies[:event_filter] = ef.filter }
end
private
def new_event_filter
active_filter = params[:event_filter].presence || cookies[:event_filter]
EventFilter.new(active_filter)
end
end
......@@ -6,6 +6,7 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController
include OnboardingExperimentHelper
include SortingHelper
include SortingPreference
include FiltersEvents
prepend_before_action(only: [:index]) { authenticate_sessionless_user!(:rss) }
before_action :set_non_archived_param
......
......@@ -2,6 +2,7 @@
class DashboardController < Dashboard::ApplicationController
include IssuableCollectionsAction
include FiltersEvents
prepend_before_action(only: [:issues]) { authenticate_sessionless_user!(:rss) }
prepend_before_action(only: [:issues_calendar]) { authenticate_sessionless_user!(:ics) }
......
......@@ -7,6 +7,7 @@ class GroupsController < Groups::ApplicationController
include PreviewMarkdown
include RecordUserLastActivity
include SendFileUpload
include FiltersEvents
extend ::Gitlab::Utils::Override
respond_to :html
......
# frozen_string_literal: true
module Projects
module Pipelines
class TestsController < Projects::ApplicationController
before_action :pipeline
before_action :authorize_read_pipeline!
before_action :authorize_read_build!
before_action :validate_feature_flag!
def summary
respond_to do |format|
format.json do
render json: TestReportSerializer
.new(project: project, current_user: @current_user)
.represent(pipeline.test_report_summary)
end
end
end
private
def validate_feature_flag!
render_404 unless Feature.enabled?(:build_report_summary, project)
end
def pipeline
project.all_pipelines.find(tests_params[:id])
end
def tests_params
params.permit(:id)
end
end
end
end
......@@ -186,7 +186,7 @@ class Projects::PipelinesController < Projects::ApplicationController
format.json do
render json: TestReportSerializer
.new(current_user: @current_user)
.represent(pipeline_test_report, project: project)
.represent(pipeline_test_report, project: project, details: true)
end
end
end
......
......@@ -8,6 +8,7 @@ class ProjectsController < Projects::ApplicationController
include SendFileUpload
include RecordUserLastActivity
include ImportUrlParams
include FiltersEvents
prepend_before_action(only: [:show]) { authenticate_sessionless_user!(:rss) }
......
......@@ -46,7 +46,7 @@ class UserRecentEventsFinder
SQL
# Workaround for https://github.com/rails/rails/issues/24193
Event.from([Arel.sql(sql)])
ensure_design_visibility(Event.from([Arel.sql(sql)]))
end
# rubocop: enable CodeReuse/ActiveRecord
......@@ -59,4 +59,11 @@ class UserRecentEventsFinder
def projects
target_user.project_interactions.to_sql
end
# TODO: remove when the :design_activity_events feature flag is removed.
def ensure_design_visibility(events)
return events if Feature.enabled?(:design_activity_events)
events.not_design
end
end
# frozen_string_literal: true
module Mutations
module MergeRequests
class Update < Base
graphql_name 'MergeRequestUpdate'
description 'Update attributes of a merge request'
argument :title, GraphQL::STRING_TYPE,
required: false,
description: copy_field_description(Types::MergeRequestType, :title)
argument :target_branch, GraphQL::STRING_TYPE,
required: false,
description: copy_field_description(Types::MergeRequestType, :target_branch)
argument :description, GraphQL::STRING_TYPE,
required: false,
description: copy_field_description(Types::MergeRequestType, :description)
def resolve(args)
merge_request = authorized_find!(args.slice(:project_path, :iid))
attributes = args.slice(:title, :description, :target_branch).compact
::MergeRequests::UpdateService
.new(merge_request.project, current_user, attributes)
.execute(merge_request)
errors = errors_on_object(merge_request)
{
merge_request: merge_request.reset,
errors: errors
}
end
end
end
end
......@@ -20,6 +20,7 @@ module Types
mount_mutation Mutations::Issues::SetDueDate
mount_mutation Mutations::Issues::Update
mount_mutation Mutations::MergeRequests::Create
mount_mutation Mutations::MergeRequests::Update
mount_mutation Mutations::MergeRequests::SetLabels
mount_mutation Mutations::MergeRequests::SetLocked
mount_mutation Mutations::MergeRequests::SetMilestone
......
......@@ -27,6 +27,9 @@ module Types
description: 'Indicates if Large File Storage (LFS) is enabled for namespace'
field :request_access_enabled, GraphQL::BOOLEAN_TYPE, null: true,
description: 'Indicates if users can request access to namespace'
field :storage_size_limit, GraphQL::INT_TYPE, null: true,
description: 'Total storage limit of the root namespace in bytes',
resolve: -> (obj, _args, _ctx) { Namespace::RootStorageSize.new(obj).limit }
field :root_storage_statistics, Types::RootStorageStatisticsType,
null: true,
......
......@@ -335,6 +335,15 @@ module ApplicationHelper
}
end
def page_startup_api_calls
@api_startup_calls
end
def add_page_startup_api_call(api_path, options: {})
@api_startup_calls ||= {}
@api_startup_calls[api_path] = options
end
def autocomplete_data_sources(object, noteable_type)
return {} unless object && noteable_type
......
......@@ -29,7 +29,11 @@ module EventsHelper
def event_action_name(event)
target = if event.target_type
if event.note?
if event.design? || event.design_note?
'design'
elsif event.wiki_page?
'wiki page'
elsif event.note?
event.note_target_type
else
event.target_type.titleize.downcase
......@@ -58,11 +62,30 @@ module EventsHelper
end
def event_filter_visible(feature_key)
return designs_visible? if feature_key == :designs
return true unless @project
@project.feature_available?(feature_key, current_user)
end
def designs_visible?
return false unless Feature.enabled?(:design_activity_events)
if @project
design_activity_enabled?(@project)
elsif @group
design_activity_enabled?(@group)
elsif @projects
@projects.with_namespace.include_project_feature.any? { |p| design_activity_enabled?(p) }
else
true
end
end
def design_activity_enabled?(project)
Ability.allowed?(current_user, :read_design_activity, project)
end
def comments_visible?
event_filter_visible(:repository) ||
event_filter_visible(:merge_requests) ||
......@@ -94,6 +117,12 @@ module EventsHelper
elsif event.milestone?
words << "##{event.target_iid}" if event.target_iid
words << "in"
elsif event.design?
words << event.design.to_reference
words << "in"
elsif event.wiki_page?
words << event.target_title
words << "in"
elsif event.target
prefix =
if event.merge_request?
......@@ -187,6 +216,15 @@ module EventsHelper
end
end
def event_design_title_html(event)
capture do
concat content_tag(:span, _('design'), class: "event-target-type append-right-4")
concat link_to(event.design.reference_link_text, design_url(event.design),
title: event.target_title,
class: 'has-tooltip event-design event-target-link append-right-4')
end
end
def event_wiki_page_target_url(event)
project_wiki_url(event.project, event.target&.canonical_slug || Wiki::HOMEPAGE)
end
......@@ -214,6 +252,18 @@ module EventsHelper
sprite_icon(icon_name, size: size) if icon_name
end
DESIGN_ICONS = {
'created' => 'upload',
'updated' => 'pencil',
'destroyed' => ICON_NAMES_BY_EVENT_TYPE['destroyed'],
'archived' => 'archive'
}.freeze
def design_event_icon(action, size: 24)
icon_name = DESIGN_ICONS[action]
sprite_icon(icon_name, size: size) if icon_name
end
def icon_for_profile_event(event)
if current_path?('users#show')
content_tag :div, class: "system-note-image #{event.action_name.parameterize}-icon" do
......@@ -229,6 +279,8 @@ module EventsHelper
def inline_event_icon(event)
unless current_path?('users#show')
content_tag :span, class: "system-note-image-inline d-none d-sm-flex append-right-4 #{event.action_name.parameterize}-icon align-self-center" do
next design_event_icon(event.action, size: 14) if event.design?
icon_for_event(event.action_name, size: 14)
end
end
......@@ -244,7 +296,7 @@ module EventsHelper
private
def design_url(design, opts)
def design_url(design, opts = {})
designs_project_issue_url(
design.project,
design.issue,
......
......@@ -80,6 +80,7 @@ module Ci
has_one :pipeline_config, class_name: 'Ci::PipelineConfig', inverse_of: :pipeline
has_many :daily_build_group_report_results, class_name: 'Ci::DailyBuildGroupReportResult', foreign_key: :last_pipeline_id
has_many :latest_builds_report_results, through: :latest_builds, source: :report_results
accepts_nested_attributes_for :variables, reject_if: :persisted?
......@@ -802,6 +803,10 @@ module Ci
complete? && latest_report_builds(reports_scope).exists?
end
def test_report_summary
Gitlab::Ci::Reports::TestReportSummary.new(latest_builds_report_results)
end
def test_reports
Gitlab::Ci::Reports::TestReports.new.tap do |test_reports|
latest_report_builds(Ci::JobArtifact.test_reports).preload(:project).find_each do |build|
......
......@@ -45,9 +45,10 @@ class EventCollection
private
def apply_feature_flags(events)
return events if ::Feature.enabled?(:wiki_events)
events = events.not_wiki_page unless ::Feature.enabled?(:wiki_events)
events = events.not_design unless ::Feature.enabled?(:design_activity_events)
events.not_wiki_page
events
end
def project_events
......
......@@ -455,6 +455,7 @@ class Project < ApplicationRecord
scope :with_statistics, -> { includes(:statistics) }
scope :with_namespace, -> { includes(:namespace) }
scope :with_import_state, -> { includes(:import_state) }
scope :include_project_feature, -> { includes(:project_feature) }
scope :with_service, ->(service) { joins(service).eager_load(service) }
scope :with_shared_runners, -> { where(shared_runners_enabled: true) }
scope :with_container_registry, -> { where(container_registry_enabled: true) }
......
......@@ -18,6 +18,7 @@ class SnippetInputAction
validates :file_path, presence: true
validates :content, presence: true, if: -> (action) { action.create_action? || action.update_action? }
validate :ensure_same_file_path_and_previous_path, if: :update_action?
validate :ensure_different_file_path_and_previous_path, if: :move_action?
validate :ensure_allowed_action
def initialize(action: nil, previous_path: nil, file_path: nil, content: nil, allowed_actions: nil)
......@@ -52,6 +53,12 @@ class SnippetInputAction
errors.add(:file_path, "can't be different from the previous_path attribute")
end
def ensure_different_file_path_and_previous_path
return if previous_path != file_path
errors.add(:file_path, 'must be different from the previous_path attribute')
end
def ensure_allowed_action
return if @allowed_actions.empty?
......
......@@ -3,11 +3,11 @@
module FindGroupProjects
extend ActiveSupport::Concern
def group_projects_for(user:, group:)
def group_projects_for(user:, group:, only_owned: true)
GroupProjectsFinder.new(
group: group,
current_user: user,
options: { include_subgroups: true, only_owned: true }
options: { include_subgroups: true, only_owned: only_owned }
).execute
end
end
......@@ -42,6 +42,14 @@ class GroupPolicy < BasePolicy
@subject.subgroup_creation_level == ::Gitlab::Access::MAINTAINER_SUBGROUP_ACCESS
end
condition(:design_management_enabled) do
group_projects_for(user: @user, group: @subject, only_owned: false).any? { |p| p.design_management_enabled? }
end
rule { design_management_enabled }.policy do
enable :read_design_activity
end
rule { public_group }.policy do
enable :read_group
enable :read_package
......@@ -70,6 +78,10 @@ class GroupPolicy < BasePolicy
enable :read_board
end
rule { ~can?(:read_group) }.policy do
prevent :read_design_activity
end
rule { has_access }.enable :read_namespace
rule { developer }.policy do
......
......@@ -545,11 +545,13 @@ class ProjectPolicy < BasePolicy
rule { can?(:read_issue) }.policy do
enable :read_design
enable :read_design_activity
end
# Design abilities could also be prevented in the issue policy.
rule { design_management_disabled }.policy do
prevent :read_design
prevent :read_design_activity
prevent :create_design
prevent :destroy_design
end
......
......@@ -9,9 +9,11 @@ class TestSuiteEntity < Grape::Entity
expose :failed_count
expose :skipped_count
expose :error_count
expose :suite_error
expose :test_cases, using: TestCaseEntity do |test_suite|
test_suite.suite_error ? [] : test_suite.test_cases.values.flat_map(&:values)
with_options if: -> (_, opts) { opts[:details] } do |test_suite|
expose :suite_error
expose :test_cases, using: TestCaseEntity do |test_suite|
test_suite.suite_error ? [] : test_suite.test_cases.values.flat_map(&:values)
end
end
end
......@@ -97,23 +97,16 @@ class EventCreateService
end
def save_designs(current_user, create: [], update: [])
created = create.group_by(&:project).flat_map do |project, designs|
Feature.enabled?(:design_activity_events, project) ? designs : []
end.to_set
updated = update.group_by(&:project).flat_map do |project, designs|
Feature.enabled?(:design_activity_events, project) ? designs : []
end.to_set
return [] if created.empty? && updated.empty?
return [] unless Feature.enabled?(:design_activity_events)
records = created.zip([:created].cycle) + updated.zip([:updated].cycle)
records = create.zip([:created].cycle) + update.zip([:updated].cycle)
return [] if records.empty?
create_record_events(records, current_user)
end
def destroy_designs(designs, current_user)
designs = designs.select do |design|
Feature.enabled?(:design_activity_events, design.project)
end
return [] unless Feature.enabled?(:design_activity_events)
return [] unless designs.present?
create_record_events(designs.zip([:destroyed].cycle), current_user)
......
......@@ -38,7 +38,8 @@ module Snippets
# Once we can perform different operations through this service
# we won't need to keep track of the `content` and `file_name` fields
if snippet_files.any?
params.merge!(content: snippet_files[0].content, file_name: snippet_files[0].file_path)
params[:content] = snippet_files[0].content if snippet_files[0].content
params[:file_name] = snippet_files[0].file_path
end
snippet.assign_attributes(params)
......
......@@ -7,6 +7,8 @@
- if event.wiki_page?
= render "events/event/wiki", event: event
- elsif event.design?
= render 'events/event/design', event: event
- elsif event.created_project_action?
= render "events/event/created_project", event: event
- elsif event.push_action?
......
= icon_for_profile_event(event)
= event_user_info(event)
.event-title.d-flex.flex-wrap
= inline_event_icon(event)
%span.event-type.d-inline-block.append-right-4{ class: event.action_name }
= event.action_name
= event_design_title_html(event)
= render "events/event_scope", event: event
......@@ -25,6 +25,8 @@
%meta{ 'http-equiv' => 'X-UA-Compatible', content: 'IE=edge' }
= render 'layouts/startup_js'
-# Open Graph - http://ogp.me/
%meta{ property: 'og:type', content: "object" }
%meta{ property: 'og:site_name', content: site_name }
......
- return unless page_startup_api_calls.present?
= javascript_tag nonce: true do
:plain
var gl = window.gl || {};
gl.startup_calls = #{page_startup_api_calls.to_json};
if (gl.startup_calls && window.fetch) {
Object.keys(gl.startup_calls).forEach(apiCall => {
gl.startup_calls[apiCall] = {
fetchCall: fetch(apiCall)
};
});
}
......@@ -4,6 +4,9 @@
- project = local_assigns.fetch(:project) { @project }
- content_url = local_assigns.fetch(:content_url) { @tree.readme ? project_blob_path(@project, tree_join(@ref, @tree.readme.path)) : project_tree_path(@project, @ref) }
- show_auto_devops_callout = show_auto_devops_callout?(@project)
- add_page_startup_api_call logs_file_project_ref_path(@project, ref, @path, format: "json", offset: 0)
- if @tree.readme
- add_page_startup_api_call project_blob_path(@project, tree_join(@ref, @tree.readme.path), viewer: "rich", format: "json")
#tree-holder.tree-holder.clearfix
.nav-block
......
......@@ -17,4 +17,6 @@
= event_filter_link EventFilter::COMMENTS, _('Comments'), s_('EventFilterBy|Filter by comments')
- if Feature.enabled?(:wiki_events) && (@project.nil? || @project.has_wiki?)
= event_filter_link EventFilter::WIKI, _('Wiki'), s_('EventFilterBy|Filter by wiki')
- if event_filter_visible(:designs)
= event_filter_link EventFilter::DESIGNS, _('Designs'), s_('EventFilterBy|Filter by designs')
= event_filter_link EventFilter::TEAM, _('Team'), s_('EventFilterBy|Filter by team')
---
title: Support first_name and last_name attributes in LDAP user sync
merge_request: 29542
author:
type: added
---
title: SpamVerdictService can call external spam check endpoint
merge_request: 31449
author:
type: added
---
title: "[Frontend] Resolvable design discussions"
merge_request: 32399
author:
type: added
---
title: Add a GraphQL mutation for toggling the resolved state of a Discussion
merge_request: 32934
author:
type: added
---
title: Allow customization of badge key_text and key_width
merge_request: 29381
author: Fabian Schneider @fabsrc
type: added
---
title: Resolve Add a button to assign users who have commented on an issue
merge_request: 23883
author:
type: added
---
title: Add api.js methods to update issues and merge requests
merge_request: 32893
author:
type: added
---
title: Resolve incorrect x-axis padding on the Environments Dashboard
merge_request: 32533
author:
type: fixed
---
title: Added node size to cluster index
merge_request: 32435
author:
type: changed
---
title: Don't hide Commit tab in Web IDE when there are no changes yet
merge_request: 32979
author:
type: added
---
title: Add the container expiration policy attribute to the project GraphQL type
merge_request: 32100
author:
type: added
---
title: Add container expiration policy objects to the GraphQL API
merge_request: 32944
author:
type: added
---
title: Show tooltip on error detail page when hovering over dates
merge_request: 34506
author:
type: added
---
title: Fix incorrect commit search results returned when searching with ref
merge_request: 33216
author:
type: fixed
---
title: Convert `:release` yaml to `release-cli` commands
merge_request: 34261
author:
type: added
---
title: Show more context in unresolved jump button
merge_request: 32737
author:
type: changed
---
title: Implement displaying downstream pipeline error details
merge_request: 32844
author:
type: fixed
---
title: Add rake task to verify encrypted data through secrets
merge_request: 21851
author:
type: added
---
title: Add API support for sharing groups with groups
merge_request: 32008
author:
type: added
---
title: Expose `release_links.type` via API
merge_request: 33154
author:
type: changed
---
title: Add `link_type` to `ReleaseLink` GraphQL type
merge_request: 33386
author:
type: added
---
title: Add link_type column to release_links table
merge_request: 33156
author:
type: changed
---
title: Add secret detection template
merge_request: 33869
author:
type: added
---
title: Extract featurable concern from ProjectFeature
merge_request: 31700
author: Alexander Randa
type: other
---
title: Group authorization refresh to consider shared groups
merge_request: 31204
author:
type: fixed
---
title: Add database migrations to design_management_designs.filename to enforce
a 255 character limit, and modify any filenames that exceed that limit
merge_request: 33565
author:
type: changed
---
title: Add DS detection of build.gradle.kts
merge_request: !32727
author:
type: fixed
---
title: Add explicit mention of Merge request in Slack message
merge_request: 33152
author:
type: changed
---
title: Fix 'Active' checkbox text in Pipeline Schedule form to be a label
merge_request: 27054
author: Jonston Chan
type: fixed
---
title: Change copy of webhooks / integration help text
merge_request: 34301
author:
type: changed
---
title: Conan package registry support for the conan_export.tgz file
merge_request: 32866
author:
type: fixed
---
title: Change legends in monitor dashboards to tabular layout
merge_request: 30131
author:
type: changed
---
title: Added delete action for Dashboard Annotations in GraphQL
merge_request: 33468
author:
type: added
---
title: Rename Add Designs button
merge_request: 33491
author:
type: changed
---
title: Resolve image overflow at releases list panel
merge_request: 32307
author:
type: fixed
---
title: Removed UltraAuth integration for OmniAuth
merge_request: 29330
author: Kartikey Tanna
type: removed
---
title: Add CPU, memory usage charts to self monitoring default dashboard
merge_request: 33532
author:
type: changed
---
title: Add ability to filter self monitoring resource usage charts by instance name
merge_request: 34084
author:
type: changed
---
title: Improve spacing and wrapping of group actions buttons and stats in group list
view
merge_request: 32786
author:
type: fixed
---
title: Fix issues with scroll on iOS / iPad OS
merge_request: 34486
author:
type: fixed
---
title: Enable the `in this group` action in the Search dropdown
merge_request: 31939
author:
type: changed
---
title: Remove all search autocomplete for groups/projects/other
merge_request: 31187
author:
type: removed
---
title: Update red hex values to match GitLab UI
merge_request: 34544
author:
type: other
---
title: Alerts list pagination
merge_request: 33073
author:
type: added
---
title: Provide `__range` variable for Prometheus queries
merge_request: 33521
author:
type: added
---
title: Move the Members section from settings to the side nav for projects
merge_request: 32667
author:
type: changed
---
title: Add timezone display to alert based issue start time
merge_request: 32702
author:
type: added
---
title: Add Usage Ping count for all searches
merge_request: 32111
author:
type: changed
---
title: Add metrics dashboard name to document title
merge_request: 30392
author:
type: added
---
title: Display dates on metrics dashboards in UTC time zone
merge_request: 32746
author:
type: added
---
title: Update operations metrics settings title and description to make them general
merge_request: 32494
author:
type: changed
---
title: Return 404 response when redirecting request with invalid url.
merge_request: 33492
author:
type: fixed
---
title: Set fingerprints and increment events count for Alert Management alerts
merge_request: 32613
author:
type: added
---
title: Fix tabbing through form fields in projects/new flow
merge_request: 33209
author:
type: fixed
---
title: Allow user to add custom links to their metrics dashboard panels
merge_request: 32646
author:
type: added
---
title: Add DAG visualization MVC
merge_request: 33958
author:
type: added
---
title: Add mutation to create commits in GraphQL
merge_request: 31102
author:
type: added
---
title: Add mutation to create a merge request in GraphQL
merge_request: 31867
author:
type: added
---
title: Add user root query to GraphQL API
merge_request: 33041
author:
type: added
---
title: Adds groupMembership and projectMembership to GraphQL API
merge_request: 33049
author:
type: added
---
title: Add root users query to GraphQL API
merge_request: 33195
author:
type: added
---
title: Add model for project level security auto-fix settings
merge_request: 32577
author:
type: added
---
title: Reduce redundant queries for Search API users scope.
merge_request: 33795
author:
type: performance
---
title: Add todo when alert is assigned to a user
merge_request: 34104
author:
type: added
---
title: Store Todo resolution method
merge_request: 32753
author:
type: added
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册