Commit fb3b0edf authored by Fatih Acet's avatar Fatih Acet

Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ee into 5656-new-syntax-support-FE

parents 8acfd615 49410a8c
# Backend Maintainers are the default for all ruby files
*.rb @ayufan @DouweM @dzaporozhets @grzesiek @nick.thomas @rspeicher @rymai @smcgivern
*.rake @ayufan @DouweM @dzaporozhets @grzesiek @nick.thomas @rspeicher @rymai @smcgivern
*.rb @ayufan @dbalexandre @DouweM @dzaporozhets @godfat @grzesiek @nick.thomas @rspeicher @rymai @smcgivern
*.rake @ayufan @dbalexandre @DouweM @dzaporozhets @godfat @grzesiek @nick.thomas @rspeicher @rymai @smcgivern
# Technical writing team are the default reviewers for everything in `doc/`
/doc/ @axil @marcia
......
Please view this file on the master branch, on stable branches it's out of date.
## 11.6.0 (2018-12-22)
### Security (7 changes)
- Switch from CBC to GCM for Geo logout tokens. !8518
- Prevent reporter roles from viewing the Jaeger tracing settings page.
- Sanitize tracing external_urls before saving to DB and when displaying the URL to prevent XSS issues.
- Fix IDOR at /drafts/publish.
- Authorize users when listing board users and milestones.
- Resolve: Guest can set weight of a new issue.
- Fixes XSS with merge request approvers selection.
### Fixed (27 changes, 2 of them are from the community)
- Ensure that avatars in approvals have correct tooltip. !6269
- Geo: Fix push to secondary over SSH for LFS. !8044
- Don't show packages tab and settings for starter license. !8270
- Makes the vulnerability name on the Group Security Dashboard a button for better A11y. !8341
- Used the iid instead of the id for linked issues on the Group Security Dashboard. !8357
- Show navigation line separator when instance etrics is disabled. !8379 (George Tsiolis)
- Fix project deploy key creation and deletion as admin. !8432
- Changes initial state for disabled prometheus integrations. !8434
- Fix a typo in Admin: intergration -> integration. !8444 (Vincent AUBERT)
- Geo: Moving registry deletion into the job that deletes the files and project record. !8480
- Parameterize alerting rules with variables. !8481
- Fix PostReceive failing for project mirrors missing local branch. !8495
- Rails 5: Fix the check whether the database is in read-only mode. !8594
- Raisl 5: Fix Gitlab::Database::LoadBalancing#caught_up? check. !8595
- Renders upstream and downstream pipelines in the main pipeline graph. !8607
- Fix issue board api with special milestones. !8653
- fix pod dropdown not switching pod logs. !8660
- Geo - Respect the next retry time when re-verifying failed repositories. !8661
- Update elasticsearch system check to check for new supported versions. !8683
- Handle null start or due dates for dates sourcing milestone in Epics. !8689
- Fixed license managment path in MR widget for fork cases. !8700
- Fix gitlab:geo:check rake task. !8714
- Fix ability to choose shards for selective sync. !8717
- Add Rails.version to the Geo cache keys. !8775
- Support older NGINX version forwarding the client certificate for smartcard auth. !8784
- Remove duplicated smartcard login button. !8793
- Disable password autocomplete in mirror form fill.
### Deprecated (1 change)
- Deprecate non-hashed repository storage for Geo installations. !8739
### Changed (17 changes, 1 of them is from the community)
- Adds Group SAML metadata endpoint. !5782
- Group SAML SSO page warns when linking account. !8295
- Change the delete custom metric alert. !8430
- Replace weight icon. !8448 (George Tsiolis)
- Switch snowplows stateStorageStrategy to cookie. !8461
- Move merge request approval settings. !8493
- Geo: Constantly reverify repositories. !8550
- Add file and line numbers to issues created from SAST vulnerabilities. !8578
- Redesign MR header sections and approvals (EE). !8593
- Add packages_enabled attribute to Projects API. !8604
- Run geo check task from gitlab check. !8616
- Change issue create weight dropdown to an input. !8648
- Add epics state filtering in roadmap view. !8658
- Users can unlink Group SAML from accounts page. !8682
- Update casing in Built-in on project templates tab. !8688
- Epic issue list and related issue list re-design.
- Add sort direction button with sort dropdown for Epics and Roadmap.
### Performance (5 changes, 3 of them are from the community)
- Remove partial index for projects on mirror and mirror_last_update_at. !8585
- Enable some frozen string in ee/app. !8667 (gfyoung)
- Remove redundant indices for is_sample on push_rules and next_execution_timestamp on project_mirror_data. !8695
- Enable some frozen string in ee/app. (gfyoung)
- Enable some frozen string in ee/app. (gfyoung)
### Added (10 changes)
- Add support for Group-level project templates. !6878
- Added web terminals to Web IDE. !7386
- Promote an Issue to an Epic using quick action. !8051
- Smartcard authentication. !8120
- Adds Security dashboard empty state. !8443
- Add vulnerability history at group level. !8603
- Adds group security dashboard metrics chart. !8631
- Add milestones autocomplete for epics. !8632
- Parse and store dependency scanning reports in database. !8642
- Adds EE store to handle upstream & downstream pipelines.
### Other (13 changes, 4 of them are from the community)
- Add subscription table to GitLab.com billing areas. !7885
- UX improvements for the group security dashboard. !8217
- Restyles the dismissed vulnerabilities. !8401
- Adds PHILOSOPHY.md and references GitLab Product Handbook. !8515
- Make sidekiq-cluster play well with Sidekiq 5.2.2+. !8522
- Rails5: Passing a class as a value in an Active Record query is deprecated. !8540 (Jasper Maes)
- render :nothing option is deprecated, Use head method to respond with empty response body. !8560 (Jasper Maes)
- Add help page link for licence management in CI/CD settings. !8561 (George Tsiolis)
- Re-orders the Group Security Dashboard. !8624
- Move EE only differences for finders. !8629 (George Tsiolis)
- Add count of projects with at least one package to a usage ping data. !8641
- Added recommendations for handling deleted documents in Elasticsearch.
- Use new information-o icon for Security Dashboard.
## 11.5.5 (2018-12-20)
- No changes.
## 11.5.3 (2018-12-06)
- No changes.
......@@ -275,6 +383,10 @@ Please view this file on the master branch, on stable branches it's out of date.
- API: Allow issue weight parameter to be greater than or equal to zero.
## 11.3.14 (2018-12-20)
- No changes.
## 11.3.13 (2018-12-13)
- No changes.
......
This diff is collapsed.
......@@ -58,6 +58,18 @@ their contributions accepted by meeting our [Definition of done][done].
What you can expect from them is described at https://about.gitlab.com/roles/merge-request-coach/.
### Milestones on community contribution issues
The milestone of an issue that is currently being worked on by a community contributor
should not be set to a named GitLab milestone (e.g. 11.7, 11.8), until the associated
merge request is very close to being merged, and we will likely know in which named
GitLab milestone the issue will land. There are many factors that influence when
a community contributor finishes an issue, or even at all. So we should set this
milestone only when we have more certainty.
Note this only applies to issues currently assigned to community contributors. For
issues assigned to GitLabbers, we are [ambitious in assigning milestones to issues](https://about.gitlab.com/direction/#how-we-plan-releases).
## Assigning issues
If an issue is complex and needs the attention of a specific person, assignment is a good option but assigning issues might discourage other people from contributing to that issue. We need all the contributions we can get so this should never be discouraged. Also, an assigned person might not have time for a few weeks, so others should feel free to takeover.
......
11.6.0-pre
11.7.0-pre
......@@ -82,7 +82,7 @@ export function insertMarkdownText({
tag,
cursorOffset,
blockTag,
selected,
selected = '',
wrap,
select,
}) {
......@@ -212,7 +212,7 @@ export function addMarkdownListeners(form) {
blockTag: $this.data('mdBlock'),
wrap: !$this.data('mdPrepend'),
select: $this.data('mdSelect'),
tagContent: $this.data('mdTagContent').toString(),
tagContent: $this.data('mdTagContent'),
});
});
}
......
......@@ -222,16 +222,6 @@ export default {
return this.line;
},
commit() {
if (!this.discussion.for_commit) {
return null;
}
return {
id: this.discussion.commit_id,
url: this.discussion.discussion_path,
};
},
},
watch: {
isReplying() {
......@@ -397,7 +387,6 @@ Please check your network connection and try again.`;
:note="componentData(initialDiscussion)"
:line="line"
:help-page-path="helpPagePath"
:commit="commit"
@handleDeleteNote="deleteNoteHandler"
>
<note-edited-text
......
......@@ -2,8 +2,6 @@
import $ from 'jquery';
import { mapGetters, mapActions } from 'vuex';
import { escape } from 'underscore';
import { truncateSha } from '~/lib/utils/text_utility';
import { s__, sprintf } from '~/locale';
import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue';
import Flash from '../../flash';
import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue';
......@@ -39,11 +37,6 @@ export default {
required: false,
default: '',
},
commit: {
type: Object,
required: false,
default: () => null,
},
},
data() {
return {
......@@ -80,24 +73,6 @@ export default {
isTarget() {
return this.targetNoteHash === this.noteAnchorId;
},
actionText() {
if (this.commit) {
const { id, url } = this.commit;
const linkStart = `<a class="commit-sha monospace" href="${escape(url)}">`;
const linkEnd = '</a>';
return sprintf(
s__('MergeRequests|commented on commit %{linkStart}%{commitId}%{linkEnd}'),
{
commitId: truncateSha(id),
linkStart,
linkEnd,
},
false,
);
}
return '<span class="d-none d-sm-inline">&middot;</span>';
},
},
created() {
......@@ -229,9 +204,14 @@ export default {
</div>
<div class="timeline-content">
<div class="note-header">
<note-header v-once :author="author" :created-at="note.created_at" :note-id="note.id">
<slot slot="note-header-info" name="note-header-info"></slot>
<span v-html="actionText"></span>
<note-header
v-once
:author="author"
:created-at="note.created_at"
:note-id="note.id"
action-text="commented"
>
<slot slot="note-header-info" name="note-header-info"> </slot>
</note-header>
<note-actions
:author-id="author.id"
......
......@@ -79,11 +79,12 @@ Sidebar.prototype.sidebarToggleClicked = function(e, triggered) {
Sidebar.prototype.toggleTodo = function(e) {
var $btnText, $this, $todoLoading, ajaxType, url;
$this = $(e.currentTarget);
ajaxType = $this.attr('data-delete-path') ? 'delete' : 'post';
if ($this.attr('data-delete-path')) {
url = '' + $this.attr('data-delete-path');
ajaxType = $this.data('deletePath') ? 'delete' : 'post';
if ($this.data('deletePath')) {
url = '' + $this.data('deletePath');
} else {
url = '' + $this.data('url');
url = '' + $this.data('createPath');
}
$this.tooltip('hide');
......@@ -119,14 +120,14 @@ Sidebar.prototype.todoUpdateDone = function(data) {
.removeClass('is-loading')
.enable()
.attr('aria-label', $el.data(`${attrPrefix}Text`))
.attr('data-delete-path', deletePath)
.attr('title', $el.data(`${attrPrefix}Text`));
.attr('title', $el.data(`${attrPrefix}Text`))
.data('deletePath', deletePath);
if ($el.hasClass('has-tooltip')) {
$el.tooltip('_fixTitle');
}
if ($el.data(`${attrPrefix}Icon`)) {
if (typeof $el.data('isCollapsed') !== 'undefined') {
$elText.html($el.data(`${attrPrefix}Icon`));
} else {
$elText.text($el.data(`${attrPrefix}Text`));
......
......@@ -81,7 +81,7 @@ export default {
</p>
<ul>
<li>Your repository does not have a corresponding <code>serverless.yml</code> file.</li>
<li>Your <code>gitlab-ci.yml</code> file is not properly configured.</li>
<li>Your <code>.gitlab-ci.yml</code> file is not properly configured.</li>
<li>
The functions listed in the <code>serverless.yml</code> file don't match the namespace
of your cluster.
......
......@@ -71,7 +71,7 @@ export default class SidebarStore {
}
findAssignee(findAssignee) {
return this.assignees.filter(assignee => assignee.id === findAssignee.id)[0];
return this.assignees.find(assignee => assignee.id === findAssignee.id);
}
removeAssignee(removeAssignee) {
......
......@@ -5,7 +5,6 @@ module IssuableActions
include Gitlab::Utils::StrongMemoize
included do
before_action :labels, only: [:show, :new, :edit]
before_action :authorize_destroy_issuable!, only: :destroy
before_action :authorize_admin_issuable!, only: :bulk_update
end
......@@ -25,7 +24,10 @@ module IssuableActions
def show
respond_to do |format|
format.html
format.html do
@issuable_sidebar = serializer.represent(issuable, serializer: 'sidebar') # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
format.json do
render json: serializer.represent(issuable, serializer: params[:serializer])
end
......@@ -168,10 +170,6 @@ module IssuableActions
end
end
def labels
@labels ||= LabelsFinder.new(current_user, project_id: @project.id).execute # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
def authorize_destroy_issuable!
unless can?(current_user, :"destroy_#{issuable.to_ability_name}", issuable)
return access_denied!
......
......@@ -8,7 +8,7 @@ class Projects::MergeRequests::ConflictsController < Projects::MergeRequests::Ap
def show
respond_to do |format|
format.html do
labels
@issuable_sidebar = serializer.represent(@merge_request, serializer: 'sidebar')
end
format.json do
......@@ -60,9 +60,15 @@ class Projects::MergeRequests::ConflictsController < Projects::MergeRequests::Ap
end
end
private
def authorize_can_resolve_conflicts!
@conflicts_list = ::MergeRequests::Conflicts::ListService.new(@merge_request)
return render_404 unless @conflicts_list.can_be_resolved_by?(current_user)
end
def serializer
MergeRequestSerializer.new(current_user: current_user, project: project)
end
end
......@@ -24,8 +24,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
format.html
format.json do
render json: {
html: view_to_html_string("projects/merge_requests/_merge_requests"),
labels: @labels.as_json(methods: :text_color)
html: view_to_html_string("projects/merge_requests/_merge_requests")
}
end
end
......@@ -45,8 +44,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
@noteable = @merge_request
@commits_count = @merge_request.commits_count
labels
@issuable_sidebar = serializer.represent(@merge_request, serializer: 'sidebar')
set_pipeline_variables
......
......@@ -26,6 +26,18 @@ module ApplicationSettingsHelper
end
end
def all_protocols_enabled?
Gitlab::CurrentSettings.enabled_git_access_protocol.blank?
end
def ssh_enabled?
all_protocols_enabled? || enabled_protocol == 'ssh'
end
def http_enabled?
all_protocols_enabled? || enabled_protocol == 'http'
end
def enabled_project_button(project, protocol)
case protocol
when 'ssh'
......
......@@ -23,31 +23,42 @@ module IssuablesHelper
end
end
def sidebar_due_date_tooltip_label(issuable)
if issuable.due_date
"#{_('Due date')}<br />#{due_date_remaining_days(issuable)}"
else
_('Due date')
def sidebar_milestone_tooltip_label(milestone)
return _('Milestone') unless milestone.present?
[milestone[:title], sidebar_milestone_remaining_days(milestone) || _('Milestone')].join('<br/>')
end
def sidebar_milestone_remaining_days(milestone)
due_date_with_remaining_days(milestone[:due_date], milestone[:start_date])
end
def sidebar_due_date_tooltip_label(due_date)
[_('Due date'), due_date_with_remaining_days(due_date)].compact.join('<br/>')
end
def due_date_with_remaining_days(due_date, start_date = nil)
return unless due_date
"#{due_date.to_s(:medium)} (#{remaining_days_in_words(due_date, start_date)})"
end
def due_date_remaining_days(issuable)
remaining_days_in_words = remaining_days_in_words(issuable)
def sidebar_label_filter_path(base_path, label_name)
query_params = { label_name: [label_name] }.to_query
"#{issuable.due_date.to_s(:medium)} (#{remaining_days_in_words})"
"#{base_path}?#{query_params}"
end
def multi_label_name(current_labels, default_label)
if current_labels && current_labels.any?
title = current_labels.first.try(:title)
return default_label if current_labels.blank?
title = current_labels.first.try(:title) || current_labels.first[:title]
if current_labels.size > 1
"#{title} +#{current_labels.size - 1} more"
else
title
end
else
default_label
end
end
def issuable_json_path(issuable)
......@@ -197,19 +208,11 @@ module IssuablesHelper
output.join.html_safe
end
# rubocop: disable CodeReuse/ActiveRecord
def issuable_todo(issuable)
if current_user
current_user.todos.find_by(target: issuable, state: :pending)
end
end
# rubocop: enable CodeReuse/ActiveRecord
def issuable_labels_tooltip(labels, limit: 5)
first, last = labels.partition.with_index { |_, i| i < limit }
if labels && labels.any?
label_names = first.collect(&:name)
label_names = first.collect { |label| label.fetch(:title) }
label_names << "and #{last.size} more" unless last.empty?
label_names.join(', ')
......@@ -356,12 +359,6 @@ module IssuablesHelper
issuable.model_name.human.downcase
end
def selected_labels
Array(params[:label_name]).map do |label_name|
Label.new(title: label_name)
end
end
def has_filter_bar_param?
finder.class.scalar_params.any? { |p| params[p].present? }
end
......@@ -386,19 +383,20 @@ module IssuablesHelper
params[:issuable_template] if issuable_templates(issuable).any? { |template| template[:name] == params[:issuable_template] }
end
def issuable_todo_button_data(issuable, todo, is_collapsed)
def issuable_todo_button_data(issuable, is_collapsed)
{
todo_text: "Add todo",
mark_text: "Mark todo as done",
todo_icon: (is_collapsed ? sprite_icon('todo-add') : nil),
mark_icon: (is_collapsed ? sprite_icon('todo-done', css_class: 'todo-undone') : nil),
issuable_id: issuable.id,
issuable_type: issuable.class.name.underscore,
url: project_todos_path(@project),
delete_path: (dashboard_todo_path(todo) if todo),
placement: (is_collapsed ? 'left' : nil),
container: (is_collapsed ? 'body' : nil),
boundary: 'viewport'
todo_text: _('Add todo'),
mark_text: _('Mark todo as done'),
todo_icon: sprite_icon('todo-add'),
mark_icon: sprite_icon('todo-done', css_class: 'todo-undone'),
issuable_id: issuable[:id],
issuable_type: issuable[:type],
create_path: issuable[:create_todo_path],
delete_path: issuable.dig(:current_user, :todo, :delete_path),
placement: is_collapsed ? 'left' : nil,
container: is_collapsed ? 'body' : nil,
boundary: 'viewport',
is_collapsed: is_collapsed
}
end
......@@ -418,29 +416,22 @@ module IssuablesHelper
end
end
def issuable_sidebar_options(issuable, can_edit_issuable)
def issuable_sidebar_options(issuable)
{
endpoint: "#{issuable_json_path(issuable)}?serializer=sidebar",
toggleSubscriptionEndpoint: toggle_subscription_path(issuable),
moveIssueEndpoint: move_namespace_project_issue_path(namespace_id: issuable.project.namespace.to_param, project_id: issuable.project, id: issuable),
projectsAutocompleteEndpoint: autocomplete_projects_path(project_id: @project.id),
editable: can_edit_issuable,
currentUser: UserSerializer.new.represent(current_user),
endpoint: "#{issuable[:issuable_json_path]}?serializer=sidebar_extras",
toggleSubscriptionEndpoint: issuable[:toggle_subscription_path],
moveIssueEndpoint: issuable[:move_issue_path],
projectsAutocompleteEndpoint: issuable[:projects_autocomplete_path],
editable: issuable.dig(:current_user, :can_edit),
currentUser: issuable[:current_user],
rootPath: root_path,
fullPath: @project.full_path
fullPath: issuable[:project_full_path]
}
end
def parent
@project || @group
end
def issuable_milestone_tooltip_title(issuable)
if issuable.milestone
milestone_tooltip = milestone_tooltip_title(issuable.milestone)
_('Milestone') + (milestone_tooltip ? ': ' + milestone_tooltip : '')
end
end
end
IssuablesHelper.prepend(EE::IssuablesHelper)
......@@ -114,12 +114,6 @@ module MilestonesHelper
end
end
def milestone_tooltip_title(milestone)
if milestone
"#{milestone.title}<br />#{milestone_tooltip_due_date(milestone)}"
end
end
def milestone_time_for(date, date_type)
title = date_type == :start ? "Start date" : "End date"
......@@ -173,7 +167,7 @@ module MilestonesHelper
def milestone_tooltip_due_date(milestone)
if milestone.due_date
"#{milestone.due_date.to_s(:medium)} (#{remaining_days_in_words(milestone)})"
"#{milestone.due_date.to_s(:medium)} (#{remaining_days_in_words(milestone.due_date, milestone.start_date)})"
else
_('Milestone')
end
......
......@@ -85,7 +85,7 @@ module NotesHelper
diffs_project_merge_request_path(discussion.project, discussion.noteable, path_params)
elsif discussion.for_commit?
anchor = discussion.diff_discussion? ? discussion.line_code : "note_#{discussion.first_note.id}"
anchor = discussion.line_code if discussion.diff_discussion?
project_commit_path(discussion.project, discussion.noteable, anchor: anchor)
end
......
......@@ -228,7 +228,7 @@ module Clusters
return unless namespace_changed?
run_after_commit do
ClusterPlatformConfigureWorker.perform_async(cluster_id)
ClusterConfigureWorker.perform_async(cluster_id)
end
end
end
......
......@@ -5,7 +5,6 @@ class DashboardGroupMilestone < GlobalMilestone
attr_reader :group_name
override :initialize
def initialize(milestone)
super(milestone.title, Array(milestone))
......
......@@ -306,6 +306,7 @@ class Namespace < ActiveRecord::Base
def write_projects_repository_config
all_projects.find_each do |project|
project.write_repository_config
project.track_project_repository
end
end
end
......
......@@ -1244,10 +1244,8 @@ class Project < ActiveRecord::Base
end
def track_project_repository
return unless hashed_storage?(:repository)
project_repo = project_repository || build_project_repository
project_repo.update!(shard_name: repository_storage, disk_path: disk_path)
repository = project_repository || build_project_repository
repository.update!(shard_name: repository_storage, disk_path: disk_path)
end
def create_repository(force: false)
......
......@@ -1422,6 +1422,10 @@ class User < ActiveRecord::Base
todos.where(id: ids)
end
def pending_todo_for(target)
todos.find_by(target: target, state: :pending)
end
# @deprecated
alias_method :owned_or_masters_groups, :owned_or_maintainers_groups
......
......@@ -44,14 +44,14 @@ module EntityDateHelper
# It returns "Upcoming" for upcoming entities
# If due date is provided, it returns "# days|weeks|months remaining|ago"
# If start date is provided and elapsed, with no due date, it returns "# days elapsed"
def remaining_days_in_words(entity)
if entity.try(:expired?)
def remaining_days_in_words(due_date, start_date = nil)
if due_date&.past?
content_tag(:strong, 'Past due')
elsif entity.try(:upcoming?)
elsif start_date&.future?
content_tag(:strong, 'Upcoming')
elsif entity.due_date
is_upcoming = (entity.due_date - Date.today).to_i > 0
time_ago = time_ago_in_words(entity.due_date)
elsif due_date
is_upcoming = (due_date - Date.today).to_i > 0
time_ago = time_ago_in_words(due_date)
# https://gitlab.com/gitlab-org/gitlab-ce/issues/49440
#
......@@ -63,8 +63,8 @@ module EntityDateHelper
remaining_or_ago = is_upcoming ? _("remaining") : _("ago")
"#{content} #{remaining_or_ago}".html_safe
elsif entity.start_date && entity.start_date.past?
days = entity.elapsed_days
elsif start_date&.past?
days = (Date.today - start_date).to_i
"#{content_tag(:strong, days)} #{'day'.pluralize(days)} elapsed".html_safe
end
end
......
# frozen_string_literal: true
class IssuableSidebarBasicEntity < Grape::Entity
include RequestAwareEntity
expose :id
expose :type do |issuable|
issuable.to_ability_name
end
expose :author_id
expose :project_id do |issuable|
issuable.project.id
end
expose :discussion_locked
expose :reference do |issuable|
issuable.to_reference(issuable.project, full: true)
end
expose :milestone, using: ::API::Entities::Milestone
expose :labels, using: LabelEntity
expose :current_user, if: lambda { |_issuable| current_user } do
expose :current_user, merge: true, using: API::Entities::UserBasic
expose :todo, using: IssuableSidebarTodoEntity do |issuable|
current_user.pending_todo_for(issuable)
end
expose :can_edit do |issuable|
can?(current_user, :"admin_#{issuable.to_ability_name}", issuable.project)
end
expose :can_move do |issuable|
issuable.can_move?(current_user)
end
expose :can_admin_label do |issuable|
can?(current_user, :admin_label, issuable.project)
end
end
expose :issuable_json_path do |issuable|
if issuable.is_a?(MergeRequest)
project_merge_request_path(issuable.project, issuable.iid, :json)
else
project_issue_path(issuable.project, issuable.iid, :json)
end
end
expose :namespace_path do |issuable|
issuable.project.namespace.full_path
end
expose :project_path do |issuable|
issuable.project.path
end
expose :project_full_path do |issuable|
issuable.project.full_path
end
expose :project_issuables_path do |issuable|
project = issuable.project
namespace = project.namespace
if issuable.is_a?(MergeRequest)
namespace_project_merge_requests_path(namespace, project)
else
namespace_project_issues_path(namespace, project)
end
end
expose :create_todo_path do |issuable|
project_todos_path(issuable.project)
end
expose :project_milestones_path do |issuable|
project_milestones_path(issuable.project, :json)
end
expose :project_labels_path do |issuable|
project_labels_path(issuable.project, :json, include_ancestor_groups: true)
end
expose :toggle_subscription_path do |issuable|
toggle_subscription_path(issuable)
end
expose :move_issue_path do |issuable|
move_namespace_project_issue_path(
namespace_id: issuable.project.namespace.to_param,
project_id: issuable.project,
id: issuable
)
end
expose :projects_autocomplete_path do |issuable|
autocomplete_projects_path(project_id: issuable.project.id)
end
private
def current_user
request.current_user
end
end
# frozen_string_literal: true
class IssuableSidebarEntity < Grape::Entity
include TimeTrackableEntity
class IssuableSidebarExtrasEntity < Grape::Entity
include RequestAwareEntity
prepend ::EE::IssuableSidebarEntity # rubocop: disable Cop/InjectEnterpriseEditionModule
include TimeTrackableEntity
expose :participants, using: ::API::Entities::UserBasic do |issuable|
issuable.participants(request.current_user)
......
# frozen_string_literal: true
class IssuableSidebarTodoEntity < Grape::Entity
include Gitlab::Routing
expose :id
expose :delete_path do |todo|
dashboard_todo_path(todo) if todo
end
end
......@@ -38,7 +38,7 @@ class IssueBoardEntity < Grape::Entity
end
expose :issue_sidebar_endpoint, if: -> (issue) { issue.project } do |issue|
project_issue_path(issue.project, issue, format: :json, serializer: 'sidebar')
project_issue_path(issue.project, issue, format: :json, serializer: 'sidebar_extras')
end
expose :toggle_subscription_endpoint, if: -> (issue) { issue.project } do |issue|
......
......@@ -2,13 +2,15 @@
class IssueSerializer < BaseSerializer
# This overrided method takes care of which entity should be used
# to serialize the `issue` based on `basic` key in `opts` param.
# to serialize the `issue` based on `serializer` key in `opts` param.
# Hence, `entity` doesn't need to be declared on the class scope.
def represent(issue, opts = {})
entity =
case opts[:serializer]
when 'sidebar'
IssueSidebarEntity
IssueSidebarBasicEntity
when 'sidebar_extras'
IssueSidebarExtrasEntity
when 'board'
IssueBoardEntity
else
......
# frozen_string_literal: true
class IssueSidebarBasicEntity < IssuableSidebarBasicEntity
expose :due_date
expose :confidential
end
IssueSidebarBasicEntity.prepend(EE::IssueSidebarBasicEntity)
# frozen_string_literal: true
class IssueSidebarEntity < IssuableSidebarEntity
prepend ::EE::IssueSidebarEntity # rubocop: disable Cop/InjectEnterpriseEditionModule
class IssueSidebarExtrasEntity < IssuableSidebarExtrasEntity
expose :assignees, using: API::Entities::UserBasic
end
IssueSidebarExtrasEntity.prepend(EE::IssueSidebarExtrasEntity)
# frozen_string_literal: true
class MergeRequestBasicEntity < IssuableSidebarEntity
class MergeRequestBasicEntity < Grape::Entity
expose :assignee_id
expose :merge_status
expose :merge_error
......
# frozen_string_literal: true
class MergeRequestBasicSerializer < BaseSerializer
entity MergeRequestBasicEntity
end
......@@ -7,9 +7,14 @@ class MergeRequestSerializer < BaseSerializer
def represent(merge_request, opts = {})
entity =
case opts[:serializer]
when 'basic', 'sidebar'
when 'sidebar'
MergeRequestSidebarBasicEntity
when 'sidebar_extras'
IssuableSidebarExtrasEntity
when 'basic'
MergeRequestBasicEntity
else # It's 'widget'
else
# fallback to widget for old poll requests without `serializer` set
MergeRequestWidgetEntity
end
......
# frozen_string_literal: true
class MergeRequestSidebarBasicEntity < IssuableSidebarBasicEntity
expose :assignee, if: lambda { |issuable| issuable.assignee } do
expose :assignee, merge: true, using: API::Entities::UserBasic
expose :can_merge do |issuable|
issuable.can_be_merged_by?(issuable.assignee)
end
end
end
......@@ -13,7 +13,7 @@ module Clusters
configure_kubernetes
cluster.save!
ClusterPlatformConfigureWorker.perform_async(cluster.id)
ClusterConfigureWorker.perform_async(cluster.id)
rescue Google::Apis::ServerError, Google::Apis::ClientError, Google::Apis::AuthorizationError => e
log_service_error(e.class.name, provider.id, e.message)
......
......@@ -83,6 +83,7 @@ module Projects
def update_repository_configuration
project.reload_repository!
project.write_repository_config
project.track_project_repository
end
def rename_transferred_documents
......
......@@ -83,7 +83,7 @@ module Projects
project.old_path_with_namespace = @old_path
write_repository_config(@new_path)
update_repository_configuration(@new_path)
execute_system_hooks
end
......@@ -108,8 +108,9 @@ module Projects
project.save!
end
def write_repository_config(full_path)
def update_repository_configuration(full_path)
project.write_repository_config(gl_full_path: full_path)
project.track_project_repository
end
def refresh_permissions
......@@ -125,7 +126,7 @@ module Projects
rollback_folder_move
project.reload
update_namespace_and_visibility(@old_namespace)
write_repository_config(@old_path)
update_repository_configuration(@old_path)
end
def rollback_folder_move
......
!!! 5
%html.devise-layout-html{ class: system_message_class }
= render "layouts/head"
%body.ui-indigo.login-page.application.navless{ data: { page: body_data_page } }
%body.ui-indigo.login-page.application.navless.qa-login-page{ data: { page: body_data_page } }
= header_message
.page-wrap
= render "layouts/header/empty"
......
- project = project || @project
.git-clone-holder.js-git-clone-holder.input-group
- if allowed_protocols_present?
.input-group-text.clone-dropdown-btn.btn
%span.js-clone-dropdown-label
= enabled_project_button(project, enabled_protocol)
- else
%a#clone-dropdown.input-group-text.btn.btn-primary.btn-xs.clone-dropdown-btn.qa-clone-dropdown{ href: '#', data: { toggle: 'dropdown' } }
%span.append-right-4.js-clone-dropdown-label
= _('Clone')
= sprite_icon("arrow-down", css_class: "icon")
%form.p-3.dropdown-menu.dropdown-menu-right.dropdown-menu-large.dropdown-menu-selectable.clone-options-dropdown.qa-clone-options
- if ssh_enabled?
%li.pb-2
%label.label-bold
= _('Clone with SSH')
......@@ -19,6 +15,7 @@
.input-group-append
= clipboard_button(target: '#ssh_project_clone', title: _("Copy URL to clipboard"), class: "input-group-text btn-default btn-clipboard")
= render_if_exists 'projects/buttons/geo'
- if http_enabled?
%li
%label.label-bold
= _('Clone with %{http_label}') % { http_label: gitlab_config.protocol.upcase }
......
......@@ -98,4 +98,4 @@
%section.issuable-discussion
= render 'projects/issues/discussion'
= render 'shared/issuable/sidebar', issuable: @issue
= render 'shared/issuable/sidebar', issuable_sidebar: @issuable_sidebar, assignees: @issue.assignees
- page_title "Merge Conflicts", "#{@merge_request.title} (#{@merge_request.to_reference}", "Merge Requests"
- content_for :page_specific_javascripts do
= page_specific_javascript_tag('lib/ace.js')
= render "projects/merge_requests/mr_title"
.merge-request-details.issuable-details
= render "projects/merge_requests/mr_box"
= render 'shared/issuable/sidebar', issuable: @merge_request
#conflicts{ "v-cloak" => "true", data: { conflicts_path: conflicts_project_merge_request_path(@merge_request.project, @merge_request, format: :json),
resolve_conflicts_path: resolve_conflicts_project_merge_request_path(@merge_request.project, @merge_request) } }
.loading{ "v-if" => "isLoading" }
%i.fa.fa-spinner.fa-spin
.nothing-here-block{ "v-if" => "hasError" }
{{conflictsData.errorMessage}}
= render partial: "projects/merge_requests/conflicts/commit_stats"
.files-wrapper{ "v-if" => "!isLoading && !hasError" }
.files
.diff-file.file-holder.conflict{ "v-for" => "file in conflictsData.files" }
.js-file-title.file-title
%i.fa.fa-fw{ ":class" => "file.iconClass" }
%strong {{file.filePath}}
= render partial: 'projects/merge_requests/conflicts/file_actions'
.diff-content.diff-wrap-lines
.diff-wrap-lines.code.file-content.js-syntax-highlight{ "v-show" => "!isParallel && file.resolveMode === 'interactive' && file.type === 'text'" }
= render partial: "projects/merge_requests/conflicts/components/inline_conflict_lines"
.diff-wrap-lines.code.file-content.js-syntax-highlight{ "v-show" => "isParallel && file.resolveMode === 'interactive' && file.type === 'text'" }
%parallel-conflict-lines{ ":file" => "file" }
%div{ "v-show" => "file.resolveMode === 'edit' || file.type === 'text-editor'" }
= render partial: "projects/merge_requests/conflicts/components/diff_file_editor"
= render partial: "projects/merge_requests/conflicts/submit_form"
......@@ -6,7 +6,7 @@
.merge-request-details.issuable-details
= render "projects/merge_requests/mr_box"
= render 'shared/issuable/sidebar', issuable: @merge_request
= render 'shared/issuable/sidebar', issuable_sidebar: @issuable_sidebar, assignees: @merge_request.assignees
#conflicts{ "v-cloak" => "true", data: { conflicts_path: conflicts_project_merge_request_path(@merge_request.project, @merge_request, format: :json),
resolve_conflicts_path: resolve_conflicts_project_merge_request_path(@merge_request.project, @merge_request) } }
......
......@@ -86,7 +86,8 @@
.mr-loading-status
= spinner
= render 'shared/issuable/sidebar', issuable: @merge_request
= render 'shared/issuable/sidebar', issuable_sidebar: @issuable_sidebar, assignees: @merge_request.assignees
- if @merge_request.can_be_reverted?(current_user)
= render "projects/commit/change", type: 'revert', commit: @merge_request.merge_commit, title: @merge_request.title
- if @merge_request.can_be_cherry_picked?
......
......@@ -7,7 +7,9 @@
%button.btn.btn-primary.dropdown-toggle.js-dropdown-toggle{ type: "button", data: { toggle: "dropdown" } }
= sprite_icon("arrow-down", css_class: "dropdown-btn-icon icon")
%ul.dropdown-menu.dropdown-menu-selectable.dropdown-menu-right.clone-options-dropdown{ data: { dropdown: true } }
- if ssh_enabled?
%li
= dropdown_item_with_description(ssh_copy_label, project.ssh_url_to_repo, href: project.ssh_url_to_repo, data: { clone_type: 'ssh' }, default: true)
- if http_enabled?
%li
= dropdown_item_with_description(http_copy_label, project.http_url_to_repo, href: project.http_url_to_repo, data: { clone_type: 'http' })
- if issuable.is_a?(Issue)
#js-vue-sidebar-assignees{ data: { field: "#{issuable.to_ability_name}[assignee_ids]", signed_in: signed_in } }
- issuable_type = issuable_sidebar[:type]
- signed_in = !!issuable_sidebar.dig(:current_user, :id)
- can_edit_issuable = issuable_sidebar.dig(:current_user, :can_edit)
- if issuable_type == "issue"
#js-vue-sidebar-assignees{ data: { field: "#{issuable_type}[assignee_ids]", signed_in: signed_in } }
.title.hide-collapsed
= _('Assignee')
= icon('spinner spin')
- else
.sidebar-collapsed-icon.sidebar-collapsed-user{ data: { toggle: "tooltip", placement: "left", container: "body", boundary: 'viewport' }, title: sidebar_assignee_tooltip_label(issuable) }
- if issuable.assignee
= link_to_member(@project, issuable.assignee, size: 24)
- assignee = assignees.first
.sidebar-collapsed-icon.sidebar-collapsed-user{ data: { toggle: "tooltip", placement: "left", container: "body", boundary: 'viewport' }, title: (issuable_sidebar.dig(:assignee, :name) || _('Assignee')) }
- if issuable_sidebar[:assignee]
= link_to_member(@project, assignee, size: 24)
- else
= icon('user', 'aria-hidden': 'true')
.title.hide-collapsed
......@@ -18,13 +23,13 @@
%a.gutter-toggle.float-right.js-sidebar-toggle{ role: "button", href: "#", "aria-label" => _('Toggle sidebar') }
= sidebar_gutter_toggle_icon
.value.hide-collapsed
- if issuable.assignee
= link_to_member(@project, issuable.assignee, size: 32, extra_class: 'bold') do
- if !issuable.can_be_merged_by?(issuable.assignee)
- if issuable_sidebar[:assignee]
= link_to_member(@project, assignee, size: 32, extra_class: 'bold') do
- if issuable_sidebar[:assignee][:can_merge]
%span.float-right.cannot-be-merged{ data: { toggle: 'tooltip', placement: 'left' }, title: _('Not allowed to merge') }
= icon('exclamation-triangle', 'aria-hidden': 'true')
%span.username
= issuable.assignee.to_reference
@#{issuable_sidebar[:assignee][:username]}
- else
%span.assign-yourself.no-value
= _('No assignee')
......@@ -34,19 +39,33 @@
= _('assign yourself')
.selectbox.hide-collapsed
- issuable.assignees.each do |assignee|
= hidden_field_tag "#{issuable.to_ability_name}[assignee_ids][]", assignee.id, id: nil, data: { avatar_url: assignee.avatar_url, name: assignee.name, username: assignee.username }
- if assignees.none?
= hidden_field_tag "#{issuable_type}[assignee_ids][]", 0, id: nil
- else
- assignees.each do |assignee|
= hidden_field_tag "#{issuable_type}[assignee_ids][]", assignee.id, id: nil, data: { avatar_url: assignee.avatar_url, name: assignee.name, username: assignee.username }
- options = { toggle_class: 'js-user-search js-author-search', title: _('Assign to'), filter: true, dropdown_class: 'dropdown-menu-user dropdown-menu-selectable dropdown-menu-author', placeholder: _('Search users'), data: { first_user: current_user&.username, current_user: true, project_id: @project&.id, author_id: issuable.author_id, field_name: "#{issuable.to_ability_name}[assignee_ids][]", issue_update: issuable_json_path(issuable), ability_name: issuable.to_ability_name, null_user: true, display: 'static' } }
- options = { toggle_class: 'js-user-search js-author-search',
title: _('Assign to'),
filter: true,
dropdown_class: 'dropdown-menu-user dropdown-menu-selectable dropdown-menu-author',
placeholder: _('Search users'),
data: { first_user: issuable_sidebar.dig(:current_user, :username),
current_user: true,
project_id: issuable_sidebar[:project_id],
author_id: issuable_sidebar[:author_id],
field_name: "#{issuable_type}[assignee_ids][]",
issue_update: issuable_sidebar[:issuable_json_path],
ability_name: issuable_type,
null_user: true,
display: 'static' } }
- title = _('Select assignee')
- if issuable.is_a?(Issue)
- unless issuable.assignees.any?
= hidden_field_tag "#{issuable.to_ability_name}[assignee_ids][]", 0, id: nil
- if issuable_type == "issue"
- dropdown_options = issue_assignees_dropdown_options
- title = dropdown_options[:title]
- options[:toggle_class] += ' js-multiselect js-save-user-data'
- data = { field_name: "#{issuable.to_ability_name}[assignee_ids][]" }
- data = { field_name: "#{issuable_type}[assignee_ids][]" }
- data[:multi_select] = true
- data['dropdown-title'] = title
- data['dropdown-header'] = dropdown_options[:data][:'dropdown-header']
......
- is_collapsed = local_assigns.fetch(:is_collapsed, false)
- mark_content = is_collapsed ? sprite_icon('todo-done', css_class: 'todo-undone') : _('Mark todo as done')
- todo_content = is_collapsed ? sprite_icon('todo-add') : _('Add todo')
- has_todo = !!issuable_sidebar.dig(:current_user, :todo, :id)
- todo_button_data = issuable_todo_button_data(issuable_sidebar, is_collapsed)
- button_title = has_todo ? todo_button_data[:mark_text] : todo_button_data[:todo_text]
- button_icon = has_todo ? todo_button_data[:mark_icon] : todo_button_data[:todo_icon]
%button.issuable-todo-btn.js-issuable-todo{ type: 'button',
class: (is_collapsed ? 'btn-blank sidebar-collapsed-icon dont-change-state has-tooltip' : 'btn btn-default issuable-header-btn float-right'),
title: (todo.nil? ? _('Add todo') : _('Mark todo as done')),
'aria-label' => (todo.nil? ? _('Add todo') : _('Mark todo as done')),
data: issuable_todo_button_data(issuable, todo, is_collapsed) }
title: button_title,
'aria-label' => button_title,
data: todo_button_data }
%span.issuable-todo-inner.js-issuable-todo-inner<
- if todo
= mark_content
- else
= todo_content
= is_collapsed ? button_icon : button_title
= icon('spin spinner', 'aria-hidden': 'true')
......@@ -19,10 +19,9 @@
.issuable-form-select-holder
= render "shared/issuable/milestone_dropdown", selected: issuable.milestone, name: "#{issuable.class.model_name.param_key}[milestone_id]", show_any: false, show_upcoming: false, show_started: false, extra_class: "qa-issuable-milestone-dropdown js-issuable-form-dropdown js-dropdown-keep-input", dropdown_title: "Select milestone"
.form-group.row
- has_labels = @labels && @labels.any?
= form.label :label_ids, "Labels", class: "col-form-label #{has_due_date ? "col-md-2 col-lg-4" : "col-sm-2"}"
= form.hidden_field :label_ids, multiple: true, value: ''
.col-sm-10{ class: "#{"col-md-8" if has_due_date} #{'issuable-form-padding-top' if !has_labels}" }
.col-sm-10{ class: "#{"col-md-8" if has_due_date}" }
.issuable-form-select-holder
= render "shared/issuable/label_dropdown", classes: ["js-issuable-form-dropdown"], selected: issuable.labels, data_options: { field_name: "#{issuable.class.model_name.param_key}[label_ids][]", show_any: false }, dropdown_title: "Select label"
......
......@@ -65,7 +65,7 @@
%span.bold= milestone.due_date.to_s(:medium)
- else
%span.no-value No due date
- remaining_days = remaining_days_in_words(milestone)
- remaining_days = remaining_days_in_words(milestone.due_date, milestone.start_date)
- if remaining_days.present?
= surround '(', ')' do
%span.remaining-days= remaining_days
......
......@@ -27,7 +27,7 @@
- gcp_cluster:cluster_wait_for_app_installation
- gcp_cluster:wait_for_cluster_creation
- gcp_cluster:cluster_wait_for_ingress_ip_address
- gcp_cluster:cluster_platform_configure
- gcp_cluster:cluster_configure
- gcp_cluster:cluster_project_configure
- github_import_advance_stage
......
# frozen_string_literal: true
class ClusterPlatformConfigureWorker
class ClusterConfigureWorker
include ApplicationWorker
include ClusterQueue
......
......@@ -10,7 +10,7 @@ class ClusterProvisionWorker
Clusters::Gcp::ProvisionService.new.execute(provider) if cluster.gcp?
end
ClusterPlatformConfigureWorker.perform_async(cluster.id) if cluster.user?
ClusterConfigureWorker.perform_async(cluster.id) if cluster.user?
end
end
end
---
title: Use BFG object maps to clean projects
merge_request: 23189
author:
type: added
---
title: Redesign of MR header sections (CE)
merge_request: 23465
author:
type: changed
---
title: Pipeline trigger variable values are hidden in the UI by default. Maintainers
have the option to reveal them.
merge_request: 23518
author: jhampton
type: added
---
title: Show error message when attempting to reopen an MR and there is an open MR
for the same branch
merge_request: 16447
author: Akos Gyimesi
type: fixed
---
title: Add a rebase API endpoint for merge requests
merge_request: 23296
author:
type: added
---
title: Use group clusters when deploying (DeploymentPlatform)
merge_request: 22308
author:
type: changed
---
title: Add ability to create group level clusters and install gitlab managed applications
merge_request: 22450
author:
type: added
---
title: Show user contributions in correct timezone within user profile
merge_request: 23419
author:
type: changed
---
title: Allow sorting issues and MRs in reverse order
merge_request: 21438
author:
type: changed
---
title: Creates /create_merge_request quickaction
merge_request: 22485
author: Jacopo Beschi @jacopo-beschi
type: added
---
title: Reduce Gitaly calls in projects dashboard
merge_request: 23307
author:
type: performance
---
title: Removes all instances of deprecated Gitlab Upgrader calls
merge_request: 23603
author: '@jwolen'
type: removed
---
title: Add config to prohibit impersonation
merge_request: 23338
author:
type: added
---
title: Allow deleting a Pipeline via the API.
merge_request: 22988
author:
type: added
---
title: Adds Any option to label filters
merge_request: 23111
title: Extend override check to also check arity
merge_request: 23498
author: Jacopo Beschi @jacopo-beschi
type: added
---
title: Refactor issuable sidebar to use serializer
merge_request: 23379
author:
type: other
---
title: "WebIDE: Pressing Ctrl-Enter while typing on the commit message now performs the commit action"
merge_request: 23049
author: Thomas Pathier
type: added
---
title: 'SystemCheck: Use a more reliable way to detect current Ruby version'
merge_request: 23291
author:
type: changed
---
title: Fixing regression issues on pages settings and details
merge_request: 22821
author:
type: fixed
---
title: When user clicks linenumber in MR changes, highlight that line
merge_request:
author:
type: fixed
---
title: Fix "merged with [commit]" info for merge requests being merged automatically
by other actions
merge_request: 22794
author:
type: fixed
---
title: Don't show Memory Usage for unmerged MRs
merge_request:
author:
type: changed
---
title: Allow SSH public-key authentication for push mirroring
merge_request: 22982
author:
type: added
---
title: Resolve Main navbar is broken in certain viewport widths
merge_request: 23348
author:
type: fixed
---
title: Upgrade helm to 2.11.0 and upgrade on every install
merge_request: 22693
author:
type: added
---
title: Extended user centric tooltips on issue and MR page
merge_request: 23231
author:
type: added
---
title: Resolve Add border around the repository file tree
merge_request: 23018
author:
type: changed
---
title: Removes all the irrelevant code and columns that were migrated from the Project
table over to the ProjectImportState table
merge_request: 21497
author:
type: performance
---
title: Allow search and sort users at same time on admin users page
merge_request: 23439
author:
type: fixed
---
title: Scope default MR search in WebIDE dropdown to current project
merge_request: 23400
author:
type: changed
---
title: Resolve status emoji being replaced by avatar on mobile
merge_request: 23408
author:
type: other
---
title: Improves performance of Project#readme_url by caching the README path
merge_request: 23357
author:
type: performance
---
title: 'Commits API: Preserve file content in move operations if unspecified'
merge_request: 23387
author:
type: fixed
---
title: Restrict member access level to be higher than that of any parent group
merge_request: 23226
author:
type: fixed
---
title: Fix navigating by unresolved discussions on Merge Request page
merge_request: 22789
author:
type: fixed
---
title: "Make auto-generated icons for subgroups in the breadcrumb dropdown display as a circle"
merge_request: 23062
author: Thomas Pathier
type: fix
\ No newline at end of file
---
title: Design improvements to project overview page
merge_request: 22196
author:
type: changed
---
title: Uses new gitlab-ui components in Jobs and Pipelines components
merge_request:
author:
type: other
---
title: Replaces tooltip directive with the new gl-tooltip directive for consistency
in some ci/cd code
merge_request:
author:
type: other
---
title: Don't remove failed install pods after installing GitLab managed applications
merge_request: 23350
author:
type: changed
---
title: Chat message push notifications now include links back to GitLab branches
merge_request: 22651
author: Tony Castrogiovanni
type: added
---
title: Changed frontmatter filtering to support YAML, JSON, TOML, and arbitrary languages
merge_request: 23331
author: Travis Miller
type: changed
---
title: Allow user to scroll to top of tab on MR page
merge_request:
author:
type: added
---
title: Support RSA and ECDSA algorithms in Omniauth JWT provider
merge_request: 23411
author: Michael Tsyganov
type: fixed
---
title: Filter by None/Any for labels in issues/mrs API
merge_request: 22622
author: Jacopo Beschi @jacopo-beschi
type: added
---
title: removes partially matching of No Label filter and makes it case-insensitive
merge_request: 22622
author: Jacopo Beschi @jacopo-beschi
type: changed
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment