Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-07-09 00:09:09 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-07-09 00:09:09 +0300
commit83fc2f3dc81052cad76addb44726876ba1d0f156 (patch)
tree1d58eedea14b1462b40bc5b02c9561e5a128ac0b /app
parent1d3086ebb41758289c1184dc5ad1462c81e1a1f9 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/batch_comments/components/draft_note.vue2
-rw-r--r--app/assets/javascripts/batch_comments/components/parallel_draft_comment_row.vue8
-rw-r--r--app/assets/javascripts/batch_comments/components/preview_item.vue15
-rw-r--r--app/assets/javascripts/commit_merge_requests.js4
-rw-r--r--app/assets/javascripts/diffs/components/diff_file_header.vue11
-rw-r--r--app/assets/javascripts/diffs/components/diff_line_note_form.vue35
-rw-r--r--app/assets/javascripts/error_tracking/components/stacktrace_entry.vue9
-rw-r--r--app/assets/javascripts/notes/components/discussion_notes.vue2
-rw-r--r--app/assets/javascripts/notes/components/multiline_comment_form.vue29
-rw-r--r--app/assets/javascripts/notes/components/multiline_comment_utils.js59
-rw-r--r--app/assets/javascripts/notes/components/noteable_note.vue75
-rw-r--r--app/assets/javascripts/notes/mixins/diff_line_note_form.js5
-rw-r--r--app/assets/javascripts/reports/accessibility_report/components/accessibility_issue_body.vue6
-rw-r--r--app/assets/javascripts/reports/components/test_issue_body.vue2
-rw-r--r--app/assets/javascripts/snippets/components/snippet_header.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/loading_button.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/notes/system_note.vue2
-rw-r--r--app/assets/stylesheets/framework/common.scss1
-rw-r--r--app/controllers/concerns/notes_actions.rb2
-rw-r--r--app/helpers/commits_helper.rb2
-rw-r--r--app/models/commit.rb6
-rw-r--r--app/models/merge_request.rb12
-rw-r--r--app/services/jira/requests/issues/list_service.rb7
-rw-r--r--app/services/personal_access_tokens/last_used_service.rb28
-rw-r--r--app/services/update_container_registry_info_service.rb24
-rw-r--r--app/views/doorkeeper/applications/index.html.haml2
-rw-r--r--app/views/profiles/_event_table.html.haml2
-rw-r--r--app/views/profiles/notifications/_group_settings.html.haml2
-rw-r--r--app/views/profiles/notifications/_project_settings.html.haml2
-rw-r--r--app/views/projects/_home_panel.html.haml2
-rw-r--r--app/views/projects/blob/_header_content.html.haml2
-rw-r--r--app/views/projects/diffs/_file_header.html.haml2
-rw-r--r--app/views/shared/access_tokens/_table.html.haml8
-rw-r--r--app/views/shared/snippets/_header.html.haml2
-rw-r--r--app/views/shared/wikis/_sidebar.html.haml2
-rw-r--r--app/workers/concerns/worker_attributes.rb4
36 files changed, 262 insertions, 118 deletions
diff --git a/app/assets/javascripts/batch_comments/components/draft_note.vue b/app/assets/javascripts/batch_comments/components/draft_note.vue
index 9abfd43d85c..db5516b7b93 100644
--- a/app/assets/javascripts/batch_comments/components/draft_note.vue
+++ b/app/assets/javascripts/batch_comments/components/draft_note.vue
@@ -71,8 +71,8 @@ export default {
<ul class="notes draft-notes">
<noteable-note
:note="draft"
- :diff-lines="diffFile.highlighted_diff_lines"
:line="line"
+ :discussion-root="true"
class="draft-note"
@handleEdit="handleEditing"
@cancelForm="handleNotEditing"
diff --git a/app/assets/javascripts/batch_comments/components/parallel_draft_comment_row.vue b/app/assets/javascripts/batch_comments/components/parallel_draft_comment_row.vue
index 68fd20e56bc..b0916623cd2 100644
--- a/app/assets/javascripts/batch_comments/components/parallel_draft_comment_row.vue
+++ b/app/assets/javascripts/batch_comments/components/parallel_draft_comment_row.vue
@@ -35,11 +35,15 @@ export default {
<tr :class="className" class="notes_holder">
<td class="notes_line old"></td>
<td class="notes-content parallel old" colspan="2">
- <div v-if="leftDraft.isDraft" class="content"><draft-note :draft="leftDraft" /></div>
+ <div v-if="leftDraft.isDraft" class="content">
+ <draft-note :draft="leftDraft" :line="line.left" />
+ </div>
</td>
<td class="notes_line new"></td>
<td class="notes-content parallel new" colspan="2">
- <div v-if="rightDraft.isDraft" class="content"><draft-note :draft="rightDraft" /></div>
+ <div v-if="rightDraft.isDraft" class="content">
+ <draft-note :draft="rightDraft" :line="line.right" />
+ </div>
</td>
</tr>
</template>
diff --git a/app/assets/javascripts/batch_comments/components/preview_item.vue b/app/assets/javascripts/batch_comments/components/preview_item.vue
index 22495eb4d7d..3162a83f099 100644
--- a/app/assets/javascripts/batch_comments/components/preview_item.vue
+++ b/app/assets/javascripts/batch_comments/components/preview_item.vue
@@ -52,14 +52,12 @@ export default {
});
},
linePosition() {
- if (this.draft.position && this.draft.position.position_type === IMAGE_DIFF_POSITION_TYPE) {
+ if (this.position?.position_type === IMAGE_DIFF_POSITION_TYPE) {
// eslint-disable-next-line @gitlab/require-i18n-strings
- return `${this.draft.position.x}x ${this.draft.position.y}y`;
+ return `${this.position.x}x ${this.position.y}y`;
}
- const position = this.discussion ? this.discussion.position : this.draft.position;
-
- return position?.new_line || position?.old_line;
+ return this.position?.new_line || this.position?.old_line;
},
content() {
const el = document.createElement('div');
@@ -70,11 +68,14 @@ export default {
showLinePosition() {
return this.draft.file_hash || this.isDiffDiscussion;
},
+ position() {
+ return this.draft.position || this.discussion.position;
+ },
startLineNumber() {
- return getStartLineNumber(this.draft.position?.line_range);
+ return getStartLineNumber(this.position?.line_range);
},
endLineNumber() {
- return getEndLineNumber(this.draft.position?.line_range);
+ return getEndLineNumber(this.position?.line_range);
},
},
methods: {
diff --git a/app/assets/javascripts/commit_merge_requests.js b/app/assets/javascripts/commit_merge_requests.js
index 3a0ab119df6..3cdb1587a3b 100644
--- a/app/assets/javascripts/commit_merge_requests.js
+++ b/app/assets/javascripts/commit_merge_requests.js
@@ -15,14 +15,14 @@ export function createHeader(childElementCount, mergeRequestCount) {
const headerText = getHeaderText(childElementCount, mergeRequestCount);
return $('<span />', {
- class: 'append-right-5',
+ class: 'gl-mr-2',
text: headerText,
});
}
export function createLink(mergeRequest) {
return $('<a />', {
- class: 'append-right-5',
+ class: 'gl-mr-2',
href: mergeRequest.path,
text: `!${mergeRequest.iid}`,
});
diff --git a/app/assets/javascripts/diffs/components/diff_file_header.vue b/app/assets/javascripts/diffs/components/diff_file_header.vue
index 00eeac5a9d3..5dd80528726 100644
--- a/app/assets/javascripts/diffs/components/diff_file_header.vue
+++ b/app/assets/javascripts/diffs/components/diff_file_header.vue
@@ -163,16 +163,11 @@ export default {
:name="collapseIcon"
:size="16"
aria-hidden="true"
- class="diff-toggle-caret append-right-5"
+ class="diff-toggle-caret gl-mr-2"
@click.stop="handleToggleFile"
/>
<a v-once ref="titleWrapper" class="gl-mr-2" :href="titleLink" @click="handleFileNameClick">
- <file-icon
- :file-name="filePath"
- :size="18"
- aria-hidden="true"
- css-classes="append-right-5"
- />
+ <file-icon :file-name="filePath" :size="18" aria-hidden="true" css-classes="gl-mr-2" />
<span v-if="isFileRenamed">
<strong
v-gl-tooltip
@@ -208,7 +203,7 @@ export default {
{{ diffFile.a_mode }} → {{ diffFile.b_mode }}
</small>
- <span v-if="isUsingLfs" class="label label-lfs append-right-5"> {{ __('LFS') }} </span>
+ <span v-if="isUsingLfs" class="label label-lfs gl-mr-2"> {{ __('LFS') }} </span>
</div>
<div
diff --git a/app/assets/javascripts/diffs/components/diff_line_note_form.vue b/app/assets/javascripts/diffs/components/diff_line_note_form.vue
index 74305ee69bc..a737d956599 100644
--- a/app/assets/javascripts/diffs/components/diff_line_note_form.vue
+++ b/app/assets/javascripts/diffs/components/diff_line_note_form.vue
@@ -8,7 +8,10 @@ import MultilineCommentForm from '../../notes/components/multiline_comment_form.
import autosave from '../../notes/mixins/autosave';
import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue';
import { DIFF_NOTE_TYPE } from '../constants';
-import { commentLineOptions } from '../../notes/components/multiline_comment_utils';
+import {
+ commentLineOptions,
+ formatLineRange,
+} from '../../notes/components/multiline_comment_utils';
export default {
components: {
@@ -44,8 +47,10 @@ export default {
data() {
return {
commentLineStart: {
- lineCode: this.line.line_code,
+ line_code: this.line.line_code,
type: this.line.type,
+ old_line: this.line.old_line,
+ new_line: this.line.new_line,
},
};
},
@@ -74,19 +79,26 @@ export default {
diffViewType: this.diffViewType,
diffFile: this.diffFile,
linePosition: this.linePosition,
- lineRange: {
- start_line_code: this.commentLineStart.lineCode,
- start_line_type: this.commentLineStart.type,
- end_line_code: this.line.line_code,
- end_line_type: this.line.type,
- },
+ lineRange: formatLineRange(this.commentLineStart, this.line),
};
},
diffFile() {
return this.getDiffFileByHash(this.diffFileHash);
},
commentLineOptions() {
- return commentLineOptions(this.diffFile.highlighted_diff_lines, this.line.line_code);
+ const combineSides = (acc, { left, right }) => {
+ // ignore null values match lines
+ if (left && left.type !== 'match') acc.push(left);
+ // if the line_codes are identically, return to avoid duplicates
+ if (left?.line_code === right?.line_code) return acc;
+ if (right && right.type !== 'match') acc.push(right);
+ return acc;
+ };
+ const side = this.line.type === 'new' ? 'right' : 'left';
+ const lines = this.diffFile.highlighted_diff_lines.length
+ ? this.diffFile.highlighted_diff_lines
+ : this.diffFile.parallel_diff_lines.reduce(combineSides, []);
+ return commentLineOptions(lines, this.line, this.line.line_code, side);
},
},
mounted() {
@@ -136,10 +148,7 @@ export default {
<template>
<div class="content discussion-form discussion-form-container discussion-notes">
- <div
- v-if="glFeatures.multilineComments"
- class="gl-mb-3 gl-text-gray-700 gl-border-gray-200 gl-border-b-solid gl-border-b-1 gl-pb-3"
- >
+ <div v-if="glFeatures.multilineComments" class="gl-mb-3 gl-text-gray-700">
<multiline-comment-form
v-model="commentLineStart"
:line="line"
diff --git a/app/assets/javascripts/error_tracking/components/stacktrace_entry.vue b/app/assets/javascripts/error_tracking/components/stacktrace_entry.vue
index d806c6934a3..c22f34b5a8d 100644
--- a/app/assets/javascripts/error_tracking/components/stacktrace_entry.vue
+++ b/app/assets/javascripts/error_tracking/components/stacktrace_entry.vue
@@ -80,14 +80,9 @@ export default {
<div ref="header" class="file-title file-title-flex-parent">
<div class="file-header-content d-flex align-content-center">
<div v-if="hasCode" class="d-inline-block cursor-pointer" @click="toggle()">
- <icon :name="collapseIcon" :size="16" aria-hidden="true" class="append-right-5" />
+ <icon :name="collapseIcon" :size="16" aria-hidden="true" class="gl-mr-2" />
</div>
- <file-icon
- :file-name="filePath"
- :size="18"
- aria-hidden="true"
- css-classes="append-right-5"
- />
+ <file-icon :file-name="filePath" :size="18" aria-hidden="true" css-classes="gl-mr-2" />
<strong
v-gl-tooltip
:title="filePath"
diff --git a/app/assets/javascripts/notes/components/discussion_notes.vue b/app/assets/javascripts/notes/components/discussion_notes.vue
index 0b136549c14..b5e5daa8809 100644
--- a/app/assets/javascripts/notes/components/discussion_notes.vue
+++ b/app/assets/javascripts/notes/components/discussion_notes.vue
@@ -108,6 +108,7 @@ export default {
:commit="commit"
:help-page-path="helpPagePath"
:show-reply-button="userCanReply"
+ :discussion-root="true"
@handleDeleteNote="$emit('deleteNote')"
@startReplying="$emit('startReplying')"
>
@@ -151,6 +152,7 @@ export default {
:note="componentData(note)"
:help-page-path="helpPagePath"
:line="diffLine"
+ :discussion-root="index === 0"
@handleDeleteNote="$emit('deleteNote')"
>
<slot v-if="index === 0" slot="avatar-badge" name="avatar-badge"></slot>
diff --git a/app/assets/javascripts/notes/components/multiline_comment_form.vue b/app/assets/javascripts/notes/components/multiline_comment_form.vue
index 5fba011a153..6aa9a9aa450 100644
--- a/app/assets/javascripts/notes/components/multiline_comment_form.vue
+++ b/app/assets/javascripts/notes/components/multiline_comment_form.vue
@@ -21,10 +21,23 @@ export default {
},
data() {
return {
- commentLineStart: {
- lineCode: this.lineRange ? this.lineRange.start_line_code : this.line.line_code,
- type: this.lineRange ? this.lineRange.start_line_type : this.line.type,
- },
+ commentLineStart: {},
+ commentLineEndType: this.lineRange?.end?.line_type || this.line.type,
+ };
+ },
+ computed: {
+ lineNumber() {
+ return this.commentLineOptions[this.commentLineOptions.length - 1].text;
+ },
+ },
+ created() {
+ const line = this.lineRange?.start || this.line;
+
+ this.commentLineStart = {
+ line_code: line.line_code,
+ type: line.type,
+ old_line: line.old_line,
+ new_line: line.new_line,
};
},
methods: {
@@ -34,6 +47,10 @@ export default {
getLineClasses(line) {
return getLineClasses(line);
},
+ updateCommentLineStart(value) {
+ this.commentLineStart = value;
+ this.$emit('input', value);
+ },
},
};
</script>
@@ -55,12 +72,12 @@ export default {
:options="commentLineOptions"
size="sm"
class="gl-w-auto gl-vertical-align-baseline"
- @change="$emit('input', $event)"
+ @change="updateCommentLineStart"
/>
</template>
<template #end>
<span :class="getLineClasses(line)">
- {{ getSymbol(line) + (line.new_line || line.old_line) }}
+ {{ lineNumber }}
</span>
</template>
</gl-sprintf>
diff --git a/app/assets/javascripts/notes/components/multiline_comment_utils.js b/app/assets/javascripts/notes/components/multiline_comment_utils.js
index dc9c55e9b30..e8a834df713 100644
--- a/app/assets/javascripts/notes/components/multiline_comment_utils.js
+++ b/app/assets/javascripts/notes/components/multiline_comment_utils.js
@@ -7,11 +7,19 @@ export function getSymbol(type) {
}
function getLineNumber(lineRange, key) {
- if (!lineRange || !key) return '';
- const lineCode = lineRange[`${key}_line_code`] || '';
- const lineType = lineRange[`${key}_line_type`] || '';
- const lines = lineCode.split('_') || [];
- const lineNumber = lineType === 'old' ? lines[1] : lines[2];
+ if (!lineRange || !key || !lineRange[key]) return '';
+ const { new_line: newLine, old_line: oldLine, type } = lineRange[key];
+ const otherKey = key === 'start' ? 'end' : 'start';
+
+ // By default we want to see the "old" or "left side" line number
+ // The exception is if the "end" line is on the "right" side
+ // `otherLineType` is only used if `type` is null to make sure the line
+ // number relfects the "right" side number, if that is the side
+ // the comment form is located on
+ const otherLineType = !type ? lineRange[otherKey]?.type : null;
+ const lineType = type || '';
+ let lineNumber = oldLine;
+ if (lineType === 'new' || otherLineType === 'new') lineNumber = newLine;
return (lineNumber && getSymbol(lineType) + lineNumber) || '';
}
@@ -37,21 +45,48 @@ export function getLineClasses(line) {
];
}
-export function commentLineOptions(diffLines, lineCode) {
- const selectedIndex = diffLines.findIndex(line => line.line_code === lineCode);
+export function commentLineOptions(diffLines, startingLine, lineCode, side = 'left') {
+ const preferredSide = side === 'left' ? 'old_line' : 'new_line';
+ const fallbackSide = preferredSide === 'new_line' ? 'old_line' : 'new_line';
const notMatchType = l => l.type !== 'match';
+ const linesCopy = [...diffLines]; // don't mutate the argument
+ const startingLineCode = startingLine.line_code;
+
+ const currentIndex = linesCopy.findIndex(line => line.line_code === lineCode);
// We're limiting adding comments to only lines above the current line
// to make rendering simpler. Future interations will use a more
// intuitive dragging interface that will make this unnecessary
- const upToSelected = diffLines.slice(0, selectedIndex + 1);
+ const upToSelected = linesCopy.slice(0, currentIndex + 1);
// Only include the lines up to the first "Show unchanged lines" block
// i.e. not a "match" type
const lines = takeRightWhile(upToSelected, notMatchType);
- return lines.map(l => ({
- value: { lineCode: l.line_code, type: l.type },
- text: `${getSymbol(l.type)}${l.new_line || l.old_line}`,
- }));
+ // If the selected line is "hidden" in an unchanged line block
+ // or "above" the current group of lines add it to the array so
+ // that the drop down is not defaulted to empty
+ const selectedIndex = lines.findIndex(line => line.line_code === startingLineCode);
+ if (selectedIndex < 0) lines.unshift(startingLine);
+
+ return lines.map(l => {
+ const { line_code, type, old_line, new_line } = l;
+ return {
+ value: { line_code, type, old_line, new_line },
+ text: `${getSymbol(type)}${l[preferredSide] || l[fallbackSide]}`,
+ };
+ });
+}
+
+export function formatLineRange(start, end) {
+ const extractProps = ({ line_code, type, old_line, new_line }) => ({
+ line_code,
+ type,
+ old_line,
+ new_line,
+ });
+ return {
+ start: extractProps(start),
+ end: extractProps(end),
+ };
}
diff --git a/app/assets/javascripts/notes/components/noteable_note.vue b/app/assets/javascripts/notes/components/noteable_note.vue
index 0e4dd1b9c84..611bd19e628 100644
--- a/app/assets/javascripts/notes/components/noteable_note.vue
+++ b/app/assets/javascripts/notes/components/noteable_note.vue
@@ -21,6 +21,7 @@ import {
getEndLineNumber,
getLineClasses,
commentLineOptions,
+ formatLineRange,
} from './multiline_comment_utils';
import MultilineCommentForm from './multiline_comment_form.vue';
@@ -62,10 +63,15 @@ export default {
default: false,
},
diffLines: {
- type: Object,
+ type: Array,
required: false,
default: null,
},
+ discussionRoot: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
},
data() {
return {
@@ -73,10 +79,7 @@ export default {
isDeleting: false,
isRequesting: false,
isResolving: false,
- commentLineStart: {
- line_code: this.line?.line_code,
- type: this.line?.type,
- },
+ commentLineStart: {},
};
},
computed: {
@@ -144,25 +147,42 @@ export default {
return getEndLineNumber(this.lineRange);
},
showMultiLineComment() {
- return (
- this.glFeatures.multilineComments &&
- this.startLineNumber &&
- this.endLineNumber &&
- (this.startLineNumber !== this.endLineNumber || this.isEditing)
- );
+ if (!this.glFeatures.multilineComments) return false;
+ if (this.isEditing) return true;
+
+ return this.line && this.discussionRoot && this.startLineNumber !== this.endLineNumber;
},
commentLineOptions() {
- if (this.diffLines) {
- return commentLineOptions(this.diffLines, this.line.line_code);
+ if (!this.diffFile || !this.line) return [];
+
+ const sideA = this.line.type === 'new' ? 'right' : 'left';
+ const sideB = sideA === 'left' ? 'right' : 'left';
+ const lines = this.diffFile.highlighted_diff_lines.length
+ ? this.diffFile.highlighted_diff_lines
+ : this.diffFile.parallel_diff_lines.map(l => l[sideA] || l[sideB]);
+ return commentLineOptions(lines, this.commentLineStart, this.line.line_code, sideA);
+ },
+ diffFile() {
+ if (this.commentLineStart.line_code) {
+ const lineCode = this.commentLineStart.line_code.split('_')[0];
+ return this.getDiffFileByHash(lineCode);
}
- const diffFile = this.diffFile || this.getDiffFileByHash(this.targetNoteHash);
- if (!diffFile) return null;
- return commentLineOptions(diffFile.highlighted_diff_lines, this.line.line_code);
+ return null;
},
},
-
created() {
+ const line = this.note.position?.line_range?.start || this.line;
+
+ this.commentLineStart = line
+ ? {
+ line_code: line.line_code,
+ type: line.type,
+ old_line: line.old_line,
+ new_line: line.new_line,
+ }
+ : {};
+
eventHub.$on('enterEditMode', ({ noteId }) => {
if (noteId === this.note.id) {
this.isEditing = true;
@@ -224,13 +244,11 @@ export default {
formUpdateHandler(noteText, parentElement, callback, resolveDiscussion) {
const position = {
...this.note.position,
- line_range: {
- start_line_code: this.commentLineStart?.lineCode,
- start_line_type: this.commentLineStart?.type,
- end_line_code: this.line?.line_code,
- end_line_type: this.line?.type,
- },
};
+
+ if (this.commentLineStart && this.line)
+ position.line_range = formatLineRange(this.commentLineStart, this.line);
+
this.$emit('handleUpdateNote', {
note: this.note,
noteText,
@@ -246,7 +264,7 @@ export default {
note: {
target_type: this.getNoteableData.targetType,
target_id: this.note.noteable_id,
- note: { note: noteText },
+ note: { note: noteText, position: JSON.stringify(position) },
},
};
this.isRequesting = true;
@@ -317,14 +335,17 @@ export default {
>
<div v-if="showMultiLineComment" data-testid="multiline-comment">
<multiline-comment-form
- v-if="isEditing && commentLineOptions && line"
+ v-if="isEditing && note.position"
v-model="commentLineStart"
:line="line"
:comment-line-options="commentLineOptions"
:line-range="note.position.line_range"
- class="gl-mb-3 gl-text-gray-700 gl-border-gray-200 gl-border-b-solid gl-border-b-1 gl-pb-3"
+ class="gl-mb-3 gl-text-gray-700"
/>
- <div v-else class="gl-mb-3 gl-text-gray-700">
+ <div
+ v-else
+ class="gl-mb-3 gl-text-gray-700 gl-border-gray-200 gl-border-b-solid gl-border-b-1 gl-pb-3"
+ >
<gl-sprintf :message="__('Comment on lines %{startLine} to %{endLine}')">
<template #startLine>
<span :class="getLineClasses(startLineNumber)">{{ startLineNumber }}</span>
diff --git a/app/assets/javascripts/notes/mixins/diff_line_note_form.js b/app/assets/javascripts/notes/mixins/diff_line_note_form.js
index 5930b5f3321..9a2e86aeed2 100644
--- a/app/assets/javascripts/notes/mixins/diff_line_note_form.js
+++ b/app/assets/javascripts/notes/mixins/diff_line_note_form.js
@@ -4,6 +4,7 @@ import { TEXT_DIFF_POSITION_TYPE, IMAGE_DIFF_POSITION_TYPE } from '~/diffs/const
import createFlash from '~/flash';
import { s__ } from '~/locale';
import { clearDraft } from '~/lib/utils/autosave';
+import { formatLineRange } from '~/notes/components/multiline_comment_utils';
export default {
computed: {
@@ -45,6 +46,9 @@ export default {
});
},
addToReview(note) {
+ const lineRange =
+ (this.line && this.commentLineStart && formatLineRange(this.commentLineStart, this.line)) ||
+ {};
const positionType = this.diffFileCommentForm
? IMAGE_DIFF_POSITION_TYPE
: TEXT_DIFF_POSITION_TYPE;
@@ -60,6 +64,7 @@ export default {
linePosition: this.position,
positionType,
...this.diffFileCommentForm,
+ lineRange,
});
const diffFileHeadSha = this.commit && this?.diffFile?.diff_refs?.head_sha;
diff --git a/app/assets/javascripts/reports/accessibility_report/components/accessibility_issue_body.vue b/app/assets/javascripts/reports/accessibility_report/components/accessibility_issue_body.vue
index eb02714b262..575dd45f2d3 100644
--- a/app/assets/javascripts/reports/accessibility_report/components/accessibility_issue_body.vue
+++ b/app/assets/javascripts/reports/accessibility_report/components/accessibility_issue_body.vue
@@ -38,11 +38,7 @@ export default {
<template>
<div class="report-block-list-issue-description prepend-top-5 gl-mb-2">
<div ref="accessibility-issue-description" class="report-block-list-issue-description-text">
- <div
- v-if="isNew"
- ref="accessibility-issue-is-new-badge"
- class="badge badge-danger append-right-5"
- >
+ <div v-if="isNew" ref="accessibility-issue-is-new-badge" class="badge badge-danger gl-mr-2">
{{ s__('AccessibilityReport|New') }}
</div>
<div>
diff --git a/app/assets/javascripts/reports/components/test_issue_body.vue b/app/assets/javascripts/reports/components/test_issue_body.vue
index de476fda8ed..167c34846df 100644
--- a/app/assets/javascripts/reports/components/test_issue_body.vue
+++ b/app/assets/javascripts/reports/components/test_issue_body.vue
@@ -32,7 +32,7 @@ export default {
class="btn-link btn-blank text-left break-link vulnerability-name-button"
@click="openModal({ issue })"
>
- <div v-if="isNew" class="badge badge-danger append-right-5">{{ s__('New') }}</div>
+ <div v-if="isNew" class="badge badge-danger gl-mr-2">{{ s__('New') }}</div>
{{ issue.name }}
</button>
</div>
diff --git a/app/assets/javascripts/snippets/components/snippet_header.vue b/app/assets/javascripts/snippets/components/snippet_header.vue
index 4bd1453830c..707e2b0ea30 100644
--- a/app/assets/javascripts/snippets/components/snippet_header.vue
+++ b/app/assets/javascripts/snippets/components/snippet_header.vue
@@ -166,7 +166,7 @@ export default {
<div class="detail-page-header">
<div class="detail-page-header-body">
<div
- class="snippet-box has-tooltip d-flex align-items-center append-right-5 mb-1"
+ class="snippet-box has-tooltip d-flex align-items-center gl-mr-2 mb-1"
data-qa-selector="snippet_container"
:title="snippetVisibilityLevelDescription"
data-container="body"
diff --git a/app/assets/javascripts/vue_shared/components/loading_button.vue b/app/assets/javascripts/vue_shared/components/loading_button.vue
index 3508c557289..59ce632c4a2 100644
--- a/app/assets/javascripts/vue_shared/components/loading_button.vue
+++ b/app/assets/javascripts/vue_shared/components/loading_button.vue
@@ -47,7 +47,7 @@ export default {
v-if="loading"
:inline="true"
:class="{
- 'append-right-5': label,
+ 'gl-mr-2': label,
}"
class="js-loading-button-icon"
/>
diff --git a/app/assets/javascripts/vue_shared/components/notes/system_note.vue b/app/assets/javascripts/vue_shared/components/notes/system_note.vue
index b6271a95008..fe57d4f29ca 100644
--- a/app/assets/javascripts/vue_shared/components/notes/system_note.vue
+++ b/app/assets/javascripts/vue_shared/components/notes/system_note.vue
@@ -122,7 +122,7 @@ export default {
></div>
<div v-if="hasMoreCommits" class="flex-list">
<div class="system-note-commit-list-toggler flex-row" @click="expanded = !expanded">
- <icon :name="toggleIcon" :size="8" class="append-right-5" />
+ <icon :name="toggleIcon" :size="8" class="gl-mr-2" />
<span>{{ __('Toggle commit list') }}</span>
</div>
</div>
diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss
index 365b7358e16..ebf79e858e9 100644
--- a/app/assets/stylesheets/framework/common.scss
+++ b/app/assets/stylesheets/framework/common.scss
@@ -405,7 +405,6 @@ img.emoji {
.prepend-left-15 { margin-left: 15px; }
.prepend-left-20 { margin-left: 20px; }
.prepend-left-64 { margin-left: 64px; }
-.append-right-5 { margin-right: 5px; }
.append-right-10 { margin-right: 10px; }
.append-right-15 { margin-right: 15px; }
.append-right-20 { margin-right: 20px; }
diff --git a/app/controllers/concerns/notes_actions.rb b/app/controllers/concerns/notes_actions.rb
index d3dfb1813e4..eff125a1957 100644
--- a/app/controllers/concerns/notes_actions.rb
+++ b/app/controllers/concerns/notes_actions.rb
@@ -226,7 +226,7 @@ module NotesActions
end
def update_note_params
- params.require(:note).permit(:note)
+ params.require(:note).permit(:note, :position)
end
def set_polling_interval_header
diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb
index 680a1a5a919..f8490d79427 100644
--- a/app/helpers/commits_helper.rb
+++ b/app/helpers/commits_helper.rb
@@ -79,7 +79,7 @@ module CommitsHelper
# Returns a link formatted as a commit tag link
def commit_tag_link(url, text)
link_to(url, class: 'badge badge-gray ref-name') do
- sprite_icon('tag', size: 12, css_class: 'append-right-5 vertical-align-middle') + "#{text}"
+ sprite_icon('tag', size: 12, css_class: 'gl-mr-2 vertical-align-middle') + "#{text}"
end
end
diff --git a/app/models/commit.rb b/app/models/commit.rb
index 681fe727456..53bcdf8165f 100644
--- a/app/models/commit.rb
+++ b/app/models/commit.rb
@@ -469,10 +469,12 @@ class Commit
# We don't want to do anything for `Commit` model, so this is empty.
end
- WIP_REGEX = /\A\s*(((?i)(\[WIP\]|WIP:|WIP)\s|WIP$))|(fixup!|squash!)\s/.freeze
+ # WIP is deprecated in favor of Draft. Currently both options are supported
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/227426
+ DRAFT_REGEX = /\A\s*#{Regexp.union(Gitlab::Regex.merge_request_wip, Gitlab::Regex.merge_request_draft)}|(fixup!|squash!)\s/.freeze
def work_in_progress?
- !!(title =~ WIP_REGEX)
+ !!(title =~ DRAFT_REGEX)
end
def merged_merge_request?(user)
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 6a3fba93aea..c6437f66148 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -391,25 +391,27 @@ class MergeRequest < ApplicationRecord
end
end
- WIP_REGEX = /\A*(\[WIP\]\s*|WIP:\s*|WIP\s+)+\s*/i.freeze
+ # WIP is deprecated in favor of Draft. Currently both options are supported
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/227426
+ DRAFT_REGEX = /\A*#{Regexp.union(Gitlab::Regex.merge_request_wip, Gitlab::Regex.merge_request_draft)}+\s*/i.freeze
def self.work_in_progress?(title)
- !!(title =~ WIP_REGEX)
+ !!(title =~ DRAFT_REGEX)
end
def self.wipless_title(title)
- title.sub(WIP_REGEX, "")
+ title.sub(DRAFT_REGEX, "")
end
def self.wip_title(title)
- work_in_progress?(title) ? title : "WIP: #{title}"
+ work_in_progress?(title) ? title : "Draft: #{title}"
end
def committers
@committers ||= commits.committers
end
- # Verifies if title has changed not taking into account WIP prefix
+ # Verifies if title has changed not taking into account Draft prefix
# for merge requests.
def wipless_title_changed(old_title)
self.class.wipless_title(old_title) != self.wipless_title
diff --git a/app/services/jira/requests/issues/list_service.rb b/app/services/jira/requests/issues/list_service.rb
index 44a3d3966a8..5752e77d16f 100644
--- a/app/services/jira/requests/issues/list_service.rb
+++ b/app/services/jira/requests/issues/list_service.rb
@@ -13,15 +13,16 @@ module Jira
@jql = params[:jql].to_s
@page = params[:page].to_i || 1
+ @per_page = params[:per_page].to_i || PER_PAGE
end
private
- attr_reader :jql, :page
+ attr_reader :jql, :page, :per_page
override :url
def url
- "#{base_api_url}/search?jql=#{CGI.escape(jql)}&startAt=#{start_at}&maxResults=#{PER_PAGE}&fields=*all"
+ "#{base_api_url}/search?jql=#{CGI.escape(jql)}&startAt=#{start_at}&maxResults=#{per_page}&fields=*all"
end
override :build_service_response
@@ -48,7 +49,7 @@ module Jira
end
def start_at
- (page - 1) * PER_PAGE
+ (page - 1) * per_page
end
end
end
diff --git a/app/services/personal_access_tokens/last_used_service.rb b/app/services/personal_access_tokens/last_used_service.rb
new file mode 100644
index 00000000000..9066fd1acdf
--- /dev/null
+++ b/app/services/personal_access_tokens/last_used_service.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+module PersonalAccessTokens
+ class LastUsedService
+ def initialize(personal_access_token)
+ @personal_access_token = personal_access_token
+ end
+
+ def execute
+ # Needed to avoid calling service on Oauth tokens
+ return unless @personal_access_token.has_attribute?(:last_used_at)
+
+ # We _only_ want to update last_used_at and not also updated_at (which
+ # would be updated when using #touch).
+ @personal_access_token.update_column(:last_used_at, Time.zone.now) if update?
+ end
+
+ private
+
+ def update?
+ return false if ::Gitlab::Database.read_only?
+
+ last_used = @personal_access_token.last_used_at
+
+ last_used.nil? || (last_used <= 1.day.ago)
+ end
+ end
+end
diff --git a/app/services/update_container_registry_info_service.rb b/app/services/update_container_registry_info_service.rb
new file mode 100644
index 00000000000..531335839a9
--- /dev/null
+++ b/app/services/update_container_registry_info_service.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+class UpdateContainerRegistryInfoService
+ def execute
+ registry_config = Gitlab.config.registry
+ return unless registry_config.enabled && registry_config.api_url.presence
+
+ # registry_info will query the /v2 route of the registry API. This route
+ # requires authentication, but not authorization (the response has no body,
+ # only headers that show the version of the registry). There might be no
+ # associated user when running this (e.g. from a rake task or a cron job),
+ # so we need to generate a valid JWT token with no access permissions to
+ # authenticate as a trusted client.
+ token = Auth::ContainerRegistryAuthenticationService.access_token([], [])
+ client = ContainerRegistry::Client.new(registry_config.api_url, token: token)
+ info = client.registry_info
+
+ Gitlab::CurrentSettings.update!(
+ container_registry_vendor: info[:vendor] || '',
+ container_registry_version: info[:version] || '',
+ container_registry_features: info[:features] || []
+ )
+ end
+end
diff --git a/app/views/doorkeeper/applications/index.html.haml b/app/views/doorkeeper/applications/index.html.haml
index bf8e2d2dd31..051799ca13f 100644
--- a/app/views/doorkeeper/applications/index.html.haml
+++ b/app/views/doorkeeper/applications/index.html.haml
@@ -41,7 +41,7 @@
%div= uri
%td= application.access_tokens.count
%td
- = link_to edit_oauth_application_path(application), class: "btn btn-transparent append-right-5" do
+ = link_to edit_oauth_application_path(application), class: "btn btn-transparent gl-mr-2" do
%span.sr-only
= _('Edit')
= icon('pencil')
diff --git a/app/views/profiles/_event_table.html.haml b/app/views/profiles/_event_table.html.haml
index c65c4fd0d81..b952868e4e3 100644
--- a/app/views/profiles/_event_table.html.haml
+++ b/app/views/profiles/_event_table.html.haml
@@ -5,7 +5,7 @@
- events.each do |event|
%li
%span.description
- = audit_icon(event.details[:with], class: "append-right-5")
+ = audit_icon(event.details[:with], class: "gl-mr-2")
= _('Signed in with %{authentication} authentication') % { authentication: event.details[:with]}
%span.float-right= time_ago_with_tooltip(event.created_at)
diff --git a/app/views/profiles/notifications/_group_settings.html.haml b/app/views/profiles/notifications/_group_settings.html.haml
index a25cd78fb0b..404bb224655 100644
--- a/app/views/profiles/notifications/_group_settings.html.haml
+++ b/app/views/profiles/notifications/_group_settings.html.haml
@@ -2,7 +2,7 @@
.gl-responsive-table-row.notification-list-item
.table-section.section-40
- %span.notification.fa.fa-holder.append-right-5
+ %span.notification.fa.fa-holder.gl-mr-2
= notification_icon(notification_icon_level(setting, emails_disabled))
%span.str-truncated
diff --git a/app/views/profiles/notifications/_project_settings.html.haml b/app/views/profiles/notifications/_project_settings.html.haml
index 63a77b335b6..f9172ae87aa 100644
--- a/app/views/profiles/notifications/_project_settings.html.haml
+++ b/app/views/profiles/notifications/_project_settings.html.haml
@@ -1,7 +1,7 @@
- emails_disabled = project.emails_disabled?
%li.notification-list-item
- %span.notification.fa.fa-holder.append-right-5
+ %span.notification.fa.fa-holder.gl-mr-2
= notification_icon(notification_icon_level(setting, emails_disabled))
%span.str-truncated
diff --git a/app/views/projects/_home_panel.html.haml b/app/views/projects/_home_panel.html.haml
index 3f6ceaba5b2..9966baf78f4 100644
--- a/app/views/projects/_home_panel.html.haml
+++ b/app/views/projects/_home_panel.html.haml
@@ -27,7 +27,7 @@
= sprite_icon('tag', size: 16, css_class: 'icon gl-mr-2')
- @project.topics_to_show.each do |topic|
- - project_topics_classes = "badge badge-pill badge-secondary append-right-5"
+ - project_topics_classes = "badge badge-pill badge-secondary gl-mr-2"
- explore_project_topic_path = explore_projects_path(tag: topic)
- if topic.length > max_project_topic_length
%a{ class: "#{ project_topics_classes } str-truncated-30 has-tooltip", data: { container: "body" }, title: topic, href: explore_project_topic_path }
diff --git a/app/views/projects/blob/_header_content.html.haml b/app/views/projects/blob/_header_content.html.haml
index 6527c6021a0..32adfb320ff 100644
--- a/app/views/projects/blob/_header_content.html.haml
+++ b/app/views/projects/blob/_header_content.html.haml
@@ -10,4 +10,4 @@
= number_to_human_size(blob.raw_size)
- if blob.stored_externally? && blob.external_storage == :lfs
- %span.badge.label-lfs.append-right-5 LFS
+ %span.badge.label-lfs.gl-mr-2 LFS
diff --git a/app/views/projects/diffs/_file_header.html.haml b/app/views/projects/diffs/_file_header.html.haml
index 6a1bff8640c..f954b09abee 100644
--- a/app/views/projects/diffs/_file_header.html.haml
+++ b/app/views/projects/diffs/_file_header.html.haml
@@ -37,4 +37,4 @@
#{diff_file.a_mode} → #{diff_file.b_mode}
- if diff_file.stored_externally? && diff_file.external_storage == :lfs
- %span.badge.label-lfs.append-right-5 LFS
+ %span.badge.label-lfs.gl-mr-2 LFS
diff --git a/app/views/shared/access_tokens/_table.html.haml b/app/views/shared/access_tokens/_table.html.haml
index 33775090dc7..55231cb9429 100644
--- a/app/views/shared/access_tokens/_table.html.haml
+++ b/app/views/shared/access_tokens/_table.html.haml
@@ -16,6 +16,9 @@
%tr
%th= _('Name')
%th= s_('AccessTokens|Created')
+ %th
+ = _('Last Used')
+ = link_to icon('question-circle'), help_page_path('user/profile/personal_access_tokens.md', anchor: 'token-activity'), target: '_blank'
%th= _('Expires')
%th= _('Scopes')
%th
@@ -25,6 +28,11 @@
%td= token.name
%td= token.created_at.to_date.to_s(:medium)
%td
+ - if token.last_used_at?
+ %span.token-last-used-label= _(time_ago_with_tooltip(token.last_used_at))
+ - else
+ %span.token-never-used-label= _('Never')
+ %td
- if token.expires?
- if token.expires_at.past? || token.expires_at.today?
%span{ class: 'text-danger has-tooltip', title: _('Expiration not enforced') }
diff --git a/app/views/shared/snippets/_header.html.haml b/app/views/shared/snippets/_header.html.haml
index 7f213c50de2..36b6bfd061f 100644
--- a/app/views/shared/snippets/_header.html.haml
+++ b/app/views/shared/snippets/_header.html.haml
@@ -1,6 +1,6 @@
.detail-page-header
.detail-page-header-body
- .snippet-box.has-tooltip.inline.append-right-5{ title: snippet_visibility_level_description(@snippet.visibility_level, @snippet), data: { container: "body" } }
+ .snippet-box.has-tooltip.inline.gl-mr-2{ title: snippet_visibility_level_description(@snippet.visibility_level, @snippet), data: { container: "body" } }
%span.sr-only
= visibility_level_label(@snippet.visibility_level)
= visibility_level_icon(@snippet.visibility_level, fw: false)
diff --git a/app/views/shared/wikis/_sidebar.html.haml b/app/views/shared/wikis/_sidebar.html.haml
index bb0b42a9bfd..cddf19fbc8e 100644
--- a/app/views/shared/wikis/_sidebar.html.haml
+++ b/app/views/shared/wikis/_sidebar.html.haml
@@ -6,7 +6,7 @@
- git_access_url = wiki_path(@wiki, action: :git_access)
= link_to git_access_url, class: active_nav_link?(path: 'wikis#git_access') ? 'active' : '', data: { qa_selector: 'clone_repository_link' } do
- = sprite_icon('download', size: 16, css_class: 'append-right-5')
+ = sprite_icon('download', size: 16, css_class: 'gl-mr-2')
%span= _("Clone repository")
.blocks-container
diff --git a/app/workers/concerns/worker_attributes.rb b/app/workers/concerns/worker_attributes.rb
index 2efa703684c..bb6192166b4 100644
--- a/app/workers/concerns/worker_attributes.rb
+++ b/app/workers/concerns/worker_attributes.rb
@@ -71,14 +71,14 @@ module WorkerAttributes
# Set this attribute on a job when it will call to services outside of the
# application, such as 3rd party applications, other k8s clusters etc See
- # doc/development/sidekiq_style_guide.md#Jobs-with-External-Dependencies for
+ # doc/development/sidekiq_style_guide.md#jobs-with-external-dependencies for
# details
def worker_has_external_dependencies!
class_attributes[:external_dependencies] = true
end
# Returns a truthy value if the worker has external dependencies.
- # See doc/development/sidekiq_style_guide.md#Jobs-with-External-Dependencies
+ # See doc/development/sidekiq_style_guide.md#jobs-with-external-dependencies
# for details
def worker_has_external_dependencies?
class_attributes[:external_dependencies]