Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
591b0e86e3
commit
6de7d2c195
|
@ -10,7 +10,7 @@ notify-update-gitaly:
|
|||
extends:
|
||||
- .notify-slack
|
||||
rules:
|
||||
- if: '$CI_MERGE_REQUEST_IID && $CI_COMMIT_BRANCH == $GITALY_UPDATE_BRANCH'
|
||||
- if: '$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME == $GITALY_UPDATE_BRANCH'
|
||||
when: on_failure
|
||||
allow_failure: true
|
||||
variables:
|
||||
|
|
|
@ -128,6 +128,7 @@
|
|||
- "{,ee/}spec/**/*.rb"
|
||||
- ".gitlab-ci.yml"
|
||||
- ".gitlab/ci/**/*"
|
||||
- "*_VERSION"
|
||||
|
||||
.db-patterns: &db-patterns
|
||||
- "{,ee/}{,spec/}{db,migrations}/**/*"
|
||||
|
|
|
@ -27,7 +27,7 @@ After your merge request has been approved according to our [approval guidelines
|
|||
* At this point, it might be easy to squash the commits from the MR into one
|
||||
* You can use the script `bin/secpick` instead of the following steps, to help you cherry-picking. See the [secpick documentation]
|
||||
- [ ] Create each MR targeting the stable branch `X-Y-stable`, using the [Security Release merge request template].
|
||||
* Every merge request will have its own set of TODOs, so make sure to complete those.
|
||||
* Every merge request will have its own set of to-dos, so make sure to complete those.
|
||||
- [ ] On the "Related merge requests" section, ensure that `4` merge requests are associated: The one targeting `master` and the `3` backports.
|
||||
- [ ] If this issue requires less than `4` merge requests, post a message on the Security Release Tracking Issue and ping the Release Managers.
|
||||
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
<script>
|
||||
/* eslint-disable vue/no-v-html */
|
||||
import { GlButton } from '@gitlab/ui';
|
||||
import { __, sprintf } from '~/locale';
|
||||
import ModalStore from '../../stores/modal_store';
|
||||
import modalMixin from '../../mixins/modal_mixins';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GlButton,
|
||||
},
|
||||
mixins: [modalMixin],
|
||||
props: {
|
||||
newIssuePath: {
|
||||
|
@ -54,17 +58,22 @@ export default {
|
|||
<div class="text-content">
|
||||
<h4>{{ contents.title }}</h4>
|
||||
<p v-html="contents.content"></p>
|
||||
<a v-if="activeTab === 'all'" :href="newIssuePath" class="btn btn-success btn-inverted">{{
|
||||
__('New issue')
|
||||
}}</a>
|
||||
<button
|
||||
<gl-button
|
||||
v-if="activeTab === 'all'"
|
||||
:href="newIssuePath"
|
||||
category="secondary"
|
||||
variant="success"
|
||||
>
|
||||
{{ __('New issue') }}
|
||||
</gl-button>
|
||||
<gl-button
|
||||
v-if="activeTab === 'selected'"
|
||||
class="btn btn-default"
|
||||
type="button"
|
||||
category="primary"
|
||||
variant="default"
|
||||
@click="changeTab('all')"
|
||||
>
|
||||
{{ __('Open issues') }}
|
||||
</button>
|
||||
</gl-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -2,21 +2,50 @@
|
|||
import { GlBanner } from '@gitlab/ui';
|
||||
import { s__ } from '~/locale';
|
||||
import { parseBoolean, setCookie, getCookie } from '~/lib/utils/common_utils';
|
||||
import Tracking from '~/tracking';
|
||||
|
||||
const trackingMixin = Tracking.mixin();
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GlBanner,
|
||||
},
|
||||
inject: ['svgPath', 'inviteMembersPath', 'isDismissedKey'],
|
||||
mixins: [trackingMixin],
|
||||
inject: ['svgPath', 'inviteMembersPath', 'isDismissedKey', 'trackLabel'],
|
||||
data() {
|
||||
return {
|
||||
isDismissed: parseBoolean(getCookie(this.isDismissedKey)),
|
||||
tracking: {
|
||||
label: this.trackLabel,
|
||||
},
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.$nextTick(() => {
|
||||
this.addTrackingAttributesToButton();
|
||||
});
|
||||
},
|
||||
mounted() {
|
||||
this.trackOnShow();
|
||||
},
|
||||
methods: {
|
||||
handleClose() {
|
||||
setCookie(this.isDismissedKey, true);
|
||||
this.isDismissed = true;
|
||||
this.track(this.$options.dismissEvent);
|
||||
},
|
||||
trackOnShow() {
|
||||
if (!this.isDismissed) this.track(this.$options.displayEvent);
|
||||
},
|
||||
addTrackingAttributesToButton() {
|
||||
if (this.$refs.banner === undefined) return;
|
||||
|
||||
const button = this.$refs.banner.$el.querySelector(`[href='${this.inviteMembersPath}']`);
|
||||
|
||||
if (button) {
|
||||
button.setAttribute('data-track-event', this.$options.buttonClickEvent);
|
||||
button.setAttribute('data-track-label', this.trackLabel);
|
||||
}
|
||||
},
|
||||
},
|
||||
i18n: {
|
||||
|
@ -26,6 +55,9 @@ export default {
|
|||
),
|
||||
button_text: s__('InviteMembersBanner|Invite your colleagues'),
|
||||
},
|
||||
displayEvent: 'invite_members_banner_displayed',
|
||||
buttonClickEvent: 'invite_members_banner_button_clicked',
|
||||
dismissEvent: 'invite_members_banner_dismissed',
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ export default function initInviteMembersBanner() {
|
|||
return false;
|
||||
}
|
||||
|
||||
const { svgPath, inviteMembersPath, isDismissedKey } = el.dataset;
|
||||
const { svgPath, inviteMembersPath, isDismissedKey, trackLabel } = el.dataset;
|
||||
|
||||
return new Vue({
|
||||
el,
|
||||
|
@ -16,6 +16,7 @@ export default function initInviteMembersBanner() {
|
|||
svgPath,
|
||||
inviteMembersPath,
|
||||
isDismissedKey,
|
||||
trackLabel,
|
||||
},
|
||||
render: createElement => createElement(InviteMembersBanner),
|
||||
});
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import { GlLoadingIcon, GlTooltipDirective, GlIcon } from '@gitlab/ui';
|
||||
import { __ } from '~/locale';
|
||||
import { __, sprintf } from '~/locale';
|
||||
import resolvedStatusMixin from '~/batch_comments/mixins/resolved_status';
|
||||
import ReplyButton from './note_actions/reply_button.vue';
|
||||
import eventHub from '~/sidebar/event_hub';
|
||||
import Api from '~/api';
|
||||
import { deprecatedCreateFlash as flash } from '~/flash';
|
||||
import { splitCamelCase } from '../../lib/utils/text_utility';
|
||||
|
||||
export default {
|
||||
name: 'NoteActions',
|
||||
|
@ -47,6 +48,26 @@ export default {
|
|||
required: false,
|
||||
default: null,
|
||||
},
|
||||
isAuthor: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
isContributor: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
noteableType: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
projectName: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
showReply: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
|
@ -121,6 +142,9 @@ export default {
|
|||
targetType() {
|
||||
return this.getNoteableData.targetType;
|
||||
},
|
||||
noteableDisplayName() {
|
||||
return splitCamelCase(this.noteableType).toLowerCase();
|
||||
},
|
||||
assignees() {
|
||||
return this.getNoteableData.assignees || [];
|
||||
},
|
||||
|
@ -130,6 +154,22 @@ export default {
|
|||
canAssign() {
|
||||
return this.getNoteableData.current_user?.can_update && this.isIssue;
|
||||
},
|
||||
displayAuthorBadgeText() {
|
||||
return sprintf(__('This user is the author of this %{noteable}.'), {
|
||||
noteable: this.noteableDisplayName,
|
||||
});
|
||||
},
|
||||
displayMemberBadgeText() {
|
||||
return sprintf(__('This user is a %{access} of the %{name} project.'), {
|
||||
access: this.accessLevel.toLowerCase(),
|
||||
name: this.projectName,
|
||||
});
|
||||
},
|
||||
displayContributorBadgeText() {
|
||||
return sprintf(__('This user has previously committed to the %{name} project.'), {
|
||||
name: this.projectName,
|
||||
});
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onEdit() {
|
||||
|
@ -175,7 +215,24 @@ export default {
|
|||
|
||||
<template>
|
||||
<div class="note-actions">
|
||||
<span v-if="accessLevel" class="note-role user-access-role">{{ accessLevel }}</span>
|
||||
<span
|
||||
v-if="isAuthor"
|
||||
class="note-role user-access-role has-tooltip d-none d-md-inline-block"
|
||||
:title="displayAuthorBadgeText"
|
||||
>{{ __('Author') }}</span
|
||||
>
|
||||
<span
|
||||
v-if="accessLevel"
|
||||
class="note-role user-access-role has-tooltip"
|
||||
:title="displayMemberBadgeText"
|
||||
>{{ accessLevel }}</span
|
||||
>
|
||||
<span
|
||||
v-else-if="isContributor"
|
||||
class="note-role user-access-role has-tooltip"
|
||||
:title="displayContributorBadgeText"
|
||||
>{{ __('Contributor') }}</span
|
||||
>
|
||||
<div v-if="canResolve" class="note-actions-item">
|
||||
<button
|
||||
ref="resolveButton"
|
||||
|
|
|
@ -389,6 +389,10 @@ export default {
|
|||
:note-id="note.id"
|
||||
:note-url="note.noteable_note_url"
|
||||
:access-level="note.human_access"
|
||||
:is-contributor="note.is_contributor"
|
||||
:is-author="note.is_noteable_author"
|
||||
:project-name="note.project_name"
|
||||
:noteable-type="note.noteable_type"
|
||||
:show-reply="showReplyButton"
|
||||
:can-edit="note.current_user.can_edit"
|
||||
:can-award-emoji="note.current_user.can_award_emoji"
|
||||
|
|
|
@ -143,7 +143,7 @@ export default {
|
|||
:button-title="
|
||||
sprintf(s__('MarkdownEditor|Add bold text (%{modifierKey}B)'), { modifierKey })
|
||||
"
|
||||
:shortcuts="['command+b', 'ctrl+b']"
|
||||
shortcuts="mod+b"
|
||||
icon="bold"
|
||||
/>
|
||||
<toolbar-button
|
||||
|
@ -151,7 +151,7 @@ export default {
|
|||
:button-title="
|
||||
sprintf(s__('MarkdownEditor|Add italic text (%{modifierKey}I)'), { modifierKey })
|
||||
"
|
||||
:shortcuts="['command+i', 'ctrl+i']"
|
||||
shortcuts="mod+i"
|
||||
icon="italic"
|
||||
/>
|
||||
<toolbar-button
|
||||
|
@ -207,7 +207,7 @@ export default {
|
|||
:button-title="
|
||||
sprintf(s__('MarkdownEditor|Add a link (%{modifierKey}K)'), { modifierKey })
|
||||
"
|
||||
:shortcuts="['command+k', 'ctrl+k']"
|
||||
shortcuts="mod+k"
|
||||
icon="link"
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -5,7 +5,6 @@ module RendersNotes
|
|||
def prepare_notes_for_rendering(notes, noteable = nil)
|
||||
preload_noteable_for_regular_notes(notes)
|
||||
preload_max_access_for_authors(notes, @project)
|
||||
preload_first_time_contribution_for_authors(noteable, notes)
|
||||
preload_author_status(notes)
|
||||
Notes::RenderService.new(current_user).execute(notes)
|
||||
|
||||
|
@ -19,7 +18,8 @@ module RendersNotes
|
|||
return unless project
|
||||
|
||||
user_ids = notes.map(&:author_id)
|
||||
project.team.max_member_access_for_user_ids(user_ids)
|
||||
access = project.team.max_member_access_for_user_ids(user_ids).select { |k, v| v == Gitlab::Access::NO_ACCESS }.keys
|
||||
project.team.contribution_check_for_user_ids(access)
|
||||
end
|
||||
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
|
@ -28,12 +28,6 @@ module RendersNotes
|
|||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
def preload_first_time_contribution_for_authors(noteable, notes)
|
||||
return unless noteable.is_a?(Issuable) && noteable.first_contribution?
|
||||
|
||||
notes.each {|n| n.specialize_for_first_contribution!(noteable)}
|
||||
end
|
||||
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def preload_author_status(notes)
|
||||
ActiveRecord::Associations::Preloader.new.preload(notes, { author: :status })
|
||||
|
|
|
@ -205,6 +205,12 @@ module IssuablesHelper
|
|||
author_output
|
||||
end
|
||||
|
||||
if access = project.team.human_max_access(issuable.author_id)
|
||||
output << content_tag(:span, access, class: "user-access-role has-tooltip d-none d-xl-inline-block gl-ml-3 ", title: _("This user is a %{access} of the %{name} project.") % { access: access.downcase, name: project.name })
|
||||
elsif project.team.contributor?(issuable.author_id)
|
||||
output << content_tag(:span, _("Contributor"), class: "user-access-role has-tooltip d-none d-xl-inline-block gl-ml-3", title: _("This user has previously committed to the %{name} project.") % { name: project.name })
|
||||
end
|
||||
|
||||
output << content_tag(:span, (sprite_icon('first-contribution', css_class: 'gl-icon gl-vertical-align-middle') if issuable.first_contribution?), class: 'has-tooltip gl-ml-2', title: _('1st contribution!'))
|
||||
|
||||
output << content_tag(:span, (issuable.task_status if issuable.tasks?), id: "task_status", class: "d-none d-sm-none d-md-inline-block gl-ml-3")
|
||||
|
|
|
@ -85,6 +85,10 @@ module NotesHelper
|
|||
note.project.team.max_member_access(note.author_id)
|
||||
end
|
||||
|
||||
def note_human_max_access(note)
|
||||
note.project.team.human_max_access(note.author_id)
|
||||
end
|
||||
|
||||
def discussion_path(discussion)
|
||||
if discussion.for_merge_request?
|
||||
return unless discussion.diff_discussion?
|
||||
|
|
|
@ -410,10 +410,17 @@ class Group < Namespace
|
|||
.where(namespaces: { id: self_and_descendants.select(:id) })
|
||||
end
|
||||
|
||||
def max_member_access_for_user(user)
|
||||
# Return the highest access level for a user
|
||||
#
|
||||
# A special case is handled here when the user is a GitLab admin
|
||||
# which implies it has "OWNER" access everywhere, but should not
|
||||
# officially appear as a member of a group unless specifically added to it
|
||||
#
|
||||
# @param user [User]
|
||||
# @param only_concrete_membership [Bool] whether require admin concrete membership status
|
||||
def max_member_access_for_user(user, only_concrete_membership: false)
|
||||
return GroupMember::NO_ACCESS unless user
|
||||
|
||||
return GroupMember::OWNER if user.admin?
|
||||
return GroupMember::OWNER if user.admin? && !only_concrete_membership
|
||||
|
||||
max_member_access = members_with_parents.where(user_id: user)
|
||||
.reorder(access_level: :desc)
|
||||
|
|
|
@ -1603,7 +1603,7 @@ class MergeRequest < ApplicationRecord
|
|||
def first_contribution?
|
||||
return false if project.team.max_member_access(author_id) > Gitlab::Access::GUEST
|
||||
|
||||
project.merge_requests.merged.where(author_id: author_id).empty?
|
||||
!project.merge_requests.merged.exists?(author_id: author_id)
|
||||
end
|
||||
|
||||
# TODO: remove once production database rename completes
|
||||
|
|
|
@ -20,20 +20,6 @@ class Note < ApplicationRecord
|
|||
include ThrottledTouch
|
||||
include FromUnion
|
||||
|
||||
module SpecialRole
|
||||
FIRST_TIME_CONTRIBUTOR = :first_time_contributor
|
||||
|
||||
class << self
|
||||
def values
|
||||
constants.map {|const| self.const_get(const, false)}
|
||||
end
|
||||
|
||||
def value?(val)
|
||||
values.include?(val)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
cache_markdown_field :note, pipeline: :note, issuable_state_filter_enabled: true
|
||||
|
||||
redact_field :note
|
||||
|
@ -60,9 +46,6 @@ class Note < ApplicationRecord
|
|||
# Attribute used to store the attributes that have been changed by quick actions.
|
||||
attr_accessor :commands_changes
|
||||
|
||||
# A special role that may be displayed on issuable's discussions
|
||||
attr_reader :special_role
|
||||
|
||||
default_value_for :system, false
|
||||
|
||||
attr_mentionable :note, pipeline: :note
|
||||
|
@ -220,10 +203,6 @@ class Note < ApplicationRecord
|
|||
.where(noteable_type: type, noteable_id: ids)
|
||||
end
|
||||
|
||||
def has_special_role?(role, note)
|
||||
note.special_role == role
|
||||
end
|
||||
|
||||
def search(query)
|
||||
fuzzy_search(query, [:note])
|
||||
end
|
||||
|
@ -342,20 +321,20 @@ class Note < ApplicationRecord
|
|||
noteable.author_id == user.id
|
||||
end
|
||||
|
||||
def special_role=(role)
|
||||
raise "Role is undefined, #{role} not found in #{SpecialRole.values}" unless SpecialRole.value?(role)
|
||||
def contributor?
|
||||
return false unless ::Feature.enabled?(:show_contributor_on_note, project)
|
||||
|
||||
@special_role = role
|
||||
project&.team&.contributor?(self.author_id)
|
||||
end
|
||||
|
||||
def has_special_role?(role)
|
||||
self.class.has_special_role?(role, self)
|
||||
def noteable_author?(noteable)
|
||||
return false unless ::Feature.enabled?(:show_author_on_note, project)
|
||||
|
||||
noteable.author == self.author
|
||||
end
|
||||
|
||||
def specialize_for_first_contribution!(noteable)
|
||||
return unless noteable.author_id == self.author_id
|
||||
|
||||
self.special_role = Note::SpecialRole::FIRST_TIME_CONTRIBUTOR
|
||||
def project_name
|
||||
project&.name
|
||||
end
|
||||
|
||||
def confidential?(include_noteable: false)
|
||||
|
|
|
@ -178,6 +178,40 @@ class ProjectTeam
|
|||
max_member_access_for_user_ids([user_id])[user_id]
|
||||
end
|
||||
|
||||
def contribution_check_for_user_ids(user_ids)
|
||||
user_ids = user_ids.uniq
|
||||
key = "contribution_check_for_users:#{project.id}"
|
||||
|
||||
Gitlab::SafeRequestStore[key] ||= {}
|
||||
contributors = Gitlab::SafeRequestStore[key] || {}
|
||||
|
||||
user_ids -= contributors.keys
|
||||
|
||||
return contributors if user_ids.empty?
|
||||
|
||||
resource_contributors = project.merge_requests
|
||||
.merged
|
||||
.where(author_id: user_ids, target_branch: project.default_branch.to_s)
|
||||
.pluck(:author_id)
|
||||
.product([true]).to_h
|
||||
|
||||
contributors.merge!(resource_contributors)
|
||||
|
||||
missing_resource_ids = user_ids - resource_contributors.keys
|
||||
|
||||
missing_resource_ids.each do |resource_id|
|
||||
contributors[resource_id] = false
|
||||
end
|
||||
|
||||
contributors
|
||||
end
|
||||
|
||||
def contributor?(user_id)
|
||||
return false if max_member_access(user_id) >= Gitlab::Access::GUEST
|
||||
|
||||
contribution_check_for_user_ids([user_id])[user_id]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def fetch_members(level = nil)
|
||||
|
|
|
@ -46,6 +46,10 @@ class NoteEntity < API::Entities::Note
|
|||
SystemNoteHelper.system_note_icon_name(note)
|
||||
end
|
||||
|
||||
expose :is_noteable_author do |note|
|
||||
note.noteable_author?(request.noteable)
|
||||
end
|
||||
|
||||
expose :discussion_id do |note|
|
||||
note.discussion_id(request.noteable)
|
||||
end
|
||||
|
|
|
@ -5,6 +5,14 @@ class ProjectNoteEntity < NoteEntity
|
|||
note.project.team.human_max_access(note.author_id)
|
||||
end
|
||||
|
||||
expose :is_contributor, if: -> (note, _) { note.project.present? } do |note|
|
||||
note.contributor?
|
||||
end
|
||||
|
||||
expose :project_name, if: -> (note, _) { note.project.present? } do |note|
|
||||
note.project.name
|
||||
end
|
||||
|
||||
expose :toggle_award_path, if: -> (note, _) { note.emoji_awardable? } do |note|
|
||||
toggle_award_emoji_project_note_path(note.project, note.id)
|
||||
end
|
||||
|
|
|
@ -114,8 +114,13 @@ module Projects
|
|||
# completes), and any other affected users in the background
|
||||
def setup_authorizations
|
||||
if @project.group
|
||||
current_user.project_authorizations.create!(project: @project,
|
||||
access_level: @project.group.max_member_access_for_user(current_user))
|
||||
group_access_level = @project.group.max_member_access_for_user(current_user,
|
||||
only_concrete_membership: true)
|
||||
|
||||
if group_access_level > GroupMember::NO_ACCESS
|
||||
current_user.project_authorizations.create!(project: @project,
|
||||
access_level: group_access_level)
|
||||
end
|
||||
|
||||
if Feature.enabled?(:specialized_project_authorization_workers)
|
||||
AuthorizedProjectUpdate::ProjectCreateWorker.perform_async(@project.id)
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
.container-fluid.container-limited{ class: "gl-pb-2! gl-pt-6! #{@content_class}" }
|
||||
.js-group-invite-members-banner{ data: { svg_path: image_path('illustrations/merge_requests.svg'),
|
||||
is_dismissed_key: "invite_#{@group.id}_#{current_user.id}",
|
||||
track_label: 'invite_members_banner',
|
||||
invite_members_path: group_group_members_path(@group) } }
|
||||
|
||||
= content_for :meta_tags do
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
- access = note_max_access_for_user(note)
|
||||
- if note.has_special_role?(Note::SpecialRole::FIRST_TIME_CONTRIBUTOR)
|
||||
%span.note-role.note-role-special.has-tooltip{ title: _("This is the author's first Merge Request to this project.") }
|
||||
= sprite_icon('first-contribution', css_class: 'gl-icon gl-vertical-align-top')
|
||||
- if access.nonzero?
|
||||
%span.note-role.user-access-role= Gitlab::Access.human_access(access)
|
||||
- access = note_human_max_access(note)
|
||||
- if note.noteable_author?(@noteable)
|
||||
%span{ class: 'note-role user-access-role has-tooltip d-none d-md-inline-block', title: _("This user is the author of this %{noteable}.") % { noteable: @noteable.human_class_name } }= _("Author")
|
||||
- if access
|
||||
%span{ class: 'note-role user-access-role has-tooltip', title: _("This user is a %{access} of the %{name} project.") % { access: access.downcase, name: note.project_name } }= access
|
||||
- elsif note.contributor?
|
||||
%span{ class: 'note-role user-access-role has-tooltip', title: _("This user has previously committed to the %{name} project.") % { name: note.project_name } }= _("Contributor")
|
||||
|
||||
- if note.resolvable?
|
||||
- can_resolve = can?(current_user, :resolve_note, note)
|
||||
|
|
|
@ -2,18 +2,18 @@
|
|||
|
||||
.md-header-toolbar.active
|
||||
= markdown_toolbar_button({ icon: "bold",
|
||||
data: { "md-tag" => "**", "md-shortcuts": '["command+b","ctrl+b"]' },
|
||||
data: { "md-tag" => "**", "md-shortcuts": '["mod+b"]' },
|
||||
title: sprintf(s_("MarkdownEditor|Add bold text (%{modifier_key}B)") % { modifier_key: modifier_key }) })
|
||||
|
||||
= markdown_toolbar_button({ icon: "italic",
|
||||
data: { "md-tag" => "_", "md-shortcuts": '["command+i","ctrl+i"]' },
|
||||
data: { "md-tag" => "_", "md-shortcuts": '["mod+i"]' },
|
||||
title: sprintf(s_("MarkdownEditor|Add italic text (%{modifier_key}I)") % { modifier_key: modifier_key }) })
|
||||
|
||||
= markdown_toolbar_button({ icon: "quote", data: { "md-tag" => "> ", "md-prepend" => true }, title: _("Insert a quote") })
|
||||
= markdown_toolbar_button({ icon: "code", data: { "md-tag" => "`", "md-block" => "```" }, title: _("Insert code") })
|
||||
|
||||
= markdown_toolbar_button({ icon: "link",
|
||||
data: { "md-tag" => "[{text}](url)", "md-select" => "url", "md-shortcuts": '["command+k","ctrl+k"]' },
|
||||
data: { "md-tag" => "[{text}](url)", "md-select" => "url", "md-shortcuts": '["mod+k"]' },
|
||||
title: sprintf(s_("MarkdownEditor|Add a link (%{modifier_key}K)") % { modifier_key: modifier_key }) })
|
||||
|
||||
= markdown_toolbar_button({ icon: "list-bulleted", data: { "md-tag" => "- ", "md-prepend" => true }, title: _("Add a bullet list") })
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Do not add admins as owners to project authorizations during project creation
|
||||
merge_request: 42335
|
||||
author:
|
||||
type: fixed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Display Contributor and Author badges on notes
|
||||
merge_request: 40198
|
||||
author: Mycroft Kang @TaehyeokKang
|
||||
type: added
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Stop applying Ctrl keyboard shortcuts inside Markdown editors on Mac
|
||||
merge_request: 42239
|
||||
author:
|
||||
type: fixed
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
name: show_author_on_note
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40198
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/250282
|
||||
group: group::project management
|
||||
type: development
|
||||
default_enabled: false
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
name: show_contributor_on_note
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40198
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/249179
|
||||
group: group::project management
|
||||
type: development
|
||||
default_enabled: false
|
|
@ -126,7 +126,7 @@ The following documentation relates to the DevOps **Plan** stage:
|
|||
| [Roadmap](user/group/roadmap/index.md) **(ULTIMATE)** | Visualize epic timelines. |
|
||||
| [Service Desk](user/project/service_desk.md) | A simple way to allow people to create issues in your GitLab instance without needing their own user account. |
|
||||
| [Time Tracking](user/project/time_tracking.md) | Track time spent on issues and merge requests. |
|
||||
| [Todos](user/todos.md) | Keep track of work requiring attention with a chronological list displayed on a simple dashboard. |
|
||||
| [To-Do List](user/todos.md) | Keep track of work requiring attention with a chronological list displayed on a simple dashboard. |
|
||||
|
||||
<div align="right">
|
||||
<a type="button" class="btn btn-default" href="#overview">
|
||||
|
@ -159,7 +159,7 @@ The following documentation relates to the DevOps **Create** stage:
|
|||
| [Issue Analytics](user/group/issues_analytics/index.md) **(PREMIUM)** | Check how many issues were created per month. |
|
||||
| [Merge Request Analytics](user/analytics/merge_request_analytics.md) **(PREMIUM)** | Check your throughput productivity - how many merge requests were merged per month. |
|
||||
| [Projects](user/project/index.md), including [project access](public_access/public_access.md)<br/>and [settings](user/project/settings/index.md) | Host source code, and control your project's visibility and set configuration. |
|
||||
| [Search through GitLab](user/search/index.md) | Search for issues, merge requests, projects, groups, and todos. |
|
||||
| [Search through GitLab](user/search/index.md) | Search for issues, merge requests, projects, groups, and to-dos. |
|
||||
| [Snippets](user/snippets.md) | Snippets allow you to create little bits of code. |
|
||||
| [Web IDE](user/project/web_ide/index.md) | Edit files within GitLab's user interface. |
|
||||
| [Static Site Editor](user/project/static_site_editor/index.md) | Edit content on static websites. |
|
||||
|
|
|
@ -151,7 +151,7 @@ The following API resources are available outside of project and group contexts
|
|||
| [Sidekiq metrics](sidekiq_metrics.md) | `/sidekiq` |
|
||||
| [Suggestions](suggestions.md) | `/suggestions` |
|
||||
| [System hooks](system_hooks.md) | `/hooks` |
|
||||
| [Todos](todos.md) | `/todos` |
|
||||
| [To-dos](todos.md) | `/todos` |
|
||||
| [Users](users.md) | `/users` |
|
||||
| [Validate `.gitlab-ci.yml` file](lint.md) | `/lint` |
|
||||
| [Version](version.md) | `/version` |
|
||||
|
|
|
@ -422,10 +422,10 @@ DELETE /groups/:id/epics/:epic_iid
|
|||
curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/1/epics/5"
|
||||
```
|
||||
|
||||
## Create a todo
|
||||
## Create a to-do
|
||||
|
||||
Manually creates a todo for the current user on an epic. If
|
||||
there already exists a todo for the user on that epic, status code `304` is
|
||||
Manually creates a to-do for the current user on an epic. If
|
||||
there already exists a to-do for the user on that epic, status code `304` is
|
||||
returned.
|
||||
|
||||
```plaintext
|
||||
|
|
|
@ -1496,10 +1496,10 @@ Example response:
|
|||
}
|
||||
```
|
||||
|
||||
## Create a todo
|
||||
## Create a to-do
|
||||
|
||||
Manually creates a todo for the current user on an issue. If
|
||||
there already exists a todo for the user on that issue, status code `304` is
|
||||
Manually creates a to-do for the current user on an issue. If
|
||||
there already exists a to-do for the user on that issue, status code `304` is
|
||||
returned.
|
||||
|
||||
```plaintext
|
||||
|
|
|
@ -2085,10 +2085,10 @@ the `approvals_before_merge` parameter:
|
|||
}
|
||||
```
|
||||
|
||||
## Create a todo
|
||||
## Create a to-do
|
||||
|
||||
Manually creates a todo for the current user on a merge request.
|
||||
If there already exists a todo for the user on that merge request,
|
||||
Manually creates a to-do for the current user on a merge request.
|
||||
If there already exists a to-do for the user on that merge request,
|
||||
status code `304` is returned.
|
||||
|
||||
```plaintext
|
||||
|
|
|
@ -4,13 +4,13 @@ group: Project Management
|
|||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
|
||||
---
|
||||
|
||||
# Todos API
|
||||
# To-dos API
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/3188) in GitLab 8.10.
|
||||
|
||||
## Get a list of todos
|
||||
## Get a list of to-dos
|
||||
|
||||
Returns a list of todos. When no filter is applied, it returns all pending todos
|
||||
Returns a list of to-dos. When no filter is applied, it returns all pending to-dos
|
||||
for the current user. Different filters allow the user to precise the request.
|
||||
|
||||
```plaintext
|
||||
|
@ -25,8 +25,8 @@ Parameters:
|
|||
| `author_id` | integer | no | The ID of an author |
|
||||
| `project_id` | integer | no | The ID of a project |
|
||||
| `group_id` | integer | no | The ID of a group |
|
||||
| `state` | string | no | The state of the todo. Can be either `pending` or `done` |
|
||||
| `type` | string | no | The type of a todo. Can be either `Issue`, `MergeRequest`, `DesignManagement::Design` or `AlertManagement::Alert` |
|
||||
| `state` | string | no | The state of the to-do. Can be either `pending` or `done` |
|
||||
| `type` | string | no | The type of a to-do. Can be either `Issue`, `MergeRequest`, `DesignManagement::Design` or `AlertManagement::Alert` |
|
||||
|
||||
```shell
|
||||
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/todos"
|
||||
|
@ -187,10 +187,10 @@ Example Response:
|
|||
]
|
||||
```
|
||||
|
||||
## Mark a todo as done
|
||||
## Mark a to-do as done
|
||||
|
||||
Marks a single pending todo given by its ID for the current user as done. The
|
||||
todo marked as done is returned in the response.
|
||||
Marks a single pending to-do given by its ID for the current user as done. The
|
||||
to-do marked as done is returned in the response.
|
||||
|
||||
```plaintext
|
||||
POST /todos/:id/mark_as_done
|
||||
|
@ -200,7 +200,7 @@ Parameters:
|
|||
|
||||
| Attribute | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `id` | integer | yes | The ID of a todo |
|
||||
| `id` | integer | yes | The ID of a to-do |
|
||||
|
||||
```shell
|
||||
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/todos/130/mark_as_done"
|
||||
|
@ -285,9 +285,9 @@ Example Response:
|
|||
}
|
||||
```
|
||||
|
||||
## Mark all todos as done
|
||||
## Mark all to-dos as done
|
||||
|
||||
Marks all pending todos for the current user as done. It returns the HTTP status code `204` with an empty response.
|
||||
Marks all pending to-dos for the current user as done. It returns the HTTP status code `204` with an empty response.
|
||||
|
||||
```plaintext
|
||||
POST /todos/mark_as_done
|
||||
|
|
|
@ -74,8 +74,8 @@ Below are the changes made between V3 and V4.
|
|||
- `POST /projects/:id/trigger/builds` to `POST /projects/:id/trigger/pipeline`
|
||||
- Require description when creating a new trigger `POST /projects/:id/triggers`
|
||||
- Simplify project payload exposed on Environment endpoints [!9675](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/9675)
|
||||
- API uses merge request `IID`s (internal ID, as in the web UI) rather than `ID`s. This affects the merge requests, award emoji, todos, and time tracking APIs. [!9530](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/9530)
|
||||
- API uses issue `IID`s (internal ID, as in the web UI) rather than `ID`s. This affects the issues, award emoji, todos, and time tracking APIs. [!9530](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/9530)
|
||||
- API uses merge request `IID`s (internal ID, as in the web UI) rather than `ID`s. This affects the merge requests, award emoji, to-dos, and time tracking APIs. [!9530](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/9530)
|
||||
- API uses issue `IID`s (internal ID, as in the web UI) rather than `ID`s. This affects the issues, award emoji, to-dos, and time tracking APIs. [!9530](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/9530)
|
||||
- Change initial page from `0` to `1` on `GET /projects/:id/repository/commits` (like on the rest of the API) [!9679](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/9679)
|
||||
- Return correct `Link` header data for `GET /projects/:id/repository/commits` [!9679](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/9679)
|
||||
- Update endpoints for repository files [!9637](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/9637)
|
||||
|
|
|
@ -547,6 +547,7 @@ The order of precedence for variables is (from highest to lowest):
|
|||
and [manual pipeline run variables](#override-a-variable-by-manually-running-a-pipeline).
|
||||
1. Project-level [variables](#custom-environment-variables) or [protected variables](#protect-a-custom-variable).
|
||||
1. Group-level [variables](#group-level-environment-variables) or [protected variables](#protect-a-custom-variable).
|
||||
1. Instance-level [variables](#instance-level-cicd-environment-variables) or [protected variables](#protect-a-custom-variable).
|
||||
1. [Inherited environment variables](#inherit-environment-variables).
|
||||
1. YAML-defined [job-level variables](../yaml/README.md#variables).
|
||||
1. YAML-defined [global variables](../yaml/README.md#variables).
|
||||
|
|
|
@ -175,7 +175,7 @@ guide on how you can add a new custom validator.
|
|||
validates the parameter value for different cases. Mainly, it checks whether a
|
||||
path is relative and does it contain `../../` relative traversal using
|
||||
`File::Separator` or not, and whether the path is absolute, for example
|
||||
`/etc/passwd/`. By default, absolute paths are not allowed. However, you can optionally pass in an allowlist for allowed absolute paths in the following way:
|
||||
`/etc/passwd/`. By default, absolute paths are not allowed. However, you can optionally pass in an allowlist for allowed absolute paths in the following way:
|
||||
`requires :file_path, type: String, file_path: { allowlist: ['/foo/bar/', '/home/foo/', '/app/home'] }`
|
||||
|
||||
- `Git SHA`:
|
||||
|
@ -249,7 +249,7 @@ most basic entity, with successive entities building upon that scope.
|
|||
|
||||
The `with_api_entity_associations` scope will also [automatically preload
|
||||
data](https://gitlab.com/gitlab-org/gitlab/blob/19f74903240e209736c7668132e6a5a735954e7c/app%2Fmodels%2Ftodo.rb#L34)
|
||||
for `Todo` _targets_ when returned in the Todos API.
|
||||
for `Todo` _targets_ when returned in the [to-dos API](../api/todos.md).
|
||||
|
||||
For more context and discussion about preloading see
|
||||
[this merge request](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/25711)
|
||||
|
|
|
@ -119,7 +119,7 @@ use:
|
|||
# Feature Name
|
||||
|
||||
> - [Introduced](link-to-issue) in GitLab 12.0.
|
||||
> - It was deployed [deployed behind a feature flag](<replace with path to>/user/feature_flags.md), disabled by default.
|
||||
> - It was [deployed behind a feature flag](<replace with path to>/user/feature_flags.md), disabled by default.
|
||||
> - [Became enabled by default](link-to-issue) on GitLab 12.1.
|
||||
> - It's enabled on GitLab.com.
|
||||
> - It's recommended for production use.
|
||||
|
|
|
@ -369,6 +369,7 @@ create an issue or an MR to propose a change to the user interface text.
|
|||
- milestones
|
||||
- reorder issues
|
||||
- runner, runners, shared runners
|
||||
- a to-do, to-dos
|
||||
- *Some features are capitalized*, typically nouns naming GitLab-specific
|
||||
capabilities or tools. For example:
|
||||
- GitLab CI/CD
|
||||
|
|
|
@ -448,7 +448,9 @@ so we need to set some guidelines for their use going forward:
|
|||
- `let!` variables should be used only in case if strict evaluation with defined
|
||||
order is required, otherwise `let` will suffice. Remember that `let` is lazy and won't
|
||||
be evaluated until it is referenced.
|
||||
- Use named `subject(:name)` over un-named `subject` in examples, as this gives the subject a contextual name.
|
||||
- Avoid referencing `subject` in examples. Use a named subject `subject(:name)`, or a `let` variable instead, so
|
||||
the variable has a contextual name.
|
||||
- If the `subject` is never referenced inside examples, then it's acceptable to define the `subject` without a name.
|
||||
|
||||
### Common test setup
|
||||
|
||||
|
|
|
@ -30,12 +30,12 @@ The **Overview** tab provides basic information about the alert:
|
|||
|
||||
![Alert Full Details](./img/alert_detail_full_v13_1.png)
|
||||
|
||||
### Update an Alert's status
|
||||
### Update an alert's status
|
||||
|
||||
The Alert detail view enables you to update the Alert Status.
|
||||
See [Create and manage alerts in GitLab](./alerts.md) for more details.
|
||||
|
||||
### Create an Issue from an Alert
|
||||
### Create an issue from an alert
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/217745) in GitLab 13.1.
|
||||
|
||||
|
@ -47,7 +47,7 @@ alert by clicking the **View Issue** button.
|
|||
Closing a GitLab issue associated with an alert changes the alert's status to Resolved.
|
||||
See [Create and manage alerts in GitLab](alerts.md) for more details about alert statuses.
|
||||
|
||||
### Update an Alert's assignee
|
||||
### Update an alert's assignee
|
||||
|
||||
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3066) in GitLab 13.1.
|
||||
|
||||
|
@ -73,7 +73,7 @@ GitLab currently only supports a single assignee per alert.
|
|||
**{angle-double-right}** **Expand sidebar** to expand it.
|
||||
1. In the right sidebar, locate the **Assignee** and click **Edit**. From the
|
||||
dropdown menu, select each user you want to assign to the alert. GitLab creates
|
||||
a [To-Do list item](../../user/todos.md) for each user.
|
||||
a [to-do list item](../../user/todos.md) for each user.
|
||||
|
||||
![Alert Details View Assignee(s)](./img/alert_todo_assignees_v13_1.png)
|
||||
|
||||
|
@ -96,12 +96,12 @@ The following actions will result in a system note:
|
|||
|
||||
![Alert Details View System Notes](./img/alert_detail_system_notes_v13_1.png)
|
||||
|
||||
### Create a To-Do from an Alert
|
||||
### Create a to-do from an alert
|
||||
|
||||
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3066) in GitLab 13.1.
|
||||
|
||||
You can manually create [To-Do list items](../../user/todos.md) for yourself from the
|
||||
Alert details screen, and view them later on your **To-Do List**. To add a To-Do:
|
||||
Alert details screen, and view them later on your **To-Do List**. To add a to-do:
|
||||
|
||||
1. To display the list of current alerts, click
|
||||
**{cloud-gear}** **Operations > Alerts**.
|
||||
|
@ -110,11 +110,11 @@ Alert details screen, and view them later on your **To-Do List**. To add a To-Do
|
|||
|
||||
![Alert Details Add A To Do](./img/alert_detail_add_todo_v13_1.png)
|
||||
|
||||
Click the **To-Do** **{todo-done}** in the navigation bar to view your current To-Do list.
|
||||
Click the **To-Do** **{todo-done}** in the navigation bar to view your current to-do list.
|
||||
|
||||
![Alert Details Added to Do](./img/alert_detail_added_todo_v13_1.png)
|
||||
|
||||
### View an Alert's metrics data
|
||||
### View an alert's metrics data
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/217768) in GitLab 13.2.
|
||||
|
||||
|
@ -154,7 +154,7 @@ unassign their account from the alert when their role is complete.
|
|||
The alert status can be updated on the [Alert list](./alerts.md) to
|
||||
reflect if the alert has been resolved.
|
||||
|
||||
## View an Alert's logs
|
||||
## View an alert's logs
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/217768) in GitLab 13.3.
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ The GitLab University curriculum is composed of GitLab videos, screencasts, pres
|
|||
1. [Repositories, Projects and Groups - Video](https://www.youtube.com/watch?v=4TWfh1aKHHw&index=1&list=PLFGfElNsQthbQu_IWlNOxul0TbS_2JH-e)
|
||||
1. [Creating a Project in GitLab - Video](https://www.youtube.com/watch?v=7p0hrpNaJ14)
|
||||
1. [How to Create Files and Directories](https://about.gitlab.com/blog/2016/02/10/feature-highlight-create-files-and-directories-from-files-page/)
|
||||
1. [GitLab Todos](https://about.gitlab.com/blog/2016/03/02/gitlab-todos-feature-highlight/)
|
||||
1. [GitLab To-Do List](https://about.gitlab.com/blog/2016/03/02/gitlab-todos-feature-highlight/)
|
||||
1. [GitLab's Work in Progress (WIP) Flag](https://about.gitlab.com/blog/2016/01/08/feature-highlight-wip/)
|
||||
|
||||
### 1.5. Migrating from other Source Control
|
||||
|
|
|
@ -22,11 +22,11 @@ known response, the result is cached for 6 hours.
|
|||
If the external authorization is enabled, GitLab will further block pages and
|
||||
functionality that render cross-project data. That includes:
|
||||
|
||||
- most pages under Dashboard (Activity, Milestones, Snippets, Assigned merge
|
||||
requests, Assigned issues, Todos)
|
||||
- under a specific group (Activity, Contribution analytics, Issues, Issue boards,
|
||||
Labels, Milestones, Merge requests)
|
||||
- Global and Group search will be disabled
|
||||
- Most pages under Dashboard (Activity, Milestones, Snippets, Assigned merge
|
||||
requests, Assigned issues, To-Do List).
|
||||
- Under a specific group (Activity, Contribution analytics, Issues, Issue boards,
|
||||
Labels, Milestones, Merge requests).
|
||||
- Global and Group search will be disabled.
|
||||
|
||||
This is to prevent performing to many requests at once to the external
|
||||
authorization service.
|
||||
|
|
|
@ -88,8 +88,9 @@ investigate it for potential threats by
|
|||
|
||||
The **Threat Monitoring** page's **Policy** tab displays deployed
|
||||
network policies for all available environments. You can check a
|
||||
network policy's `yaml` manifest and toggle the policy's enforcement
|
||||
status. This section has the following prerequisites:
|
||||
network policy's `yaml` manifest, toggle the policy's enforcement
|
||||
status, and create and edit deployed policies. This section has the
|
||||
following prerequisites:
|
||||
|
||||
- Your project contains at least one [environment](../../../ci/environments/index.md)
|
||||
- You've [installed Cilium](../../clusters/applications.md#install-cilium-using-gitlab-cicd)
|
||||
|
@ -124,3 +125,47 @@ Disabled network policies have the
|
|||
`podSelector` block. This narrows the scope of such a policy and as a
|
||||
result it doesn't affect any pods. The policy itself is still deployed
|
||||
to the corresponding deployment namespace.
|
||||
|
||||
### Container Network Policy editor
|
||||
|
||||
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3403) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 13.4.
|
||||
|
||||
The policy editor allows you to create, edit, and delete policies. To
|
||||
create a new policy click the **New policy** button located in the
|
||||
**Policy** tab's header. To edit an existing policy, click**Edit
|
||||
policy** in the selected policy drawer.
|
||||
|
||||
NOTE: **Note:**
|
||||
The policy editor only supports the
|
||||
[CiliumNetworkPolicy](https://docs.cilium.io/en/v1.8/policy/)specification. Regular
|
||||
Kubernetes
|
||||
[NetworkPolicy](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/#networkpolicy-v1-networking-k8s-io)
|
||||
resources aren't supported.
|
||||
|
||||
The policy editor has two modes:
|
||||
|
||||
- The visual _Rule_ mode allows you to construct and preview policy
|
||||
rules using rule blocks and related controls.
|
||||
- YAML mode allows you to enter a policy definition in `.yaml` format
|
||||
and is aimed at expert users and cases that the Rule mode doesn't
|
||||
support.
|
||||
|
||||
You can use both modes interchangeably and switch between them at any
|
||||
time. If a YAML resource is incorrect, Rule mode is automatically
|
||||
disabled. You must use YAML mode to fix your policy before Rule mode
|
||||
is available again.
|
||||
|
||||
Rule mode supports the following rule types:
|
||||
|
||||
- [Labels](https://docs.cilium.io/en/v1.8/policy/language/#labels-based).
|
||||
- [Entities](https://docs.cilium.io/en/v1.8/policy/language/#entities-based).
|
||||
- [IP/CIDR](https://docs.cilium.io/en/v1.8/policy/language/#ip-cidr-based). Only
|
||||
the `toCIDR` block without `except` is supported.
|
||||
- [DNS](https://docs.cilium.io/en/v1.8/policy/language/#dns-based).
|
||||
- [Level 4](https://docs.cilium.io/en/v1.8/policy/language/#layer-4-examples)
|
||||
can be added to all other rules.
|
||||
|
||||
Once your policy is complete, save it by pressing the **Save policy**
|
||||
button at the bottom of the editor. Existing policies can also be
|
||||
removed from the editor interface by clicking the **Delete policy**
|
||||
button at the bottom of the editor.
|
||||
|
|
|
@ -361,7 +361,7 @@ Here are possible causes and solutions:
|
|||
|
||||
Getting both of these errors at the same time suggests the NameID capitalization provided by the Identity Provider didn't exactly match the previous value for that user.
|
||||
|
||||
This can be prevented by configuring the [NameID](#nameid) to return a consistent value. Fixing this for an individual user involves [unlinking SAML in the GitLab account](#unlinking-accounts), although this will cause group membership and Todos to be lost.
|
||||
This can be prevented by configuring the [NameID](#nameid) to return a consistent value. Fixing this for an individual user involves [unlinking SAML in the GitLab account](#unlinking-accounts), although this will cause group membership and to-dos to be lost.
|
||||
|
||||
### Message: "Request to link SAML account must be authorized"
|
||||
|
||||
|
|
|
@ -134,10 +134,10 @@ the best of GitLab Flavored Markdown in your threads, comments,
|
|||
issues and merge requests descriptions, and everywhere else GFM is
|
||||
supported.
|
||||
|
||||
## Todos
|
||||
## To-Do List
|
||||
|
||||
Never forget to reply to your collaborators. [GitLab Todos](todos.md)
|
||||
are a tool for working faster and more effectively with your team,
|
||||
Never forget to reply to your collaborators. [GitLab To-Do List](todos.md)
|
||||
is a tool for working faster and more effectively with your team,
|
||||
by listing all user or group mentions, as well as issues and merge
|
||||
requests you're assigned to.
|
||||
|
||||
|
|
|
@ -144,7 +144,7 @@ Users will be notified of the following events:
|
|||
| New email added | User | Security email, always sent. |
|
||||
| Email changed | User | Security email, always sent. |
|
||||
| Password changed | User | Security email, always sent when user changes their own password |
|
||||
| Password changed by administrator | User | Security email, always sent when an adminstrator changes the password of another user |
|
||||
| Password changed by administrator | User | Security email, always sent when an administrator changes the password of another user |
|
||||
| Two-factor authentication disabled | User | Security email, always sent. |
|
||||
| New user created | User | Sent on user creation, except for OmniAuth (LDAP)|
|
||||
| User added to project | User | Sent when user is added to project |
|
||||
|
|
|
@ -114,7 +114,7 @@ You have 8 options here that you can use for your default dashboard view:
|
|||
- Your projects' activity
|
||||
- Starred projects' activity
|
||||
- Your groups
|
||||
- Your [Todos](../todos.md)
|
||||
- Your [to-dos](../todos.md)
|
||||
- Assigned Issues
|
||||
- Assigned Merge Requests
|
||||
- Operations Dashboard **(PREMIUM)**
|
||||
|
|
|
@ -44,9 +44,9 @@ the icon and the date colored red. You can sort issues by those that are
|
|||
|
||||
![Issues with due dates in the issues index page](img/due_dates_issues_index_page.png)
|
||||
|
||||
Due dates also appear in your [todos list](../../todos.md).
|
||||
Due dates also appear in your [to-do list](../../todos.md).
|
||||
|
||||
![Issues with due dates in the todos](img/due_dates_todos.png)
|
||||
![Issues with due dates in the to-dos](img/due_dates_todos.png)
|
||||
|
||||
The day before an open issue is due, an email will be sent to all participants
|
||||
of the issue. Like the due date, the "day before the due date" is determined by the
|
||||
|
|
|
@ -196,7 +196,7 @@ allowing many formatting options.
|
|||
### Mentions
|
||||
|
||||
You can mention a user or a group present in your GitLab instance with `@username` or
|
||||
`@groupname` and they will be notified via todos and email, unless they have disabled
|
||||
`@groupname` and they will be notified via to-dos and email, unless they have disabled
|
||||
all notifications in their profile settings. This is controlled in the
|
||||
[notification settings](../../profile/notifications.md).
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
type: index, reference
|
||||
---
|
||||
|
||||
# Reviewing and managing merge requests
|
||||
# Reviewing and managing merge requests **(CORE)**
|
||||
|
||||
Merge requests are the primary method of making changes to files in a GitLab project.
|
||||
Changes are proposed by [creating and submitting a merge request](creating_merge_requests.md),
|
||||
|
@ -203,6 +203,11 @@ If there's an [environment](../../../ci/environments/index.md) and the applicati
|
|||
successfully deployed to it, the deployed environment and the link to the
|
||||
Review App will be shown as well.
|
||||
|
||||
NOTE: **Note:**
|
||||
When the default branch (for example, `main`) is red due to a failed CI pipeline, the `merge` button
|
||||
When the pipeline fails in a merge request but it can be merged nonetheless,
|
||||
the **Merge** button will be colored in red.
|
||||
|
||||
### Post-merge pipeline status
|
||||
|
||||
When a merge request is merged, you can see the post-merge pipeline status of
|
||||
|
|
|
@ -5,67 +5,75 @@ group: Project Management
|
|||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
|
||||
---
|
||||
|
||||
# GitLab To-Do List
|
||||
# GitLab To-Do List **(CORE)**
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/2817) in GitLab 8.5.
|
||||
|
||||
When you log into GitLab, you normally want to see where you should spend your
|
||||
time, take some action, or know what you need to keep an eye on without
|
||||
a huge pile of e-mail notifications. GitLab is where you do your work,
|
||||
so being able to get started quickly is important.
|
||||
When you sign in to GitLab, you normally want to determine where you should
|
||||
spend your time. This can include taking an action, or keeping track of things
|
||||
(without having to read lots of email notifications). Because GitLab is where you
|
||||
do your work, being able to get started quickly is important.
|
||||
|
||||
Your To-Do List offers a chronological list of items that are waiting for your input, all
|
||||
in a simple dashboard.
|
||||
Your *To-Do List* offers a chronological list of items waiting for your input
|
||||
(known as *to-dos*) in a single dashboard.
|
||||
|
||||
![To Do screenshot showing a list of items to check on](img/todos_index.png)
|
||||
The To-Do List supports tracking [actions](#what-triggers-a-to-do) related to
|
||||
the following:
|
||||
|
||||
You can quickly access your To-Do List by clicking the checkmark icon next to the
|
||||
search bar in the top navigation. If the count is:
|
||||
- Issues
|
||||
- Merge Requests
|
||||
- Epics **(ULTIMATE)**
|
||||
|
||||
- Less than 100, the number in blue is the number of To-Do items.
|
||||
- 100 or more, the number displays as 99+. The exact number displays
|
||||
on the To-Do List.
|
||||
you still have open. Otherwise, the number displays as 99+. The exact number
|
||||
displays on the To-Do List.
|
||||
![to-do screenshot showing a list of items to check on](img/todos_index.png)
|
||||
|
||||
You can access your To-Do List by clicking the **{task-done}** To-Do List icon
|
||||
next to the search bar in the top navigation. If the to-do item count is:
|
||||
|
||||
- *Less than 100*, the number in blue is the number of to-do items.
|
||||
- *100 or more*, the number displays as 99+. The exact number displays in the
|
||||
To-Do List.
|
||||
|
||||
![To Do icon](img/todos_icon.png)
|
||||
|
||||
## What triggers a To Do
|
||||
## What triggers a to-do
|
||||
|
||||
A To Do appears on your To-Do List when:
|
||||
A to-do item appears on your To-Do List when:
|
||||
|
||||
- An issue or merge request is assigned to you
|
||||
- You are `@mentioned` in the description or comment of an:
|
||||
- Issue
|
||||
- Merge Request
|
||||
- Epic **(ULTIMATE)**
|
||||
- An issue or merge request is assigned to you.
|
||||
- You're `@mentioned` in the description or comment of an issue or merge request
|
||||
(or epic **(ULTIMATE)**).
|
||||
- You are `@mentioned` in a comment on a:
|
||||
- Commit
|
||||
- Design
|
||||
- The CI/CD pipeline for your merge request failed
|
||||
- An open merge request becomes unmergeable due to conflict, and one of the following is true:
|
||||
- You are the author
|
||||
- You are the user that set it to automatically merge once the pipeline succeeds
|
||||
- [Since GitLab 13.2](https://gitlab.com/gitlab-org/gitlab/-/issues/12136), a merge request
|
||||
is removed from a [merge train](../ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/index.md)
|
||||
and you are the user that added it. **(PREMIUM)**
|
||||
- The CI/CD pipeline for your merge request failed.
|
||||
- An open merge request becomes unmergeable due to conflict, and one of the
|
||||
following is true:
|
||||
- You're the author.
|
||||
- You're the user that set the merge request to automatically merge after a
|
||||
pipeline succeeds.
|
||||
- [Since GitLab 13.2](https://gitlab.com/gitlab-org/gitlab/-/issues/12136), a
|
||||
merge request is removed from a
|
||||
[merge train](../ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/index.md),
|
||||
and you're the user that added it. **(PREMIUM)**
|
||||
|
||||
When multiple trigger actions occur for the same user on the same object (for example, an issue)
|
||||
only the first is displayed as a single to-do on their To-Do List.
|
||||
When several trigger actions occur for the same user on the same object (for
|
||||
example, an issue), GitLab displays only the first action as a single to-do
|
||||
item.
|
||||
|
||||
To-do triggers are not affected by [GitLab Notification Email settings](profile/notifications.md).
|
||||
To-do triggers aren't affected by [GitLab notification email settings](profile/notifications.md).
|
||||
|
||||
NOTE: **Note:**
|
||||
When a user no longer has access to a resource related to a To Do (like an issue, merge request,
|
||||
project, or group) the related To-Do items are deleted within the next hour for security reasons.
|
||||
The delete is delayed to prevent data loss, in case the user's access was revoked by mistake.
|
||||
When a user no longer has access to a resource related to a to-do (such as an
|
||||
issue, merge request, project, or group), for security reasons GitLab deletes
|
||||
any related to-do items within the next hour. Deletion is delayed to prevent
|
||||
data loss, in the case where a user's access is accidentally revoked.
|
||||
|
||||
### Directly addressing a To Do
|
||||
### Directly addressing a to-do
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/7926) in GitLab 9.0.
|
||||
|
||||
If you are mentioned at the start of a line, the To Do you receive will be listed
|
||||
as 'directly addressed'. For example, in this comment:
|
||||
If you're mentioned at the start of a line, the to-do you receive will be listed
|
||||
as *directly addressed*. For example, in the following comment:
|
||||
|
||||
```markdown
|
||||
@alice What do you think? cc: @bob
|
||||
|
@ -79,81 +87,71 @@ as 'directly addressed'. For example, in this comment:
|
|||
@erin @frank thank you!
|
||||
```
|
||||
|
||||
The people receiving directly addressed To-Do items are `@alice`, `@erin`, and
|
||||
`@frank`. Directly addressed To-Do items only differ from mentions in their type
|
||||
The people receiving directly addressed to-do items are `@alice`, `@erin`, and
|
||||
`@frank`. Directly addressed to-do items only differ from mentions in their type
|
||||
for filtering purposes; otherwise, they appear as normal.
|
||||
|
||||
### Manually creating a To Do
|
||||
### Manually creating a to-do
|
||||
|
||||
You can also add the following to your To-Do List by clicking the **Add a To Do** button on an:
|
||||
|
||||
- Issue
|
||||
- Merge Request
|
||||
- Epic **(ULTIMATE)**
|
||||
You can add an issue or merge request (or epic **(ULTIMATE)**) to your
|
||||
To-Do List by clicking its **Add a To Do** button.
|
||||
|
||||
![Adding a To Do from the issuable sidebar](img/todos_add_todo_sidebar.png)
|
||||
|
||||
## Marking a To Do as done
|
||||
## Marking a to-do as done
|
||||
|
||||
Any action to the following will mark the corresponding To Do as done:
|
||||
Any action to an issue or merge request (or epic **(ULTIMATE)**) will mark its
|
||||
corresponding to-do as done.
|
||||
|
||||
- Issue
|
||||
- Merge Request
|
||||
- Epic **(ULTIMATE)**
|
||||
|
||||
Actions that dismiss To-Do items include:
|
||||
Actions that dismiss to-do items include:
|
||||
|
||||
- Changing the assignee
|
||||
- Changing the milestone
|
||||
- Adding/removing a label
|
||||
- Commenting on the issue
|
||||
|
||||
Your To-Do List is personal, and items are only marked as done if the action comes from
|
||||
you. If you close the issue or merge request, your To Do is automatically
|
||||
marked as done.
|
||||
Your To-Do List is personal, and items are only marked as done if you take
|
||||
action. If you close the issue or merge request, your to-do is marked as done.
|
||||
|
||||
To prevent other users from closing issues without you being notified, if someone else closes, merges, or takes action on the any of the following, your To Do will remain pending:
|
||||
To prevent other users from closing issues without you being notified, if
|
||||
someone else closes, merges, or takes action on an issue or merge request (or
|
||||
epic **(ULTIMATE)**), your to-do will remain pending.
|
||||
|
||||
- Issue
|
||||
- Merge request
|
||||
- Epic **(ULTIMATE)**
|
||||
There's just one to-do for each of these, so mentioning a user many times in an
|
||||
issue will only trigger one to-do item.
|
||||
|
||||
There is just one To Do for each of these, so mentioning a user a hundred times in an issue will only trigger one To Do.
|
||||
If no action is needed, you can manually mark the to-do as done by clicking its
|
||||
corresponding **Done** button to have GitLab remove the item from your
|
||||
To-Do List.
|
||||
|
||||
If no action is needed, you can manually mark the To Do as done by clicking the
|
||||
corresponding **Done** button, and it will disappear from your To-Do List.
|
||||
![A to-do in the To-Do List](img/todos_todo_list_item.png)
|
||||
|
||||
![A To Do in the To-Do List](img/todos_todo_list_item.png)
|
||||
|
||||
You can also mark a To Do as done by clicking the **Mark as done** button in the sidebar of the following:
|
||||
|
||||
- Issue
|
||||
- Merge Request
|
||||
- Epic **(ULTIMATE)**
|
||||
You can also mark a to-do as done by clicking the **Mark as done** button in the
|
||||
sidebar of an issue or merge request (or epic **(ULTIMATE)**).
|
||||
|
||||
![Mark as done from the issuable sidebar](img/todos_mark_done_sidebar.png)
|
||||
|
||||
You can mark all your To-Do items as done at once by clicking the **Mark all as
|
||||
done** button.
|
||||
You can mark all your to-do items as done at once by clicking the
|
||||
**Mark all as done** button.
|
||||
|
||||
## Filtering your To-Do List
|
||||
|
||||
There are four kinds of filters you can use on your To-Do List.
|
||||
You can use the following types of filters with your To-Do List:
|
||||
|
||||
| Filter | Description |
|
||||
| ------- | ----------- |
|
||||
| Project | Filter by project |
|
||||
| Group | Filter by group |
|
||||
| Author | Filter by the author that triggered the To Do |
|
||||
| Type | Filter by issue, merge request, design, or epic **(ULTIMATE)** |
|
||||
| Action | Filter by the action that triggered the To Do |
|
||||
| Filter | Description |
|
||||
| ------- | ---------------------------------------------------------------- |
|
||||
| Project | Filter by project. |
|
||||
| Group | Filter by group. |
|
||||
| Author | Filter by the author that triggered the To Do. |
|
||||
| Type | Filter by issue, merge request, design, or epic. **(ULTIMATE)** |
|
||||
| Action | Filter by the action that triggered the To Do. |
|
||||
|
||||
You can also filter by more than one of these at the same time. The possible Actions are
|
||||
[described above](#what-triggers-a-to-do) and include:
|
||||
You can also filter by more than one of these at the same time. The previously
|
||||
described [triggering actions](#what-triggers-a-to-do) include:
|
||||
|
||||
- Any Action
|
||||
- Any action
|
||||
- Assigned
|
||||
- Mentioned
|
||||
- Added
|
||||
- Pipelines
|
||||
- Directly Addressed
|
||||
- Directly addressed
|
||||
|
|
|
@ -17,7 +17,7 @@ module API
|
|||
end
|
||||
|
||||
def process_metrics
|
||||
Sidekiq::ProcessSet.new.map do |process|
|
||||
Sidekiq::ProcessSet.new(false).map do |process|
|
||||
{
|
||||
hostname: process['hostname'],
|
||||
pid: process['pid'],
|
||||
|
|
|
@ -7005,6 +7005,9 @@ msgstr ""
|
|||
msgid "Contributions per group member"
|
||||
msgstr ""
|
||||
|
||||
msgid "Contributor"
|
||||
msgstr ""
|
||||
|
||||
msgid "Contributors"
|
||||
msgstr ""
|
||||
|
||||
|
@ -25843,9 +25846,6 @@ msgstr ""
|
|||
msgid "This is a security log of important events involving your account."
|
||||
msgstr ""
|
||||
|
||||
msgid "This is the author's first Merge Request to this project."
|
||||
msgstr ""
|
||||
|
||||
msgid "This is the highest peak of users on your installation since the license started."
|
||||
msgstr ""
|
||||
|
||||
|
@ -26083,6 +26083,15 @@ msgstr ""
|
|||
msgid "This user has no identities"
|
||||
msgstr ""
|
||||
|
||||
msgid "This user has previously committed to the %{name} project."
|
||||
msgstr ""
|
||||
|
||||
msgid "This user is a %{access} of the %{name} project."
|
||||
msgstr ""
|
||||
|
||||
msgid "This user is the author of this %{noteable}."
|
||||
msgstr ""
|
||||
|
||||
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -6,6 +6,10 @@ RSpec.describe 'Markdown keyboard shortcuts', :js do
|
|||
let_it_be(:project) { create(:project, :repository) }
|
||||
let_it_be(:user) { create(:user) }
|
||||
|
||||
let(:is_mac) { page.evaluate_script('navigator.platform').include?('Mac') }
|
||||
let(:modifier_key) { is_mac ? :command : :control }
|
||||
let(:other_modifier_key) { is_mac ? :control : :command }
|
||||
|
||||
before do
|
||||
project.add_developer(user)
|
||||
|
||||
|
@ -16,7 +20,7 @@ RSpec.describe 'Markdown keyboard shortcuts', :js do
|
|||
wait_for_requests
|
||||
end
|
||||
|
||||
shared_examples 'keyboard shortcuts for modifier key' do
|
||||
shared_examples 'keyboard shortcuts' do
|
||||
it 'bolds text when <modifier>+B is pressed' do
|
||||
type_and_select('bold')
|
||||
|
||||
|
@ -57,17 +61,29 @@ RSpec.describe 'Markdown keyboard shortcuts', :js do
|
|||
end
|
||||
end
|
||||
|
||||
shared_examples 'keyboard shortcuts for implementation' do
|
||||
context 'Ctrl key' do
|
||||
let(:modifier_key) { :control }
|
||||
shared_examples 'no side effects' do
|
||||
it 'does not bold text when <other modifier>+B is pressed' do
|
||||
type_and_select('bold')
|
||||
|
||||
it_behaves_like 'keyboard shortcuts for modifier key'
|
||||
markdown_field.send_keys([@other_modifier_key, 'b'])
|
||||
|
||||
expect(markdown_field.value).not_to eq('**bold**')
|
||||
end
|
||||
|
||||
context '⌘ key' do
|
||||
let(:modifier_key) { :command }
|
||||
it 'does not italicize text when <other modifier>+I is pressed' do
|
||||
type_and_select('italic')
|
||||
|
||||
it_behaves_like 'keyboard shortcuts for modifier key'
|
||||
markdown_field.send_keys([@other_modifier_key, 'i'])
|
||||
|
||||
expect(markdown_field.value).not_to eq('_italic_')
|
||||
end
|
||||
|
||||
it 'does not link text when <other modifier>+K is pressed' do
|
||||
type_and_select('link')
|
||||
|
||||
markdown_field.send_keys([@other_modifier_key, 'k'])
|
||||
|
||||
expect(markdown_field.value).not_to eq('[link](url)')
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -76,7 +92,8 @@ RSpec.describe 'Markdown keyboard shortcuts', :js do
|
|||
let(:markdown_field) { find_field('Release notes') }
|
||||
let(:non_markdown_field) { find_field('Release title') }
|
||||
|
||||
it_behaves_like 'keyboard shortcuts for implementation'
|
||||
it_behaves_like 'keyboard shortcuts'
|
||||
it_behaves_like 'no side effects'
|
||||
end
|
||||
|
||||
context 'Haml markdown editor' do
|
||||
|
@ -84,7 +101,8 @@ RSpec.describe 'Markdown keyboard shortcuts', :js do
|
|||
let(:markdown_field) { find_field('Description') }
|
||||
let(:non_markdown_field) { find_field('Title') }
|
||||
|
||||
it_behaves_like 'keyboard shortcuts for implementation'
|
||||
it_behaves_like 'keyboard shortcuts'
|
||||
it_behaves_like 'no side effects'
|
||||
end
|
||||
|
||||
def type_and_select(text)
|
||||
|
|
|
@ -60,6 +60,9 @@
|
|||
"resolve_with_issue_path": { "type": "string" },
|
||||
"cached_markdown_version": { "type": "integer" },
|
||||
"human_access": { "type": ["string", "null"] },
|
||||
"is_noteable_author": { "type": "boolean" },
|
||||
"is_contributor": { "type": "boolean" },
|
||||
"project_name": { "type": "string" },
|
||||
"toggle_award_path": { "type": "string" },
|
||||
"path": { "type": "string" },
|
||||
"commands_changes": { "type": "object", "additionalProperties": true },
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
import { GlBanner } from '@gitlab/ui';
|
||||
import InviteMembersBanner from '~/groups/components/invite_members_banner.vue';
|
||||
import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
|
||||
import { setCookie, parseBoolean } from '~/lib/utils/common_utils';
|
||||
import InviteMembersBanner from '~/groups/components/invite_members_banner.vue';
|
||||
|
||||
jest.mock('~/lib/utils/common_utils');
|
||||
|
||||
|
@ -12,6 +13,7 @@ const body =
|
|||
const svgPath = '/illustrations/background';
|
||||
const inviteMembersPath = 'groups/members';
|
||||
const buttonText = 'Invite your colleagues';
|
||||
const trackLabel = 'invite_members_banner';
|
||||
|
||||
const createComponent = (stubs = {}) => {
|
||||
return shallowMount(InviteMembersBanner, {
|
||||
|
@ -19,6 +21,7 @@ const createComponent = (stubs = {}) => {
|
|||
svgPath,
|
||||
inviteMembersPath,
|
||||
isDismissedKey,
|
||||
trackLabel,
|
||||
},
|
||||
stubs,
|
||||
});
|
||||
|
@ -26,10 +29,51 @@ const createComponent = (stubs = {}) => {
|
|||
|
||||
describe('InviteMembersBanner', () => {
|
||||
let wrapper;
|
||||
let trackingSpy;
|
||||
|
||||
beforeEach(() => {
|
||||
document.body.dataset.page = 'any:page';
|
||||
trackingSpy = mockTracking('_category_', undefined, jest.spyOn);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
wrapper = null;
|
||||
unmockTracking();
|
||||
});
|
||||
|
||||
describe('tracking', () => {
|
||||
beforeEach(() => {
|
||||
wrapper = createComponent({ GlBanner });
|
||||
});
|
||||
|
||||
const trackCategory = undefined;
|
||||
const displayEvent = 'invite_members_banner_displayed';
|
||||
const buttonClickEvent = 'invite_members_banner_button_clicked';
|
||||
const dismissEvent = 'invite_members_banner_dismissed';
|
||||
|
||||
it('sends the displayEvent when the banner is displayed', () => {
|
||||
expect(trackingSpy).toHaveBeenCalledWith(trackCategory, displayEvent, {
|
||||
label: trackLabel,
|
||||
});
|
||||
});
|
||||
|
||||
it('sets the button attributes for the buttonClickEvent', () => {
|
||||
const button = wrapper.find(`[href='${wrapper.vm.inviteMembersPath}']`);
|
||||
|
||||
expect(button.attributes()).toMatchObject({
|
||||
'data-track-event': buttonClickEvent,
|
||||
'data-track-label': trackLabel,
|
||||
});
|
||||
});
|
||||
|
||||
it('sends the dismissEvent when the banner is dismissed', () => {
|
||||
wrapper.find(GlBanner).vm.$emit('close');
|
||||
|
||||
expect(trackingSpy).toHaveBeenCalledWith(trackCategory, dismissEvent, {
|
||||
label: trackLabel,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('rendering', () => {
|
||||
|
|
|
@ -35,8 +35,12 @@ describe('noteActions', () => {
|
|||
canEdit: true,
|
||||
canAwardEmoji: true,
|
||||
canReportAsAbuse: true,
|
||||
isAuthor: true,
|
||||
isContributor: false,
|
||||
noteableType: 'MergeRequest',
|
||||
noteId: '539',
|
||||
noteUrl: `${TEST_HOST}/group/project/-/merge_requests/1#note_1`,
|
||||
projectName: 'project',
|
||||
reportAbusePath: `${TEST_HOST}/abuse_reports/new?ref_url=http%3A%2F%2Flocalhost%3A3000%2Fgitlab-org%2Fgitlab-ce%2Fissues%2F7%23note_539&user_id=26`,
|
||||
showReply: false,
|
||||
};
|
||||
|
@ -60,15 +64,43 @@ describe('noteActions', () => {
|
|||
wrapper = shallowMountNoteActions(props);
|
||||
});
|
||||
|
||||
it('should render noteable author badge', () => {
|
||||
expect(
|
||||
wrapper
|
||||
.findAll('.note-role')
|
||||
.at(0)
|
||||
.text()
|
||||
.trim(),
|
||||
).toEqual('Author');
|
||||
});
|
||||
|
||||
it('should render access level badge', () => {
|
||||
expect(
|
||||
wrapper
|
||||
.find('.note-role')
|
||||
.findAll('.note-role')
|
||||
.at(1)
|
||||
.text()
|
||||
.trim(),
|
||||
).toEqual(props.accessLevel);
|
||||
});
|
||||
|
||||
it('should render contributor badge', () => {
|
||||
wrapper.setProps({
|
||||
accessLevel: null,
|
||||
isContributor: true,
|
||||
});
|
||||
|
||||
return wrapper.vm.$nextTick().then(() => {
|
||||
expect(
|
||||
wrapper
|
||||
.findAll('.note-role')
|
||||
.at(1)
|
||||
.text()
|
||||
.trim(),
|
||||
).toBe('Contributor');
|
||||
});
|
||||
});
|
||||
|
||||
it('should render emoji link', () => {
|
||||
expect(wrapper.find('.js-add-award').exists()).toBe(true);
|
||||
expect(wrapper.find('.js-add-award').attributes('data-position')).toBe('right');
|
||||
|
|
|
@ -63,9 +63,9 @@ describe('Shortcuts', () => {
|
|||
// Get all shortcuts specified with md-shortcuts attributes in the fixture.
|
||||
// `shortcuts` will look something like this:
|
||||
// [
|
||||
// [ 'command+b', 'ctrl+b' ],
|
||||
// [ 'command+i', 'ctrl+i' ],
|
||||
// [ 'command+k', 'ctrl+k' ]
|
||||
// [ 'mod+b' ],
|
||||
// [ 'mod+i' ],
|
||||
// [ 'mod+k' ]
|
||||
// ]
|
||||
shortcuts = $('.edit-note .js-md')
|
||||
.map(function getShortcutsFromToolbarBtn() {
|
||||
|
|
|
@ -653,6 +653,19 @@ RSpec.describe Group do
|
|||
expect(shared_group.max_member_access_for_user(user)).to eq(Gitlab::Access::MAINTAINER)
|
||||
end
|
||||
end
|
||||
|
||||
context 'evaluating admin access level' do
|
||||
let_it_be(:admin) { create(:admin) }
|
||||
|
||||
it 'returns OWNER by default' do
|
||||
expect(group.max_member_access_for_user(admin)).to eq(Gitlab::Access::OWNER)
|
||||
end
|
||||
|
||||
it 'returns NO_ACCESS when only concrete membership should be considered' do
|
||||
expect(group.max_member_access_for_user(admin, only_concrete_membership: true))
|
||||
.to eq(Gitlab::Access::NO_ACCESS)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#members_with_parents' do
|
||||
|
|
|
@ -286,6 +286,56 @@ RSpec.describe Note do
|
|||
end
|
||||
end
|
||||
|
||||
describe "noteable_author?" do
|
||||
let(:user1) { create(:user) }
|
||||
let(:user2) { create(:user) }
|
||||
let(:project) { create(:project, :public, :repository) }
|
||||
|
||||
context 'when note is on commit' do
|
||||
let(:noteable) { create(:commit, project: project, author: user1) }
|
||||
|
||||
context 'if user is the noteable author' do
|
||||
let(:note) { create(:discussion_note_on_commit, commit_id: noteable.id, project: project, author: user1) }
|
||||
let(:diff_note) { create(:diff_note_on_commit, commit_id: noteable.id, project: project, author: user1) }
|
||||
|
||||
it 'returns true' do
|
||||
expect(note.noteable_author?(noteable)).to be true
|
||||
expect(diff_note.noteable_author?(noteable)).to be true
|
||||
end
|
||||
end
|
||||
|
||||
context 'if user is not the noteable author' do
|
||||
let(:note) { create(:discussion_note_on_commit, commit_id: noteable.id, project: project, author: user2) }
|
||||
let(:diff_note) { create(:diff_note_on_commit, commit_id: noteable.id, project: project, author: user2) }
|
||||
|
||||
it 'returns false' do
|
||||
expect(note.noteable_author?(noteable)).to be false
|
||||
expect(diff_note.noteable_author?(noteable)).to be false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when note is on issue' do
|
||||
let(:noteable) { create(:issue, project: project, author: user1) }
|
||||
|
||||
context 'if user is the noteable author' do
|
||||
let(:note) { create(:note, noteable: noteable, author: user1, project: project) }
|
||||
|
||||
it 'returns true' do
|
||||
expect(note.noteable_author?(noteable)).to be true
|
||||
end
|
||||
end
|
||||
|
||||
context 'if user is not the noteable author' do
|
||||
let(:note) { create(:note, noteable: noteable, author: user2, project: project) }
|
||||
|
||||
it 'returns false' do
|
||||
expect(note.noteable_author?(noteable)).to be false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "edited?" do
|
||||
let(:note) { build(:note, updated_by_id: nil, created_at: Time.current, updated_at: Time.current + 5.hours) }
|
||||
|
||||
|
@ -1228,22 +1278,6 @@ RSpec.describe Note do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#special_role=' do
|
||||
let(:role) { Note::SpecialRole::FIRST_TIME_CONTRIBUTOR }
|
||||
|
||||
it 'assigns role' do
|
||||
subject.special_role = role
|
||||
|
||||
expect(subject.special_role).to eq(role)
|
||||
end
|
||||
|
||||
it 'does not assign unknown role' do
|
||||
expect { subject.special_role = :bogus }.to raise_error(/Role is undefined/)
|
||||
|
||||
expect(subject.special_role).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
describe '#parent' do
|
||||
it 'returns project for project notes' do
|
||||
project = create(:project)
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
require "spec_helper"
|
||||
|
||||
RSpec.describe ProjectTeam do
|
||||
include ProjectForksHelper
|
||||
|
||||
let(:maintainer) { create(:user) }
|
||||
let(:reporter) { create(:user) }
|
||||
let(:guest) { create(:user) }
|
||||
|
@ -237,6 +239,35 @@ RSpec.describe ProjectTeam do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#contributor?' do
|
||||
let(:project) { create(:project, :public, :repository) }
|
||||
|
||||
context 'when user is a member of project' do
|
||||
before do
|
||||
project.add_maintainer(maintainer)
|
||||
project.add_reporter(reporter)
|
||||
project.add_guest(guest)
|
||||
end
|
||||
|
||||
it { expect(project.team.contributor?(maintainer.id)).to be false }
|
||||
it { expect(project.team.contributor?(reporter.id)).to be false }
|
||||
it { expect(project.team.contributor?(guest.id)).to be false }
|
||||
end
|
||||
|
||||
context 'when user has at least one merge request merged into default_branch' do
|
||||
let(:contributor) { create(:user) }
|
||||
let(:user_without_access) { create(:user) }
|
||||
let(:first_fork_project) { fork_project(project, contributor, repository: true) }
|
||||
|
||||
before do
|
||||
create(:merge_request, :merged, author: contributor, target_project: project, source_project: first_fork_project, target_branch: project.default_branch.to_s)
|
||||
end
|
||||
|
||||
it { expect(project.team.contributor?(contributor.id)).to be true }
|
||||
it { expect(project.team.contributor?(user_without_access.id)).to be false }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#max_member_access' do
|
||||
let(:requester) { create(:user) }
|
||||
|
||||
|
@ -366,6 +397,66 @@ RSpec.describe ProjectTeam do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#contribution_check_for_user_ids', :request_store do
|
||||
let(:project) { create(:project, :public, :repository) }
|
||||
let(:contributor) { create(:user) }
|
||||
let(:second_contributor) { create(:user) }
|
||||
let(:user_without_access) { create(:user) }
|
||||
let(:first_fork_project) { fork_project(project, contributor, repository: true) }
|
||||
let(:second_fork_project) { fork_project(project, second_contributor, repository: true) }
|
||||
|
||||
let(:users) do
|
||||
[contributor, second_contributor, user_without_access].map(&:id)
|
||||
end
|
||||
|
||||
let(:expected) do
|
||||
{
|
||||
contributor.id => true,
|
||||
second_contributor.id => true,
|
||||
user_without_access.id => false
|
||||
}
|
||||
end
|
||||
|
||||
before do
|
||||
create(:merge_request, :merged, author: contributor, target_project: project, source_project: first_fork_project, target_branch: project.default_branch.to_s)
|
||||
create(:merge_request, :merged, author: second_contributor, target_project: project, source_project: second_fork_project, target_branch: project.default_branch.to_s)
|
||||
end
|
||||
|
||||
def contributors(users)
|
||||
project.team.contribution_check_for_user_ids(users)
|
||||
end
|
||||
|
||||
it 'does not perform extra queries when asked for users who have already been found' do
|
||||
contributors(users)
|
||||
|
||||
expect { contributors([contributor.id]) }.not_to exceed_query_limit(0)
|
||||
|
||||
expect(contributors([contributor.id])).to eq(expected)
|
||||
end
|
||||
|
||||
it 'only requests the extra users when uncached users are passed' do
|
||||
new_contributor = create(:user)
|
||||
new_fork_project = fork_project(project, new_contributor, repository: true)
|
||||
second_new_user = create(:user)
|
||||
all_users = users + [new_contributor.id, second_new_user.id]
|
||||
create(:merge_request, :merged, author: new_contributor, target_project: project, source_project: new_fork_project, target_branch: project.default_branch.to_s)
|
||||
|
||||
expected_all = expected.merge(new_contributor.id => true,
|
||||
second_new_user.id => false)
|
||||
|
||||
contributors(users)
|
||||
|
||||
queries = ActiveRecord::QueryRecorder.new { contributors(all_users) }
|
||||
|
||||
expect(queries.count).to eq(1)
|
||||
expect(contributors([new_contributor.id])).to eq(expected_all)
|
||||
end
|
||||
|
||||
it 'returns correct contributors' do
|
||||
expect(contributors(users)).to eq(expected)
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'max member access for users' do
|
||||
let(:project) { create(:project) }
|
||||
let(:group) { create(:group) }
|
||||
|
@ -438,9 +529,9 @@ RSpec.describe ProjectTeam do
|
|||
it 'does not perform extra queries when asked for users who have already been found' do
|
||||
access_levels(users)
|
||||
|
||||
expect { access_levels(users) }.not_to exceed_query_limit(0)
|
||||
expect { access_levels([maintainer.id]) }.not_to exceed_query_limit(0)
|
||||
|
||||
expect(access_levels(users)).to eq(expected)
|
||||
expect(access_levels([maintainer.id])).to eq(expected)
|
||||
end
|
||||
|
||||
it 'only requests the extra users when uncached users are passed' do
|
||||
|
|
|
@ -490,6 +490,25 @@ RSpec.describe API::Projects do
|
|||
expect(json_response.first['name']).to eq(project4.name)
|
||||
expect(json_response.first['owner']['username']).to eq(user4.username)
|
||||
end
|
||||
|
||||
context 'when admin creates a project' do
|
||||
before do
|
||||
group = create(:group)
|
||||
project_create_opts = {
|
||||
name: 'GitLab',
|
||||
namespace_id: group.id
|
||||
}
|
||||
|
||||
Projects::CreateService.new(admin, project_create_opts).execute
|
||||
end
|
||||
|
||||
it 'does not list as owned project for admin' do
|
||||
get api('/projects', admin), params: { owned: true }
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(json_response).to be_empty
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'and with starred=true' do
|
||||
|
|
Loading…
Reference in New Issue