summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/diffs/components/diff_row.vue
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/diffs/components/diff_row.vue')
-rw-r--r--app/assets/javascripts/diffs/components/diff_row.vue271
1 files changed, 271 insertions, 0 deletions
diff --git a/app/assets/javascripts/diffs/components/diff_row.vue b/app/assets/javascripts/diffs/components/diff_row.vue
new file mode 100644
index 00000000000..77a97c67f3b
--- /dev/null
+++ b/app/assets/javascripts/diffs/components/diff_row.vue
@@ -0,0 +1,271 @@
+<script>
+import { mapActions, mapGetters, mapState } from 'vuex';
+import { GlTooltipDirective, GlIcon, GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui';
+import { CONTEXT_LINE_CLASS_NAME, PARALLEL_DIFF_VIEW_TYPE } from '../constants';
+import DiffGutterAvatars from './diff_gutter_avatars.vue';
+import * as utils from './diff_row_utils';
+
+export default {
+ components: {
+ GlIcon,
+ DiffGutterAvatars,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ SafeHtml,
+ },
+ props: {
+ fileHash: {
+ type: String,
+ required: true,
+ },
+ filePath: {
+ type: String,
+ required: true,
+ },
+ line: {
+ type: Object,
+ required: true,
+ },
+ isCommented: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ inline: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+ computed: {
+ ...mapGetters('diffs', ['fileLineCoverage']),
+ ...mapGetters(['isLoggedIn']),
+ ...mapState({
+ isHighlighted(state) {
+ const line = this.line.left?.line_code ? this.line.left : this.line.right;
+ return utils.isHighlighted(state, line, this.isCommented);
+ },
+ }),
+ classNameMap() {
+ return {
+ [CONTEXT_LINE_CLASS_NAME]: this.line.isContextLineLeft,
+ [PARALLEL_DIFF_VIEW_TYPE]: true,
+ };
+ },
+ parallelViewLeftLineType() {
+ return utils.parallelViewLeftLineType(this.line, this.isHighlighted);
+ },
+ coverageState() {
+ return this.fileLineCoverage(this.filePath, this.line.right.new_line);
+ },
+ classNameMapCellLeft() {
+ return utils.classNameMapCell(this.line.left, this.isHighlighted, this.isLoggedIn);
+ },
+ classNameMapCellRight() {
+ return utils.classNameMapCell(this.line.right, this.isHighlighted, this.isLoggedIn);
+ },
+ addCommentTooltipLeft() {
+ return utils.addCommentTooltip(this.line.left);
+ },
+ addCommentTooltipRight() {
+ return utils.addCommentTooltip(this.line.right);
+ },
+ shouldRenderCommentButton() {
+ return (
+ this.isLoggedIn &&
+ !this.line.isContextLineLeft &&
+ !this.line.isMetaLineLeft &&
+ !this.line.hasDiscussionsLeft &&
+ !this.line.hasDiscussionsRight
+ );
+ },
+ },
+ mounted() {
+ this.scrollToLineIfNeededParallel(this.line);
+ },
+ methods: {
+ ...mapActions('diffs', [
+ 'scrollToLineIfNeededParallel',
+ 'showCommentForm',
+ 'setHighlightedRow',
+ 'toggleLineDiscussions',
+ ]),
+ // Prevent text selecting on both sides of parallel diff view
+ // Backport of the same code from legacy diff notes.
+ handleParallelLineMouseDown(e) {
+ const line = e.currentTarget;
+ const table = line.closest('.diff-table');
+
+ table.classList.remove('left-side-selected', 'right-side-selected');
+ const [lineClass] = ['left-side', 'right-side'].filter(name => line.classList.contains(name));
+
+ if (lineClass) {
+ table.classList.add(`${lineClass}-selected`);
+ }
+ },
+ handleCommentButton(line) {
+ this.showCommentForm({ lineCode: line.line_code, fileHash: this.fileHash });
+ },
+ },
+};
+</script>
+
+<template>
+ <div :class="classNameMap" class="diff-grid-row diff-tr line_holder">
+ <div class="diff-grid-left left-side">
+ <template v-if="line.left">
+ <div
+ :class="classNameMapCellLeft"
+ data-testid="leftLineNumber"
+ class="diff-td diff-line-num old_line"
+ >
+ <span
+ v-if="shouldRenderCommentButton"
+ v-gl-tooltip
+ data-testid="leftCommentButton"
+ class="add-diff-note tooltip-wrapper"
+ :title="addCommentTooltipLeft"
+ >
+ <button
+ type="button"
+ class="add-diff-note note-button js-add-diff-note-button qa-diff-comment"
+ :disabled="line.left.commentsDisabled"
+ @click="handleCommentButton(line.left)"
+ >
+ <gl-icon :size="12" name="comment" />
+ </button>
+ </span>
+ <a
+ v-if="line.left.old_line"
+ :data-linenumber="line.left.old_line"
+ :href="line.lineHrefOld"
+ @click="setHighlightedRow(line.lineCode)"
+ >
+ </a>
+ <diff-gutter-avatars
+ v-if="line.hasDiscussionsLeft"
+ :discussions="line.left.discussions"
+ :discussions-expanded="line.left.discussionsExpanded"
+ data-testid="leftDiscussions"
+ @toggleLineDiscussions="
+ toggleLineDiscussions({
+ lineCode: line.left.line_code,
+ fileHash,
+ expanded: !line.left.discussionsExpanded,
+ })
+ "
+ />
+ </div>
+ <div :class="classNameMapCellLeft" class="diff-td diff-line-num old_line">
+ <a
+ v-if="line.left.old_line"
+ :data-linenumber="line.left.old_line"
+ :href="line.lineHrefOld"
+ @click="setHighlightedRow(line.lineCode)"
+ >
+ </a>
+ </div>
+ <div :class="parallelViewLeftLineType" class="diff-td line-coverage left-side"></div>
+ <div
+ :id="line.left.line_code"
+ :key="line.left.line_code"
+ v-safe-html="line.left.rich_text"
+ :class="parallelViewLeftLineType"
+ class="diff-td line_content with-coverage parallel left-side"
+ data-testid="leftContent"
+ @mousedown="handleParallelLineMouseDown"
+ ></div>
+ </template>
+ <template v-else>
+ <div data-testid="leftEmptyCell" class="diff-td diff-line-num old_line empty-cell"></div>
+ <div class="diff-td diff-line-num old_line empty-cell"></div>
+ <div class="diff-td line-coverage left-side empty-cell"></div>
+ <div class="diff-td line_content with-coverage parallel left-side empty-cell"></div>
+ </template>
+ </div>
+ <div
+ v-if="!inline || (line.right && Boolean(line.right.type))"
+ class="diff-grid-right right-side"
+ >
+ <template v-if="line.right">
+ <div
+ :class="classNameMapCellRight"
+ data-testid="rightLineNumber"
+ class="diff-td diff-line-num new_line"
+ >
+ <span
+ v-if="shouldRenderCommentButton"
+ v-gl-tooltip
+ data-testid="rightCommentButton"
+ class="add-diff-note tooltip-wrapper"
+ :title="addCommentTooltipRight"
+ >
+ <button
+ type="button"
+ class="add-diff-note note-button js-add-diff-note-button qa-diff-comment"
+ :disabled="line.right.commentsDisabled"
+ @click="handleCommentButton(line.right)"
+ >
+ <gl-icon :size="12" name="comment" />
+ </button>
+ </span>
+ <a
+ v-if="line.right.new_line"
+ :data-linenumber="line.right.new_line"
+ :href="line.lineHrefNew"
+ @click="setHighlightedRow(line.lineCode)"
+ >
+ </a>
+ <diff-gutter-avatars
+ v-if="line.hasDiscussionsRight"
+ :discussions="line.right.discussions"
+ :discussions-expanded="line.right.discussionsExpanded"
+ data-testid="rightDiscussions"
+ @toggleLineDiscussions="
+ toggleLineDiscussions({
+ lineCode: line.right.line_code,
+ fileHash,
+ expanded: !line.right.discussionsExpanded,
+ })
+ "
+ />
+ </div>
+ <div :class="classNameMapCellRight" class="diff-td diff-line-num new_line">
+ <a
+ v-if="line.right.new_line"
+ :data-linenumber="line.right.new_line"
+ :href="line.lineHrefNew"
+ @click="setHighlightedRow(line.lineCode)"
+ >
+ </a>
+ </div>
+ <div
+ v-gl-tooltip.hover
+ :title="coverageState.text"
+ :class="[line.right.type, coverageState.class, { hll: isHighlighted }]"
+ class="diff-td line-coverage right-side"
+ ></div>
+ <div
+ :id="line.right.line_code"
+ :key="line.right.rich_text"
+ v-safe-html="line.right.rich_text"
+ :class="[
+ line.right.type,
+ {
+ hll: isHighlighted,
+ },
+ ]"
+ class="diff-td line_content with-coverage parallel right-side"
+ @mousedown="handleParallelLineMouseDown"
+ ></div>
+ </template>
+ <template v-else>
+ <div data-testid="rightEmptyCell" class="diff-td diff-line-num old_line empty-cell"></div>
+ <div class="diff-td diff-line-num old_line empty-cell"></div>
+ <div class="diff-td line-coverage right-side empty-cell"></div>
+ <div class="diff-td line_content with-coverage parallel right-side empty-cell"></div>
+ </template>
+ </div>
+ </div>
+</template>