Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
c2afac6a37
commit
3ce7340b2a
|
@ -47,6 +47,11 @@ export const METRICS_POPOVER_CONTENT = {
|
|||
"ValueStreamAnalytics|Median time from the earliest commit of a linked issue's merge request to when that issue is closed.",
|
||||
),
|
||||
},
|
||||
'lead-time-for-changes': {
|
||||
description: s__(
|
||||
'ValueStreamAnalytics|Median time between merge request merge and deployment to a production environment for all MRs deployed in the given time period.',
|
||||
),
|
||||
},
|
||||
'new-issue': { description: s__('ValueStreamAnalytics|Number of new issues created.') },
|
||||
'new-issues': { description: s__('ValueStreamAnalytics|Number of new issues created.') },
|
||||
deploys: { description: s__('ValueStreamAnalytics|Total number of deploys to production.') },
|
||||
|
|
|
@ -29,6 +29,11 @@ export default {
|
|||
required: false,
|
||||
default: false,
|
||||
},
|
||||
lineRange: {
|
||||
type: Object,
|
||||
required: false,
|
||||
default: null,
|
||||
},
|
||||
linePosition: {
|
||||
type: String,
|
||||
required: false,
|
||||
|
@ -59,6 +64,7 @@ export default {
|
|||
<diff-line-note-form
|
||||
:diff-file-hash="diffFileHash"
|
||||
:line="line"
|
||||
:range="lineRange"
|
||||
:note-target-line="line"
|
||||
:help-page-path="helpPagePath"
|
||||
:line-position="linePosition"
|
||||
|
|
|
@ -32,6 +32,11 @@ export default {
|
|||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
range: {
|
||||
type: Object,
|
||||
required: false,
|
||||
default: null,
|
||||
},
|
||||
linePosition: {
|
||||
type: String,
|
||||
required: false,
|
||||
|
@ -49,6 +54,7 @@ export default {
|
|||
},
|
||||
data() {
|
||||
return {
|
||||
lines: null,
|
||||
commentLineStart: {
|
||||
line_code: this.line.line_code,
|
||||
type: this.line.type,
|
||||
|
@ -116,10 +122,8 @@ export default {
|
|||
return commentLineOptions(lines, this.line, this.line.line_code, side);
|
||||
},
|
||||
commentLines() {
|
||||
if (!this.selectedCommentPosition) return [];
|
||||
|
||||
const lines = [];
|
||||
const { start, end } = this.selectedCommentPosition;
|
||||
const { start, end } = this.lines;
|
||||
const diffLines = this.diffFile[INLINE_DIFF_LINES_KEY];
|
||||
let isAdding = false;
|
||||
|
||||
|
@ -144,6 +148,9 @@ export default {
|
|||
return lines;
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.lines = { ...this.range };
|
||||
},
|
||||
mounted() {
|
||||
if (this.isLoggedIn) {
|
||||
const keys = [
|
||||
|
@ -189,6 +196,9 @@ export default {
|
|||
this.handleCancelCommentForm(),
|
||||
);
|
||||
},
|
||||
updateStartLine(line) {
|
||||
this.lines.start = line;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@ -199,7 +209,9 @@ export default {
|
|||
<multiline-comment-form
|
||||
v-model="commentLineStart"
|
||||
:line="line"
|
||||
:line-range="lines"
|
||||
:comment-line-options="commentLineOptions"
|
||||
@input="updateStartLine"
|
||||
/>
|
||||
</div>
|
||||
<note-form
|
||||
|
|
|
@ -6,6 +6,7 @@ import draftCommentsMixin from '~/diffs/mixins/draft_comments';
|
|||
import { getCommentedLines } from '~/notes/components/multiline_comment_utils';
|
||||
import { hide } from '~/tooltips';
|
||||
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import { pickDirection } from '../utils/diff_line';
|
||||
import DiffCommentCell from './diff_comment_cell.vue';
|
||||
import DiffExpansionCell from './diff_expansion_cell.vue';
|
||||
import DiffRow from './diff_row.vue';
|
||||
|
@ -106,6 +107,16 @@ export default {
|
|||
});
|
||||
this.idState.dragStart = null;
|
||||
},
|
||||
singleLineComment(code, line) {
|
||||
const lineDir = pickDirection({ line, code });
|
||||
|
||||
this.idState.updatedLineRange = {
|
||||
start: lineDir,
|
||||
end: lineDir,
|
||||
};
|
||||
|
||||
this.showCommentForm({ lineCode: lineDir.line_code, fileHash: this.diffFile.file_hash });
|
||||
},
|
||||
isHighlighted(line) {
|
||||
return isHighlighted(
|
||||
this.highlightedRow,
|
||||
|
@ -169,7 +180,7 @@ export default {
|
|||
:index="index"
|
||||
:is-highlighted="isHighlighted(line)"
|
||||
:file-line-coverage="fileLineCoverage"
|
||||
@showCommentForm="(lineCode) => showCommentForm({ lineCode, fileHash: diffFile.file_hash })"
|
||||
@showCommentForm="(code) => singleLineComment(code, line)"
|
||||
@setHighlightedRow="setHighlightedRow"
|
||||
@toggleLineDiscussions="
|
||||
({ lineCode, expanded }) =>
|
||||
|
@ -193,6 +204,7 @@ export default {
|
|||
<diff-comment-cell
|
||||
v-if="line.left && (line.left.renderDiscussion || line.left.hasCommentForm)"
|
||||
:line="line.left"
|
||||
:line-range="idState.updatedLineRange"
|
||||
:diff-file-hash="diffFile.file_hash"
|
||||
:help-page-path="helpPagePath"
|
||||
line-position="left"
|
||||
|
@ -206,6 +218,7 @@ export default {
|
|||
<diff-comment-cell
|
||||
v-if="line.right && (line.right.renderDiscussion || line.right.hasCommentForm)"
|
||||
:line="line.right"
|
||||
:line-range="idState.updatedLineRange"
|
||||
:diff-file-hash="diffFile.file_hash"
|
||||
:line-index="index"
|
||||
:help-page-path="helpPagePath"
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
export function pickDirection({ line, code } = {}) {
|
||||
const { left, right } = line;
|
||||
let direction = left || right;
|
||||
|
||||
if (right?.line_code === code) {
|
||||
direction = right;
|
||||
}
|
||||
|
||||
return direction;
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
<script>
|
||||
import { GlIcon, GlPopover } from '@gitlab/ui';
|
||||
import { __, sprintf } from '~/locale';
|
||||
import { MAX_TITLE_LENGTH, MAX_BODY_LENGTH } from '../../constants';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GlIcon,
|
||||
GlPopover,
|
||||
},
|
||||
props: {
|
||||
text: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
scrollTop: 0,
|
||||
isFocused: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
allLines() {
|
||||
return this.text.split('\n').map((line, i) => ({
|
||||
text: line.substr(0, this.getLineLength(i)) || ' ',
|
||||
highlightedText: line.substr(this.getLineLength(i)),
|
||||
}));
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
handleScroll() {
|
||||
if (this.$refs.textarea) {
|
||||
this.$nextTick(() => {
|
||||
this.scrollTop = this.$refs.textarea.scrollTop;
|
||||
});
|
||||
}
|
||||
},
|
||||
getLineLength(i) {
|
||||
return i === 0 ? MAX_TITLE_LENGTH : MAX_BODY_LENGTH;
|
||||
},
|
||||
onInput(e) {
|
||||
this.$emit('input', e.target.value);
|
||||
},
|
||||
onCtrlEnter() {
|
||||
if (!this.isFocused) return;
|
||||
this.$emit('submit');
|
||||
},
|
||||
updateIsFocused(isFocused) {
|
||||
this.isFocused = isFocused;
|
||||
},
|
||||
},
|
||||
popoverOptions: {
|
||||
triggers: 'hover',
|
||||
placement: 'top',
|
||||
content: sprintf(
|
||||
__(`
|
||||
The character highlighter helps you keep the subject line to %{titleLength} characters
|
||||
and wrap the body at %{bodyLength} so they are readable in git.
|
||||
`),
|
||||
{ titleLength: MAX_TITLE_LENGTH, bodyLength: MAX_BODY_LENGTH },
|
||||
),
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<fieldset
|
||||
class="gl-rounded-base gl-inset-border-1-gray-400 gl-py-4 gl-px-5"
|
||||
:class="{
|
||||
'gl-outline-none! gl-focus-ring-border-1-gray-900!': isFocused,
|
||||
}"
|
||||
>
|
||||
<div
|
||||
v-once
|
||||
class="gl-display-flex gl-align-items-center gl-border-b-solid gl-border-b-1 gl-border-b-gray-100 gl-pb-3 gl-mb-3"
|
||||
>
|
||||
<div>{{ __('Commit Message') }}</div>
|
||||
<div id="commit-message-popover-container">
|
||||
<span id="commit-message-question" class="gl-gray-700 gl-ml-3">
|
||||
<gl-icon name="question" />
|
||||
</span>
|
||||
<gl-popover
|
||||
target="commit-message-question"
|
||||
container="commit-message-popover-container"
|
||||
v-bind="$options.popoverOptions"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gl-relative gl-w-full gl-h-13 gl-overflow-hidden">
|
||||
<div class="gl-absolute gl-z-index-1 gl-font-monospace gl-text-transparent">
|
||||
<div
|
||||
data-testid="highlights"
|
||||
:style="{
|
||||
transform: `translate3d(0, ${-scrollTop}px, 0)`,
|
||||
}"
|
||||
>
|
||||
<div v-for="(line, index) in allLines" :key="index">
|
||||
<span
|
||||
data-testid="highlights-text"
|
||||
class="gl-white-space-pre-wrap gl-word-break-word"
|
||||
v-text="line.text"
|
||||
>
|
||||
</span
|
||||
><mark
|
||||
v-show="line.highlightedText"
|
||||
data-testid="highlights-mark"
|
||||
class="gl-px-1 gl-py-0 gl-bg-orange-100 gl-text-transparent gl-white-space-pre-wrap gl-word-break-word"
|
||||
v-text="line.highlightedText"
|
||||
>
|
||||
</mark>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<textarea
|
||||
ref="textarea"
|
||||
:placeholder="placeholder"
|
||||
:value="text"
|
||||
class="gl-absolute gl-w-full gl-h-full gl-z-index-2 gl-font-monospace p-0 gl-outline-0 gl-bg-transparent gl-border-0"
|
||||
data-qa-selector="ide_commit_message_field"
|
||||
dir="auto"
|
||||
name="commit-message"
|
||||
@scroll="handleScroll"
|
||||
@input="onInput"
|
||||
@focus="updateIsFocused(true)"
|
||||
@blur="updateIsFocused(false)"
|
||||
@keydown.ctrl.enter="onCtrlEnter"
|
||||
@keydown.meta.enter="onCtrlEnter"
|
||||
>
|
||||
</textarea>
|
||||
</div>
|
||||
</fieldset>
|
||||
</template>
|
|
@ -20,7 +20,7 @@ export function generateMessages(emptyStateMeta) {
|
|||
);
|
||||
|
||||
const serviceDeskSupportedMessage = s__(
|
||||
'ServiceDesk|Issues created from Service Desk emails appear here. Each comment becomes part of the email conversation.',
|
||||
'ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation.',
|
||||
);
|
||||
|
||||
const commonDescription = `
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script>
|
||||
import { GlFormSelect, GlSprintf } from '@gitlab/ui';
|
||||
import { mapActions, mapState } from 'vuex';
|
||||
import { mapActions } from 'vuex';
|
||||
import { getSymbol, getLineClasses } from './multiline_comment_utils';
|
||||
|
||||
export default {
|
||||
|
@ -27,13 +27,12 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState({ selectedCommentPosition: ({ notes }) => notes.selectedCommentPosition }),
|
||||
lineNumber() {
|
||||
return this.commentLineOptions[this.commentLineOptions.length - 1].text;
|
||||
},
|
||||
},
|
||||
created() {
|
||||
const line = this.selectedCommentPosition?.start || this.lineRange?.start || this.line;
|
||||
const line = this.lineRange?.start || this.line;
|
||||
|
||||
this.commentLineStart = {
|
||||
line_code: line.line_code,
|
||||
|
@ -42,7 +41,6 @@ export default {
|
|||
new_line: line.new_line,
|
||||
};
|
||||
|
||||
if (this.selectedCommentPosition) return;
|
||||
this.highlightSelection();
|
||||
},
|
||||
destroyed() {
|
||||
|
|
|
@ -334,13 +334,13 @@ export default {
|
|||
:markdown-docs-path="markdownDocsPath"
|
||||
:quick-actions-docs-path="quickActionsDocsPath"
|
||||
:line="line"
|
||||
:lines="lines"
|
||||
:note="discussionNote"
|
||||
:can-suggest="canSuggest"
|
||||
:add-spacing-classes="false"
|
||||
:help-page-path="helpPagePath"
|
||||
:show-suggest-popover="showSuggestPopover"
|
||||
:textarea-value="updatedNoteBody"
|
||||
:lines="lines"
|
||||
@handleSuggestDismissed="() => $emit('handleSuggestDismissed')"
|
||||
>
|
||||
<template #textarea>
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
Prevent flashing of content when using startup.css
|
||||
*/
|
||||
@mixin cloak-startup-scss($display) {
|
||||
// General selector for cloaking until ready
|
||||
.cloak-startup,
|
||||
// Breadcrumbs and alerts on the top of the page
|
||||
.content-wrapper > .alert-wrapper,
|
||||
// Content on pages
|
||||
|
|
|
@ -281,3 +281,12 @@ $gl-line-height-42: px-to-rem(42px);
|
|||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
// Will both be moved to @gitlab/ui by https://gitlab.com/gitlab-org/gitlab-ui/-/issues/1465
|
||||
.gl-text-transparent {
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
.gl-focus-ring-border-1-gray-900\! {
|
||||
@include gl-focus($gl-border-size-1, $gray-900, true);
|
||||
}
|
||||
|
|
|
@ -146,6 +146,9 @@ module ApplicationSettingImplementation
|
|||
session_expire_delay: Settings.gitlab['session_expire_delay'],
|
||||
shared_runners_enabled: Settings.gitlab_ci['shared_runners_enabled'],
|
||||
shared_runners_text: nil,
|
||||
sidekiq_job_limiter_mode: Gitlab::SidekiqMiddleware::SizeLimiter::Validator::COMPRESS_MODE,
|
||||
sidekiq_job_limiter_compression_threshold_bytes: Gitlab::SidekiqMiddleware::SizeLimiter::Validator::DEFAULT_COMPRESSION_THRESHOLD_BYTES,
|
||||
sidekiq_job_limiter_limit_bytes: Gitlab::SidekiqMiddleware::SizeLimiter::Validator::DEFAULT_SIZE_LIMIT,
|
||||
sign_in_text: nil,
|
||||
signup_enabled: Settings.gitlab['signup_enabled'],
|
||||
snippet_size_limit: 50.megabytes,
|
||||
|
|
|
@ -2,4 +2,5 @@
|
|||
- view_model = top_nav_responsive_view_model(project: @project, group: @group)
|
||||
|
||||
.top-nav-responsive{ class: top_class }
|
||||
#js-top-nav-responsive{ data: { view_model: view_model.to_json } }
|
||||
.cloak-startup
|
||||
#js-top-nav-responsive{ data: { view_model: view_model.to_json } }
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
= s_("ServiceDesk|Your users can send emails to this address:")
|
||||
%code= @project.service_desk_address
|
||||
|
||||
%span= s_("ServiceDesk|Issues created from Service Desk emails appear here. Each comment becomes part of the email conversation.")
|
||||
%span= s_("ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation.")
|
||||
= link_to _('Learn more.'), help_page_path('user/project/service_desk')
|
||||
|
||||
- if can_edit_project_settings && !service_desk_enabled
|
||||
|
|
|
@ -5,6 +5,7 @@ description: Count of unique users per month who toggled a task item in a merge
|
|||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: code_review
|
||||
product_section: 'TBD'
|
||||
value_type: number
|
||||
status: active
|
||||
time_frame: 28d
|
||||
|
|
|
@ -5,6 +5,7 @@ description: Count of unique users per month who approve a merge request
|
|||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: code_review
|
||||
product_section: 'TBD'
|
||||
value_type: number
|
||||
status: active
|
||||
time_frame: 28d
|
||||
|
|
|
@ -5,6 +5,7 @@ description: Count of unique users per month who unapprove a merge request
|
|||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: code_review
|
||||
product_section: 'TBD'
|
||||
value_type: number
|
||||
status: active
|
||||
time_frame: 28d
|
||||
|
|
|
@ -5,6 +5,7 @@ description: Count of unique users per month who resolve a thread in a merge req
|
|||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: code_review
|
||||
product_section: 'TBD'
|
||||
value_type: number
|
||||
status: active
|
||||
time_frame: 28d
|
||||
|
|
|
@ -5,6 +5,7 @@ description: Count of unique users per month who unresolve a thread in a merge r
|
|||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: code_review
|
||||
product_section: 'TBD'
|
||||
value_type: number
|
||||
status: active
|
||||
time_frame: 28d
|
||||
|
|
|
@ -5,6 +5,7 @@ description: Count of unique users per month who edit the title of a merge reque
|
|||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: code_review
|
||||
product_section: 'TBD'
|
||||
value_type: number
|
||||
status: active
|
||||
time_frame: 28d
|
||||
|
|
|
@ -5,6 +5,7 @@ description: Count of unique users per month who edit the description of a merge
|
|||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: code_review
|
||||
product_section: 'TBD'
|
||||
value_type: number
|
||||
status: active
|
||||
time_frame: 28d
|
||||
|
|
|
@ -6,6 +6,7 @@ description: Count of unique users per month who create a note as part of a merg
|
|||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: code_review
|
||||
product_section: 'TBD'
|
||||
value_type: number
|
||||
status: active
|
||||
time_frame: 28d
|
||||
|
|
|
@ -6,6 +6,7 @@ description: Count of unique users per month who publish their review as part of
|
|||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: code_review
|
||||
product_section: 'TBD'
|
||||
value_type: number
|
||||
status: active
|
||||
time_frame: 28d
|
||||
|
|
|
@ -6,6 +6,7 @@ description: Count of unique users per month who create a multiline comment in a
|
|||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: code_review
|
||||
product_section: 'TBD'
|
||||
value_type: number
|
||||
status: active
|
||||
time_frame: 28d
|
||||
|
|
|
@ -6,6 +6,7 @@ description: Count of unique users per week who edit a multiline comment in a me
|
|||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: code_review
|
||||
product_section: 'TBD'
|
||||
value_type: number
|
||||
status: active
|
||||
time_frame: 28d
|
||||
|
|
|
@ -6,6 +6,7 @@ description: Count of unique users per month who remove a multiline comment in a
|
|||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: code_review
|
||||
product_section: 'TBD'
|
||||
value_type: number
|
||||
status: active
|
||||
time_frame: 28d
|
||||
|
|
|
@ -5,6 +5,7 @@ description: Count of unique users per month who are assigned to a merge request
|
|||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: code_review
|
||||
product_section: 'TBD'
|
||||
value_type: number
|
||||
status: active
|
||||
time_frame: 28d
|
||||
|
|
|
@ -5,6 +5,7 @@ description: Count of unique users per month who mark a merge request as a draft
|
|||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: code_review
|
||||
product_section: 'TBD'
|
||||
value_type: number
|
||||
status: active
|
||||
time_frame: 28d
|
||||
|
|
|
@ -5,6 +5,7 @@ description: Count of unique users per month who unmark a merge request as a dra
|
|||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: code_review
|
||||
product_section: 'TBD'
|
||||
value_type: number
|
||||
status: active
|
||||
time_frame: 28d
|
||||
|
|
|
@ -5,6 +5,7 @@ description: Count of unique users per month who request a review of a merge req
|
|||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: code_review
|
||||
product_section: 'TBD'
|
||||
value_type: number
|
||||
status: active
|
||||
time_frame: 28d
|
||||
|
|
|
@ -5,6 +5,7 @@ description: Count of unique users per month who add an approval rule to a merge
|
|||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: code_review
|
||||
product_section: 'TBD'
|
||||
value_type: number
|
||||
status: active
|
||||
time_frame: 28d
|
||||
|
|
|
@ -6,6 +6,7 @@ description: Count of unique users per month who delete an approval rule to a me
|
|||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: code_review
|
||||
product_section: 'TBD'
|
||||
value_type: number
|
||||
status: active
|
||||
time_frame: 28d
|
||||
|
|
|
@ -6,6 +6,7 @@ description: Count of unique users per month who delete an approval rule to a me
|
|||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: code_review
|
||||
product_section: 'TBD'
|
||||
value_type: number
|
||||
status: active
|
||||
time_frame: 28d
|
||||
|
|
|
@ -5,6 +5,7 @@ description: Count of unique users per month who use GitLab Workflow for VS Code
|
|||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: editor_extension
|
||||
product_section: 'TBD'
|
||||
value_type: number
|
||||
status: active
|
||||
time_frame: 28d
|
||||
|
|
|
@ -5,6 +5,7 @@ description: Count of unique users per month who create a merge request from an
|
|||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: code_review
|
||||
product_section: 'TBD'
|
||||
value_type: number
|
||||
status: active
|
||||
time_frame: 28d
|
||||
|
|
|
@ -5,6 +5,7 @@ description: Count of unique users per month who interact with a merge request
|
|||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: code_review
|
||||
product_section: 'TBD'
|
||||
value_type: number
|
||||
status: active
|
||||
time_frame: 28d
|
||||
|
|
|
@ -7,6 +7,7 @@ product_section:
|
|||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: code_review
|
||||
product_section: 'TBD'
|
||||
value_type: number
|
||||
status: active
|
||||
milestone: "13.12"
|
||||
|
|
|
@ -7,6 +7,7 @@ product_section:
|
|||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: code_review
|
||||
product_section: 'TBD'
|
||||
value_type: number
|
||||
status: active
|
||||
milestone: "13.12"
|
||||
|
|
|
@ -5,6 +5,7 @@ description: Count of WAU editing an issue title
|
|||
product_stage: plan
|
||||
product_group: group::project management
|
||||
product_category: issue_tracking
|
||||
product_section: 'TBD'
|
||||
value_type: number
|
||||
status: active
|
||||
milestone: "13.6"
|
||||
|
|
|
@ -5,6 +5,7 @@ description: Count of unique users per week who toggled a task item in a merge r
|
|||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: code_review
|
||||
product_section: 'TBD'
|
||||
value_type: number
|
||||
status: active
|
||||
time_frame: 7d
|
||||
|
|
|
@ -5,6 +5,7 @@ description: Count of unique users per week who approve a merge request
|
|||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: code_review
|
||||
product_section: 'TBD'
|
||||
value_type: number
|
||||
status: active
|
||||
time_frame: 7d
|
||||
|
|
|
@ -5,6 +5,7 @@ description: Count of unique users per week who unapprove a merge request
|
|||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: code_review
|
||||
product_section: 'TBD'
|
||||
value_type: number
|
||||
status: active
|
||||
time_frame: 7d
|
||||
|
|
|
@ -5,6 +5,7 @@ description: Count of unique users per week who resolve a thread in a merge requ
|
|||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: code_review
|
||||
product_section: 'TBD'
|
||||
value_type: number
|
||||
status: active
|
||||
time_frame: 7d
|
||||
|
|
|
@ -5,6 +5,7 @@ description: Count of unique users per week who unresolve a thread in a merge re
|
|||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: code_review
|
||||
product_section: 'TBD'
|
||||
value_type: number
|
||||
status: active
|
||||
time_frame: 7d
|
||||
|
|
|
@ -5,6 +5,7 @@ description: Count of unique users per week who edit the title of a merge reques
|
|||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: code_review
|
||||
product_section: 'TBD'
|
||||
value_type: number
|
||||
status: active
|
||||
time_frame: 7d
|
||||
|
|
|
@ -5,6 +5,7 @@ description: Count of unique users per week who edit the description of a merge
|
|||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: code_review
|
||||
product_section: 'TBD'
|
||||
value_type: number
|
||||
status: active
|
||||
time_frame: 7d
|
||||
|
|
|
@ -6,6 +6,7 @@ description: Count of unique users per week who create a note as part of a merge
|
|||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: code_review
|
||||
product_section: 'TBD'
|
||||
value_type: number
|
||||
status: active
|
||||
time_frame: 7d
|
||||
|
|
|
@ -6,6 +6,7 @@ description: Count of unique users per week who publish their review as part of
|
|||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: code_review
|
||||
product_section: 'TBD'
|
||||
value_type: number
|
||||
status: active
|
||||
time_frame: 7d
|
||||
|
|
|
@ -6,6 +6,7 @@ description: Count of unique users per week who create a multiline comment in a
|
|||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: code_review
|
||||
product_section: 'TBD'
|
||||
value_type: number
|
||||
status: active
|
||||
time_frame: 7d
|
||||
|
|
|
@ -6,6 +6,7 @@ description: Count of unique users per week who edit a multiline comment in a me
|
|||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: code_review
|
||||
product_section: 'TBD'
|
||||
value_type: number
|
||||
status: active
|
||||
time_frame: 7d
|
||||
|
|
|
@ -6,6 +6,7 @@ description: Count of unique users per week who remove a multiline comment in a
|
|||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: code_review
|
||||
product_section: 'TBD'
|
||||
value_type: number
|
||||
status: active
|
||||
time_frame: 7d
|
||||
|
|
|
@ -5,6 +5,7 @@ description: Count of unique users per week who are assigned to a merge request
|
|||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: code_review
|
||||
product_section: 'TBD'
|
||||
value_type: number
|
||||
status: active
|
||||
time_frame: 7d
|
||||
|
|
|
@ -4,6 +4,7 @@ key_path: redis_hll_counters.code_review.i_code_review_user_marked_as_draft_week
|
|||
description: Count of unique users per week who mark a merge request as a draft
|
||||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_section: 'TBD'
|
||||
product_category: code_review
|
||||
value_type: number
|
||||
status: active
|
||||
|
|
|
@ -5,6 +5,7 @@ description: Count of unique users per week who unmark a merge request as a draf
|
|||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: code_review
|
||||
product_section: 'TBD'
|
||||
value_type: number
|
||||
status: active
|
||||
time_frame: 7d
|
||||
|
|
|
@ -5,6 +5,7 @@ description: Count of unique users per week who request a review of a merge requ
|
|||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: code_review
|
||||
product_section: 'TBD'
|
||||
value_type: number
|
||||
status: active
|
||||
time_frame: 7d
|
||||
|
|
|
@ -5,6 +5,7 @@ description: Count of unique users per week who add an approval rule to a merge
|
|||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: code_review
|
||||
product_section: 'TBD'
|
||||
value_type: number
|
||||
status: active
|
||||
time_frame: 7d
|
||||
|
|
|
@ -6,6 +6,7 @@ description: Count of unique users per week who delete an approval rule to a mer
|
|||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: code_review
|
||||
product_section: 'TBD'
|
||||
value_type: number
|
||||
status: active
|
||||
time_frame: 7d
|
||||
|
|
|
@ -5,6 +5,7 @@ description: Count of unique users per week who edit an approval rule to a merge
|
|||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: code_review
|
||||
product_section: 'TBD'
|
||||
value_type: number
|
||||
status: active
|
||||
time_frame: 7d
|
||||
|
|
|
@ -5,6 +5,7 @@ description: Count of unique users per week who use GitLab Workflow for VS Code
|
|||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: editor_extension
|
||||
product_section: 'TBD'
|
||||
value_type: number
|
||||
status: active
|
||||
time_frame: 7d
|
||||
|
|
|
@ -5,6 +5,7 @@ description: Count of unique users per week who create a merge request from an i
|
|||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: code_review
|
||||
product_section: 'TBD'
|
||||
value_type: number
|
||||
status: active
|
||||
time_frame: 7d
|
||||
|
|
|
@ -5,6 +5,7 @@ description: Count of unique users per week who interact with a merge request
|
|||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: code_review
|
||||
product_section: 'TBD'
|
||||
value_type: number
|
||||
status: active
|
||||
time_frame: 7d
|
||||
|
|
|
@ -3,7 +3,7 @@ data_category: optional
|
|||
key_path: redis_hll_counters.code_review.i_code_review_user_load_conflict_ui_weekly
|
||||
name: load_conflict_ui
|
||||
description: Count of unique users per week who load the conflict resolution page
|
||||
product_section:
|
||||
product_section: 'TBD'
|
||||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: code_review
|
||||
|
|
|
@ -3,7 +3,7 @@ data_category: optional
|
|||
key_path: redis_hll_counters.code_review.i_code_review_user_resolve_conflict_weekly
|
||||
name: resolve_conflict
|
||||
description: Count of unique users per week who attempt to resolve a conflict through the ui
|
||||
product_section:
|
||||
product_section: 'TBD'
|
||||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category: code_review
|
||||
|
|
|
@ -3,7 +3,7 @@ data_category: optional
|
|||
key_path: counts.in_product_marketing_email_create_0_sent
|
||||
name: "count_sent_first_email_of_the_create_track_for_in_product_marketing_emails"
|
||||
description: Total sent emails of the create track's first email
|
||||
product_section:
|
||||
product_section: 'TBD'
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
|
|
|
@ -3,7 +3,7 @@ data_category: optional
|
|||
key_path: counts.in_product_marketing_email_create_0_cta_clicked
|
||||
name: "count_clicks_on_the_first_email_of_the_create_track_for_in_product_marketing_emails"
|
||||
description: Total clicks on the create track's first email
|
||||
product_section:
|
||||
product_section: 'TBD'
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
|
|
|
@ -3,7 +3,7 @@ data_category: optional
|
|||
key_path: counts.in_product_marketing_email_create_1_sent
|
||||
name: "count_sent_second_email_of_the_create_track_for_in_product_marketing_emails"
|
||||
description: Total sent emails of the create track's second email
|
||||
product_section:
|
||||
product_section: 'TBD'
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
|
|
|
@ -3,7 +3,7 @@ data_category: optional
|
|||
key_path: counts.in_product_marketing_email_create_1_cta_clicked
|
||||
name: "count_clicks_on_the_second_email_of_the_create_track_for_in_product_marketing_emails"
|
||||
description: Total clicks on the create track's second email
|
||||
product_section:
|
||||
product_section: 'TBD'
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
|
|
|
@ -3,7 +3,7 @@ data_category: optional
|
|||
key_path: counts.in_product_marketing_email_create_2_sent
|
||||
name: "count_sent_third_email_of_the_create_track_for_in_product_marketing_emails"
|
||||
description: Total sent emails of the create track's third email
|
||||
product_section:
|
||||
product_section: 'TBD'
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
|
|
|
@ -3,7 +3,7 @@ data_category: optional
|
|||
key_path: counts.in_product_marketing_email_create_2_cta_clicked
|
||||
name: "count_clicks_on_the_third_email_of_the_create_track_for_in_product_marketing_emails"
|
||||
description: Total clicks on the create track's third email
|
||||
product_section:
|
||||
product_section: 'TBD'
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
|
|
|
@ -3,7 +3,7 @@ data_category: optional
|
|||
key_path: counts.in_product_marketing_email_verify_0_sent
|
||||
name: "count_sent_first_email_of_the_verify_track_for_in_product_marketing_emails"
|
||||
description: Total sent emails of the verify track's first email
|
||||
product_section:
|
||||
product_section: 'TBD'
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
|
|
|
@ -3,7 +3,7 @@ data_category: optional
|
|||
key_path: counts.in_product_marketing_email_verify_0_cta_clicked
|
||||
name: "count_clicks_on_the_first_email_of_the_verify_track_for_in_product_marketing_emails"
|
||||
description: Total clicks on the verify track's first email
|
||||
product_section:
|
||||
product_section: 'TBD'
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
|
|
|
@ -3,7 +3,7 @@ data_category: optional
|
|||
key_path: counts.in_product_marketing_email_verify_1_sent
|
||||
name: "count_sent_second_email_of_the_verify_track_for_in_product_marketing_emails"
|
||||
description: Total sent emails of the verify track's second email
|
||||
product_section:
|
||||
product_section: 'TBD'
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
|
|
|
@ -3,7 +3,7 @@ data_category: optional
|
|||
key_path: counts.in_product_marketing_email_verify_1_cta_clicked
|
||||
name: "count_clicks_on_the_second_email_of_the_verify_track_for_in_product_marketing_emails"
|
||||
description: Total clicks on the verify track's second email
|
||||
product_section:
|
||||
product_section: 'TBD'
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
|
|
|
@ -3,7 +3,7 @@ data_category: optional
|
|||
key_path: counts.in_product_marketing_email_verify_2_sent
|
||||
name: "count_sent_third_email_of_the_verify_track_for_in_product_marketing_emails"
|
||||
description: Total sent emails of the verify track's third email
|
||||
product_section:
|
||||
product_section: 'TBD'
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
|
|
|
@ -3,7 +3,7 @@ data_category: optional
|
|||
key_path: counts.in_product_marketing_email_verify_2_cta_clicked
|
||||
name: "count_clicks_on_the_third_email_of_the_verify_track_for_in_product_marketing_emails"
|
||||
description: Total clicks on the verify track's third email
|
||||
product_section:
|
||||
product_section: 'TBD'
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
|
|
|
@ -3,7 +3,7 @@ data_category: optional
|
|||
key_path: counts.in_product_marketing_email_trial_0_sent
|
||||
name: "count_sent_first_email_of_the_trial_track_for_in_product_marketing_emails"
|
||||
description: Total sent emails of the trial track's first email
|
||||
product_section:
|
||||
product_section: 'TBD'
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
|
|
|
@ -3,7 +3,7 @@ data_category: optional
|
|||
key_path: counts.in_product_marketing_email_trial_0_cta_clicked
|
||||
name: "count_clicks_on_the_first_email_of_the_trial_track_for_in_product_marketing_emails"
|
||||
description: Total clicks on the verify trial's first email
|
||||
product_section:
|
||||
product_section: 'TBD'
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
|
|
|
@ -3,7 +3,7 @@ data_category: optional
|
|||
key_path: counts.in_product_marketing_email_trial_1_sent
|
||||
name: "count_sent_second_email_of_the_trial_track_for_in_product_marketing_emails"
|
||||
description: Total sent emails of the trial track's second email
|
||||
product_section:
|
||||
product_section: 'TBD'
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
|
|
|
@ -3,7 +3,7 @@ data_category: optional
|
|||
key_path: counts.in_product_marketing_email_trial_1_cta_clicked
|
||||
name: "count_clicks_on_the_second_email_of_the_trial_track_for_in_product_marketing_emails"
|
||||
description: Total clicks on the trial track's second email
|
||||
product_section:
|
||||
product_section: 'TBD'
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
|
|
|
@ -3,7 +3,7 @@ data_category: optional
|
|||
key_path: counts.in_product_marketing_email_trial_2_sent
|
||||
name: "count_sent_third_email_of_the_trial_track_for_in_product_marketing_emails"
|
||||
description: Total sent emails of the trial track's third email
|
||||
product_section:
|
||||
product_section: 'TBD'
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
|
|
|
@ -3,7 +3,7 @@ data_category: optional
|
|||
key_path: counts.in_product_marketing_email_trial_2_cta_clicked
|
||||
name: "count_clicks_on_the_third_email_of_the_trial_track_for_in_product_marketing_emails"
|
||||
description: Total clicks on the trial track's third email
|
||||
product_section:
|
||||
product_section: 'TBD'
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
|
|
|
@ -3,7 +3,7 @@ data_category: optional
|
|||
key_path: counts.in_product_marketing_email_team_0_sent
|
||||
name: "count_sent_first_email_of_the_trial_team_for_in_product_marketing_emails"
|
||||
description: Total sent emails of the team track's first email
|
||||
product_section:
|
||||
product_section: 'TBD'
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
|
|
|
@ -3,7 +3,7 @@ data_category: optional
|
|||
key_path: counts.in_product_marketing_email_team_0_cta_clicked
|
||||
name: "count_clicks_on_the_first_email_of_the_team_track_for_in_product_marketing_emails"
|
||||
description: Total clicks on the team track's first email
|
||||
product_section:
|
||||
product_section: 'TBD'
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
|
|
|
@ -3,7 +3,7 @@ data_category: optional
|
|||
key_path: counts.in_product_marketing_email_team_1_sent
|
||||
name: "count_sent_second_email_of_the_team_track_for_in_product_marketing_emails"
|
||||
description: Total sent emails of the team track's second email
|
||||
product_section:
|
||||
product_section: 'TBD'
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
|
|
|
@ -3,7 +3,7 @@ data_category: optional
|
|||
key_path: counts.in_product_marketing_email_team_1_cta_clicked
|
||||
name: "count_clicks_on_the_second_email_of_the_team_track_for_in_product_marketing_emails"
|
||||
description: Total clicks on the team track's second email
|
||||
product_section:
|
||||
product_section: 'TBD'
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
|
|
|
@ -3,7 +3,7 @@ data_category: optional
|
|||
key_path: counts.in_product_marketing_email_team_2_sent
|
||||
name: "count_sent_third_email_of_the_team_track_for_in_product_marketing_emails"
|
||||
description: Total sent emails of the team track's third email
|
||||
product_section:
|
||||
product_section: 'TBD'
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
|
|
|
@ -3,7 +3,7 @@ data_category: optional
|
|||
key_path: counts.in_product_marketing_email_team_2_cta_clicked
|
||||
name: "count_clicks_on_the_third_email_of_the_team_track_for_in_product_marketing_emails"
|
||||
description: Total clicks on the team track's third email
|
||||
product_section:
|
||||
product_section: 'TBD'
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
|
|
|
@ -3,7 +3,7 @@ data_category: optional
|
|||
key_path: counts.in_product_marketing_email_experience_0_sent
|
||||
name: "count_sent_first_email_of_the_experience_track_for_in_product_marketing_emails"
|
||||
description: Total sent emails of the experience track's first email
|
||||
product_section:
|
||||
product_section: 'TBD'
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"type": "object",
|
||||
"required": ["key_path", "description", "value_type", "status", "product_group", "product_stage", "time_frame", "data_source", "distribution", "tier", "data_category", "milestone"],
|
||||
"required": ["key_path", "description", "value_type", "status", "product_group", "product_section", "product_stage", "time_frame", "data_source", "distribution", "tier", "data_category", "milestone"],
|
||||
"properties": {
|
||||
"key_path": {
|
||||
"type": "string"
|
||||
|
@ -13,10 +13,10 @@
|
|||
"type": "string"
|
||||
},
|
||||
"product_section": {
|
||||
"type": ["string", "null"]
|
||||
"type": ["string"]
|
||||
},
|
||||
"product_stage": {
|
||||
"type": ["string", "null"]
|
||||
"type": ["string"]
|
||||
},
|
||||
"product_group": {
|
||||
"type": "string"
|
||||
|
|
|
@ -6,7 +6,7 @@ comments: false
|
|||
description: Consolidating groups and projects
|
||||
---
|
||||
|
||||
# Consolidating Group and Project
|
||||
# Consolidating Groups and Projects
|
||||
|
||||
There are numerous features that exist exclusively within groups or
|
||||
projects. The boundary between group and project features used to be clear.
|
||||
|
@ -127,6 +127,22 @@ The work required to establish `Namespace` as a container for our features is
|
|||
tracked under [Consolidate Groups and Projects](https://gitlab.com/groups/gitlab-org/-/epics/6473)
|
||||
epic.
|
||||
|
||||
## Migrating features to Namespaces
|
||||
|
||||
The initial iteration will provide a framework to house features under `Namespaces`. Stage groups will eventually need to migrate their own features and functionality over to `Namespaces`. This may impact these features in unexpected ways. Therefore, to minimize UX debt and maintain product consistency, stage groups will have to consider a number of factors when migrating their features over to `Namespaces`:
|
||||
|
||||
1. **Conceptual model**: What are the current and future state conceptual models of these features ([see object modeling for designers](https://hpadkisson.medium.com/object-modeling-for-designers-an-introduction-7871bdcf8baf))? These should be documented in Pajamas (example: [Merge Requests](https://design.gitlab.com/objects/merge-request)).
|
||||
1. **Merge conflicts**: What inconsistencies are there across project, group, and admin levels? How might these be addressed? For an example of how we rationalized this for labels, please see [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/338820).
|
||||
1. **Inheritence & information flow**: How is information inherited across our container hierarchy currently? How might this be impacted if complying with the new [inheritence behavior](https://gitlab.com/gitlab-org/gitlab/-/issues/343316) framework?
|
||||
1. **Settings**: Where can settings for this feature be found currently? How will these be impacted by `Namespaces`?
|
||||
1. **Access**: Who can access this feature and is that impacted by the new container structure? Are there any role or privacy considerations?
|
||||
1. **Tier**: Is there any tier functionality that is differentiated by projects and groups?
|
||||
1. **Documentation**: Is the structure and content of documentation impacted by these changes at all?
|
||||
1. **Solution proposal**:
|
||||
- Think big: This analysis provides a great opportunity to zoom out and consider the feature UX as a whole. How could you make this feature lovable based on the new structure, inheritance, and capabilities afforded by `Namespaces`? Is there any UI which doesn't comply with Pajamas?
|
||||
- Start small: What are the product changes that need to be made to assist with the migration?
|
||||
- Move fast: Prioritise these solution ideas, document in issues, and create a roadmap for implementation.
|
||||
|
||||
## Who
|
||||
|
||||
Proposal:
|
||||
|
@ -151,5 +167,6 @@ DRIs:
|
|||
| Product | Melissa Ushakov |
|
||||
| Leadership | Michelle Gill |
|
||||
| Engineering | Imre Farkas |
|
||||
| Design | Nick Post |
|
||||
|
||||
<!-- vale gitlab.Spelling = YES -->
|
||||
|
|
|
@ -1085,6 +1085,61 @@ In this example:
|
|||
- `script` does not merge, but `script: ['rake rspec']` overwrites
|
||||
`script: ['echo "Hello world!"']`. You can use [YAML anchors](yaml_specific_features.md#anchors) to merge arrays.
|
||||
|
||||
##### Exclude a key from `extends`
|
||||
|
||||
To exclude a key from the extended content, you must assign it to `null`, for example:
|
||||
|
||||
```yaml
|
||||
.base:
|
||||
script: test
|
||||
variables:
|
||||
VAR1: base var 1
|
||||
|
||||
test1:
|
||||
extends: .base
|
||||
variables:
|
||||
VAR1: test1 var 1
|
||||
VAR2: test2 var 2
|
||||
|
||||
test2:
|
||||
extends: .base
|
||||
variables:
|
||||
VAR2: test2 var 2
|
||||
|
||||
test3:
|
||||
extends: .base
|
||||
variables: {}
|
||||
|
||||
test4:
|
||||
extends: .base
|
||||
variables: null
|
||||
```
|
||||
|
||||
Merged configuration:
|
||||
|
||||
```yaml
|
||||
test1:
|
||||
script: test
|
||||
variables:
|
||||
VAR1: test1 var 1
|
||||
VAR2: test2 var 2
|
||||
|
||||
test2:
|
||||
script: test
|
||||
variables:
|
||||
VAR1: base var 1
|
||||
VAR2: test2 var 2
|
||||
|
||||
test3:
|
||||
script: test
|
||||
variables:
|
||||
VAR1: base var 1
|
||||
|
||||
test4:
|
||||
script: test
|
||||
variables: null
|
||||
```
|
||||
|
||||
#### Use `extends` and `include` together
|
||||
|
||||
To reuse configuration from different configuration files,
|
||||
|
|
|
@ -272,6 +272,62 @@ logic to delete these rows if or whenever necessary in your domain.
|
|||
Finally, this de-normalization and new query also improves performance because
|
||||
it does less joins and needs less filtering.
|
||||
|
||||
##### Remove a redundant join
|
||||
|
||||
Sometimes there are cases where a query is doing excess (or redundant) joins.
|
||||
|
||||
A common example occurs where a query is joining from `A` to `C`, via some
|
||||
table with both foreign keys, `B`.
|
||||
When you only care about counting how
|
||||
many rows there are in `C` and if there are foreign keys and `NOT NULL` constraints
|
||||
on the foreign keys in `B`, then it might be enough to count those rows.
|
||||
For example, in
|
||||
[MR 71811](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/71811), it was
|
||||
previously doing `project.runners.count`, which would produce a query like:
|
||||
|
||||
```sql
|
||||
select count(*) from projects
|
||||
inner join ci_runner_projects on ci_runner_projects.project_id = projects.id
|
||||
where ci_runner_projects.runner_id IN (1, 2, 3)
|
||||
```
|
||||
|
||||
This was changed to avoid the cross-join by changing the code to
|
||||
`project.runner_projects.count`. It produces the same response with the
|
||||
following query:
|
||||
|
||||
```sql
|
||||
select count(*) from ci_runner_projects
|
||||
where ci_runner_projects.runner_id IN (1, 2, 3)
|
||||
```
|
||||
|
||||
Another common redundant join is joining all the way to another table,
|
||||
then filtering by primary key when you could have instead filtered on a foreign
|
||||
key. See an example in
|
||||
[MR 71614](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/71614). The previous
|
||||
code was `joins(scan: :build).where(ci_builds: { id: build_ids })`, which
|
||||
generated a query like:
|
||||
|
||||
```sql
|
||||
select ...
|
||||
inner join security_scans
|
||||
inner join ci_builds on security_scans.build_id = ci_builds.id
|
||||
where ci_builds.id IN (1, 2, 3)
|
||||
```
|
||||
|
||||
However, as `security_scans` already has a foreign key `build_id`, the code
|
||||
can be changed to `joins(:scan).where(security_scans: { build_id: build_ids })`,
|
||||
which produces the same response with the following query:
|
||||
|
||||
```sql
|
||||
select ...
|
||||
inner join security_scans
|
||||
where security_scans.build_id IN (1, 2, 3)
|
||||
```
|
||||
|
||||
Both of these examples of removing redundant joins remove the cross-joins,
|
||||
but they have the added benefit of producing simpler and faster
|
||||
queries.
|
||||
|
||||
##### Use `disable_joins` for `has_one` or `has_many` `through:` relations
|
||||
|
||||
Sometimes a join query is caused by using `has_one ... through:` or `has_many
|
||||
|
|
|
@ -95,10 +95,8 @@ For details about groups, watch [GitLab Namespaces (users, groups and subgroups)
|
|||
|
||||
You can give a user access to all projects in a group.
|
||||
|
||||
1. On the top bar, select **Menu > Groups**.
|
||||
1. Select **Your Groups**.
|
||||
1. Find your group and select it.
|
||||
1. From the left sidebar, select **Group information > Members**.
|
||||
1. On the top bar, select **Menu > Groups** and find your group.
|
||||
1. On the left sidebar, select **Group information > Members**.
|
||||
1. Fill in the fields.
|
||||
- The role applies to all projects in the group. [Learn more about permissions](../permissions.md).
|
||||
- On the **Access expiration date**, the user can no longer access projects in the group.
|
||||
|
@ -107,9 +105,7 @@ You can give a user access to all projects in a group.
|
|||
|
||||
As a user, you can request to be a member of a group, if an administrator allows it.
|
||||
|
||||
1. On the top bar, select **Menu > Groups**.
|
||||
1. Select **Your Groups**.
|
||||
1. Find the group and select it.
|
||||
1. On the top bar, select **Menu > Groups** and find your group.
|
||||
1. Under the group name, select **Request Access**.
|
||||
|
||||
As many as ten of the most-recently-active group owners receive an email with your request.
|
||||
|
|
|
@ -87,6 +87,12 @@ The "Time" metrics near the top of the page are measured as follows:
|
|||
- **Lead time**: median time from issue created to issue closed.
|
||||
- **Cycle time**: median time from first commit to issue closed. (You can associate a commit with an
|
||||
issue by [crosslinking in the commit message](../../project/issues/crosslinking_issues.md#from-commit-messages).)
|
||||
- **Lead Time for Changes**: median time between when a merge request is merged and deployed to a
|
||||
production environment for all merge requests deployed in the given time period.
|
||||
[Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/340150) in GitLab 14.5 (**Ultimate**
|
||||
tier only).
|
||||
|
||||
- **Lead Time for Changes**: median duration between merge request merge and deployment to a production environment for all MRs deployed in the given time period. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/340150) in GitLab 14.5 (**Ultimate** tier only).
|
||||
|
||||
The "Recent Activity" metrics near the top of the page are measured as follows:
|
||||
|
||||
|
|
|
@ -10225,6 +10225,9 @@ msgstr ""
|
|||
msgid "CycleAnalytics|Display chart filters"
|
||||
msgstr ""
|
||||
|
||||
msgid "CycleAnalytics|Lead Time for Changes"
|
||||
msgstr ""
|
||||
|
||||
msgid "CycleAnalytics|No stages selected"
|
||||
msgstr ""
|
||||
|
||||
|
@ -31085,9 +31088,6 @@ msgstr ""
|
|||
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
|
||||
msgstr ""
|
||||
|
||||
msgid "ServiceDesk|Issues created from Service Desk emails appear here. Each comment becomes part of the email conversation."
|
||||
msgstr ""
|
||||
|
||||
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
|
||||
msgstr ""
|
||||
|
||||
|
@ -37550,6 +37550,9 @@ msgstr ""
|
|||
msgid "ValueStreamAnalytics|Average number of deployments to production per day."
|
||||
msgstr ""
|
||||
|
||||
msgid "ValueStreamAnalytics|Median time between merge request merge and deployment to a production environment for all MRs deployed in the given time period."
|
||||
msgstr ""
|
||||
|
||||
msgid "ValueStreamAnalytics|Median time from issue created to issue closed."
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@
|
|||
"@gitlab/favicon-overlay": "2.0.0",
|
||||
"@gitlab/svgs": "1.218.0",
|
||||
"@gitlab/tributejs": "1.0.0",
|
||||
"@gitlab/ui": "32.19.1",
|
||||
"@gitlab/ui": "32.21.0",
|
||||
"@gitlab/visual-review-tools": "1.6.1",
|
||||
"@rails/actioncable": "6.1.4-1",
|
||||
"@rails/ujs": "6.1.4-1",
|
||||
|
|
|
@ -14,7 +14,9 @@ export * from '@gitlab/ui';
|
|||
*/
|
||||
|
||||
jest.mock('@gitlab/ui/dist/directives/tooltip.js', () => ({
|
||||
bind() {},
|
||||
GlTooltipDirective: {
|
||||
bind() {},
|
||||
},
|
||||
}));
|
||||
|
||||
jest.mock('@gitlab/ui/dist/components/base/tooltip/tooltip.js', () => ({
|
||||
|
|
|
@ -26,8 +26,9 @@ describe('DiffLineNoteForm', () => {
|
|||
propsData: {
|
||||
diffFileHash: diffFile.file_hash,
|
||||
diffLines,
|
||||
line: diffLines[0],
|
||||
noteTargetLine: diffLines[0],
|
||||
line: diffLines[1],
|
||||
range: { start: diffLines[0], end: diffLines[1] },
|
||||
noteTargetLine: diffLines[1],
|
||||
},
|
||||
});
|
||||
};
|
||||
|
@ -67,7 +68,7 @@ describe('DiffLineNoteForm', () => {
|
|||
expect(window.confirm).not.toHaveBeenCalled();
|
||||
wrapper.vm.$nextTick(() => {
|
||||
expect(wrapper.vm.cancelCommentForm).toHaveBeenCalledWith({
|
||||
lineCode: diffLines[0].line_code,
|
||||
lineCode: diffLines[1].line_code,
|
||||
fileHash: wrapper.vm.diffFileHash,
|
||||
});
|
||||
|
||||
|
@ -88,13 +89,13 @@ describe('DiffLineNoteForm', () => {
|
|||
start: {
|
||||
line_code: wrapper.vm.commentLineStart.line_code,
|
||||
type: wrapper.vm.commentLineStart.type,
|
||||
new_line: 1,
|
||||
new_line: 2,
|
||||
old_line: null,
|
||||
},
|
||||
end: {
|
||||
line_code: wrapper.vm.line.line_code,
|
||||
type: wrapper.vm.line.type,
|
||||
new_line: 1,
|
||||
new_line: 2,
|
||||
old_line: null,
|
||||
},
|
||||
};
|
||||
|
@ -120,7 +121,7 @@ describe('DiffLineNoteForm', () => {
|
|||
|
||||
describe('mounted', () => {
|
||||
it('should init autosave', () => {
|
||||
const key = 'autosave/Note/Issue/98//DiffNote//1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_1';
|
||||
const key = 'autosave/Note/Issue/98//DiffNote//1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_2';
|
||||
wrapper = createComponent();
|
||||
|
||||
expect(wrapper.vm.autosave).toBeDefined();
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
import { pickDirection } from '~/diffs/utils/diff_line';
|
||||
|
||||
describe('diff_line utilities', () => {
|
||||
describe('pickDirection', () => {
|
||||
const left = {
|
||||
line_code: 'left',
|
||||
};
|
||||
const right = {
|
||||
line_code: 'right',
|
||||
};
|
||||
const defaultLine = {
|
||||
left,
|
||||
right,
|
||||
};
|
||||
|
||||
it.each`
|
||||
code | pick | line | pickDescription
|
||||
${'left'} | ${left} | ${defaultLine} | ${'the left line'}
|
||||
${'right'} | ${right} | ${defaultLine} | ${'the right line'}
|
||||
${'junk'} | ${left} | ${defaultLine} | ${'the default: the left line'}
|
||||
${'junk'} | ${right} | ${{ right }} | ${"the right line if there's no left line to default to"}
|
||||
${'right'} | ${left} | ${{ left }} | ${"the left line when there isn't a right line to match"}
|
||||
`(
|
||||
'when provided a line and a line code `$code`, picks $pickDescription',
|
||||
({ code, line, pick }) => {
|
||||
expect(pickDirection({ line, code })).toBe(pick);
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,149 @@
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
import { nextTick } from 'vue';
|
||||
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
|
||||
import CommitMessageField from '~/ide/components/shared/commit_message_field.vue';
|
||||
|
||||
const DEFAULT_PROPS = {
|
||||
text: 'foo text',
|
||||
placeholder: 'foo placeholder',
|
||||
};
|
||||
|
||||
describe('CommitMessageField', () => {
|
||||
let wrapper;
|
||||
|
||||
const createComponent = (props = {}) => {
|
||||
wrapper = extendedWrapper(
|
||||
shallowMount(CommitMessageField, {
|
||||
propsData: {
|
||||
...DEFAULT_PROPS,
|
||||
...props,
|
||||
},
|
||||
attachTo: document.body,
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
});
|
||||
|
||||
const findTextArea = () => wrapper.find('textarea');
|
||||
const findHighlights = () => wrapper.findByTestId('highlights');
|
||||
const findHighlightsText = () => wrapper.findByTestId('highlights-text');
|
||||
const findHighlightsMark = () => wrapper.findByTestId('highlights-mark');
|
||||
const findHighlightsTexts = () => wrapper.findAllByTestId('highlights-text');
|
||||
const findHighlightsMarks = () => wrapper.findAllByTestId('highlights-mark');
|
||||
|
||||
const fillText = async (text) => {
|
||||
wrapper.setProps({ text });
|
||||
await nextTick();
|
||||
};
|
||||
|
||||
it('emits input event on input', () => {
|
||||
const value = 'foo';
|
||||
|
||||
createComponent();
|
||||
findTextArea().setValue(value);
|
||||
expect(wrapper.emitted('input')[0][0]).toEqual(value);
|
||||
});
|
||||
|
||||
describe('focus classes', () => {
|
||||
beforeEach(async () => {
|
||||
createComponent();
|
||||
findTextArea().trigger('focus');
|
||||
await nextTick();
|
||||
});
|
||||
|
||||
it('is added on textarea focus', async () => {
|
||||
expect(wrapper.attributes('class')).toEqual(
|
||||
expect.stringContaining('gl-outline-none! gl-focus-ring-border-1-gray-900!'),
|
||||
);
|
||||
});
|
||||
|
||||
it('is removed on textarea blur', async () => {
|
||||
findTextArea().trigger('blur');
|
||||
await nextTick();
|
||||
|
||||
expect(wrapper.attributes('class')).toEqual(
|
||||
expect.not.stringContaining('gl-outline-none! gl-focus-ring-border-1-gray-900!'),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('highlights', () => {
|
||||
describe('subject line', () => {
|
||||
it('does not highlight less than 50 characters', async () => {
|
||||
const text = 'text less than 50 chars';
|
||||
|
||||
createComponent();
|
||||
await fillText(text);
|
||||
|
||||
expect(findHighlightsText().text()).toEqual(text);
|
||||
expect(findHighlightsMark().text()).toBeFalsy();
|
||||
});
|
||||
|
||||
it('highlights characters over 50 length', async () => {
|
||||
const text =
|
||||
'text less than 50 chars that should not highlighted. text more than 50 should be highlighted';
|
||||
|
||||
createComponent();
|
||||
await fillText(text);
|
||||
|
||||
expect(findHighlightsText().text()).toEqual(text.slice(0, 50));
|
||||
expect(findHighlightsMark().text()).toEqual(text.slice(50));
|
||||
});
|
||||
});
|
||||
|
||||
describe('body text', () => {
|
||||
it('does not highlight body text less tan 72 characters', async () => {
|
||||
const text = 'subject line\nbody content';
|
||||
|
||||
createComponent();
|
||||
await fillText(text);
|
||||
|
||||
expect(findHighlightsTexts()).toHaveLength(2);
|
||||
expect(findHighlightsMarks().at(1).attributes('style')).toEqual('display: none;');
|
||||
});
|
||||
|
||||
it('highlights body text more than 72 characters', async () => {
|
||||
const text =
|
||||
'subject line\nbody content that will be highlighted when it is more than 72 characters in length';
|
||||
|
||||
createComponent();
|
||||
await fillText(text);
|
||||
|
||||
expect(findHighlightsTexts()).toHaveLength(2);
|
||||
expect(findHighlightsMarks().at(1).attributes('style')).not.toEqual('display: none;');
|
||||
expect(findHighlightsMarks().at(1).element.textContent).toEqual(' in length');
|
||||
});
|
||||
|
||||
it('highlights body text & subject line', async () => {
|
||||
const text =
|
||||
'text less than 50 chars that should not highlighted\nbody content that will be highlighted when it is more than 72 characters in length';
|
||||
|
||||
createComponent();
|
||||
await fillText(text);
|
||||
|
||||
expect(findHighlightsTexts()).toHaveLength(2);
|
||||
expect(findHighlightsMarks()).toHaveLength(2);
|
||||
expect(findHighlightsMarks().at(0).element.textContent).toEqual('d');
|
||||
expect(findHighlightsMarks().at(1).element.textContent).toEqual(' in length');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('scrolling textarea', () => {
|
||||
it('updates transform of highlights', async () => {
|
||||
const yCoord = 50;
|
||||
|
||||
createComponent();
|
||||
await fillText('subject line\n\n\n\n\n\n\n\n\n\n\nbody content');
|
||||
|
||||
wrapper.vm.$el.querySelector('textarea').scrollTo(0, yCoord);
|
||||
await nextTick();
|
||||
|
||||
expect(wrapper.vm.scrollTop).toEqual(yCoord);
|
||||
expect(findHighlights().attributes('style')).toEqual('transform: translate3d(0, -50px, 0);');
|
||||
});
|
||||
});
|
||||
});
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue