diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-07-09 00:09:09 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-07-09 00:09:09 +0300 |
commit | 83fc2f3dc81052cad76addb44726876ba1d0f156 (patch) | |
tree | 1d58eedea14b1462b40bc5b02c9561e5a128ac0b /app | |
parent | 1d3086ebb41758289c1184dc5ad1462c81e1a1f9 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
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] |