Merge branch 'tz-mr-new-datastructure' into 'master'
Vue MR Page - Data structure update See merge request gitlab-org/gitlab-ce!21062
This commit is contained in:
commit
6d1b585034
|
|
@ -1,4 +1,4 @@
|
|||
/* eslint-disable object-shorthand, func-names, comma-dangle, no-else-return, quotes */
|
||||
/* eslint-disable object-shorthand, func-names, no-else-return */
|
||||
/* global CommentsStore */
|
||||
/* global ResolveService */
|
||||
|
||||
|
|
@ -25,44 +25,44 @@ const ResolveDiscussionBtn = Vue.extend({
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
showButton: function () {
|
||||
showButton: function() {
|
||||
if (this.discussion) {
|
||||
return this.discussion.isResolvable();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
isDiscussionResolved: function () {
|
||||
isDiscussionResolved: function() {
|
||||
if (this.discussion) {
|
||||
return this.discussion.isResolved();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
buttonText: function () {
|
||||
buttonText: function() {
|
||||
if (this.isDiscussionResolved) {
|
||||
return "Unresolve discussion";
|
||||
return 'Unresolve discussion';
|
||||
} else {
|
||||
return "Resolve discussion";
|
||||
return 'Resolve discussion';
|
||||
}
|
||||
},
|
||||
loading: function () {
|
||||
loading: function() {
|
||||
if (this.discussion) {
|
||||
return this.discussion.loading;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
created: function () {
|
||||
created: function() {
|
||||
CommentsStore.createDiscussion(this.discussionId, this.canResolve);
|
||||
|
||||
this.discussion = CommentsStore.state[this.discussionId];
|
||||
},
|
||||
methods: {
|
||||
resolve: function () {
|
||||
resolve: function() {
|
||||
ResolveService.toggleResolveForDiscussion(this.mergeRequestId, this.discussionId);
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -8,9 +8,7 @@ window.gl = window.gl || {};
|
|||
|
||||
class ResolveServiceClass {
|
||||
constructor(root) {
|
||||
this.noteResource = Vue.resource(
|
||||
`${root}/notes{/noteId}/resolve?html=true`,
|
||||
);
|
||||
this.noteResource = Vue.resource(`${root}/notes{/noteId}/resolve?html=true`);
|
||||
this.discussionResource = Vue.resource(
|
||||
`${root}/merge_requests{/mergeRequestId}/discussions{/discussionId}/resolve?html=true`,
|
||||
);
|
||||
|
|
@ -51,10 +49,7 @@ class ResolveServiceClass {
|
|||
discussion.updateHeadline(data);
|
||||
})
|
||||
.catch(
|
||||
() =>
|
||||
new Flash(
|
||||
'An error occurred when trying to resolve a discussion. Please try again.',
|
||||
),
|
||||
() => new Flash('An error occurred when trying to resolve a discussion. Please try again.'),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ export default {
|
|||
emailPatchPath: state => state.diffs.emailPatchPath,
|
||||
}),
|
||||
...mapGetters('diffs', ['isParallelView']),
|
||||
...mapGetters(['isNotesFetched']),
|
||||
...mapGetters(['isNotesFetched', 'discussionsStructuredByLineCode']),
|
||||
targetBranch() {
|
||||
return {
|
||||
branchName: this.targetBranchName,
|
||||
|
|
@ -112,13 +112,26 @@ export default {
|
|||
},
|
||||
created() {
|
||||
this.adjustView();
|
||||
eventHub.$once('fetchedNotesData', this.setDiscussions);
|
||||
},
|
||||
methods: {
|
||||
...mapActions('diffs', ['setBaseConfig', 'fetchDiffFiles', 'startRenderDiffsQueue']),
|
||||
...mapActions('diffs', [
|
||||
'setBaseConfig',
|
||||
'fetchDiffFiles',
|
||||
'startRenderDiffsQueue',
|
||||
'assignDiscussionsToDiff',
|
||||
]),
|
||||
|
||||
fetchData() {
|
||||
this.fetchDiffFiles()
|
||||
.then(() => {
|
||||
requestIdleCallback(this.startRenderDiffsQueue, { timeout: 1000 });
|
||||
requestIdleCallback(
|
||||
() => {
|
||||
this.setDiscussions();
|
||||
this.startRenderDiffsQueue();
|
||||
},
|
||||
{ timeout: 1000 },
|
||||
);
|
||||
})
|
||||
.catch(() => {
|
||||
createFlash(__('Something went wrong on our end. Please try again!'));
|
||||
|
|
@ -128,6 +141,16 @@ export default {
|
|||
eventHub.$emit('fetchNotesData');
|
||||
}
|
||||
},
|
||||
setDiscussions() {
|
||||
if (this.isNotesFetched) {
|
||||
requestIdleCallback(
|
||||
() => {
|
||||
this.assignDiscussionsToDiff(this.discussionsStructuredByLineCode);
|
||||
},
|
||||
{ timeout: 1000 },
|
||||
);
|
||||
}
|
||||
},
|
||||
adjustView() {
|
||||
if (this.shouldShow && this.isParallelView) {
|
||||
window.mrTabs.expandViewContainer();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
<script>
|
||||
import { mapActions } from 'vuex';
|
||||
import noteableDiscussion from '../../notes/components/noteable_discussion.vue';
|
||||
|
||||
export default {
|
||||
|
|
@ -11,6 +12,14 @@ export default {
|
|||
required: true,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
...mapActions('diffs', ['removeDiscussionsFromDiff']),
|
||||
deleteNoteHandler(discussion) {
|
||||
if (discussion.notes.length <= 1) {
|
||||
this.removeDiscussionsFromDiff(discussion);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
@ -31,6 +40,7 @@ export default {
|
|||
:render-diff-file="false"
|
||||
:always-expanded="true"
|
||||
:discussions-by-diff-order="true"
|
||||
@noteDeleted="deleteNoteHandler"
|
||||
/>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<script>
|
||||
import { mapActions } from 'vuex';
|
||||
import { mapActions, mapGetters } from 'vuex';
|
||||
import _ from 'underscore';
|
||||
import { __, sprintf } from '~/locale';
|
||||
import createFlash from '~/flash';
|
||||
|
|
@ -30,6 +30,7 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['isNotesFetched', 'discussionsStructuredByLineCode']),
|
||||
isCollapsed() {
|
||||
return this.file.collapsed || false;
|
||||
},
|
||||
|
|
@ -44,23 +45,23 @@ export default {
|
|||
);
|
||||
},
|
||||
showExpandMessage() {
|
||||
return this.isCollapsed && !this.isLoadingCollapsedDiff && !this.file.tooLarge;
|
||||
return (
|
||||
!this.isCollapsed &&
|
||||
!this.file.highlightedDiffLines &&
|
||||
!this.isLoadingCollapsedDiff &&
|
||||
!this.file.tooLarge &&
|
||||
this.file.text
|
||||
);
|
||||
},
|
||||
showLoadingIcon() {
|
||||
return this.isLoadingCollapsedDiff || (!this.file.renderIt && !this.isCollapsed);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
...mapActions('diffs', ['loadCollapsedDiff']),
|
||||
...mapActions('diffs', ['loadCollapsedDiff', 'assignDiscussionsToDiff']),
|
||||
handleToggle() {
|
||||
const { collapsed, highlightedDiffLines, parallelDiffLines } = this.file;
|
||||
|
||||
if (
|
||||
collapsed &&
|
||||
!highlightedDiffLines &&
|
||||
parallelDiffLines !== undefined &&
|
||||
!parallelDiffLines.length
|
||||
) {
|
||||
const { highlightedDiffLines, parallelDiffLines } = this.file;
|
||||
if (!highlightedDiffLines && parallelDiffLines !== undefined && !parallelDiffLines.length) {
|
||||
this.handleLoadCollapsedDiff();
|
||||
} else {
|
||||
this.file.collapsed = !this.file.collapsed;
|
||||
|
|
@ -76,6 +77,14 @@ export default {
|
|||
this.file.collapsed = false;
|
||||
this.file.renderIt = true;
|
||||
})
|
||||
.then(() => {
|
||||
requestIdleCallback(
|
||||
() => {
|
||||
this.assignDiscussionsToDiff(this.discussionsStructuredByLineCode);
|
||||
},
|
||||
{ timeout: 1000 },
|
||||
);
|
||||
})
|
||||
.catch(() => {
|
||||
this.isLoadingCollapsedDiff = false;
|
||||
createFlash(__('Something went wrong on our end. Please try again!'));
|
||||
|
|
@ -136,11 +145,11 @@ export default {
|
|||
:diff-file="file"
|
||||
/>
|
||||
<loading-icon
|
||||
v-else-if="showLoadingIcon"
|
||||
v-if="showLoadingIcon"
|
||||
class="diff-content loading"
|
||||
/>
|
||||
<div
|
||||
v-if="showExpandMessage"
|
||||
v-else-if="showExpandMessage"
|
||||
class="nothing-here-block diff-collapsed"
|
||||
>
|
||||
{{ __('This diff is collapsed.') }}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,10 @@ export default {
|
|||
Icon,
|
||||
},
|
||||
props: {
|
||||
line: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
fileHash: {
|
||||
type: String,
|
||||
required: true,
|
||||
|
|
@ -21,31 +25,16 @@ export default {
|
|||
type: String,
|
||||
required: true,
|
||||
},
|
||||
lineType: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
lineNumber: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: 0,
|
||||
},
|
||||
lineCode: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
linePosition: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
metaData: {
|
||||
type: Object,
|
||||
required: false,
|
||||
default: () => ({}),
|
||||
},
|
||||
showCommentButton: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
|
|
@ -76,11 +65,6 @@ export default {
|
|||
required: false,
|
||||
default: false,
|
||||
},
|
||||
discussions: {
|
||||
type: Array,
|
||||
required: false,
|
||||
default: () => [],
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
|
|
@ -89,7 +73,7 @@ export default {
|
|||
}),
|
||||
...mapGetters(['isLoggedIn']),
|
||||
lineHref() {
|
||||
return this.lineCode ? `#${this.lineCode}` : '#';
|
||||
return `#${this.line.lineCode || ''}`;
|
||||
},
|
||||
shouldShowCommentButton() {
|
||||
return (
|
||||
|
|
@ -103,20 +87,19 @@ export default {
|
|||
);
|
||||
},
|
||||
hasDiscussions() {
|
||||
return this.discussions.length > 0;
|
||||
return this.line.discussions && this.line.discussions.length > 0;
|
||||
},
|
||||
shouldShowAvatarsOnGutter() {
|
||||
if (!this.lineType && this.linePosition === LINE_POSITION_RIGHT) {
|
||||
if (!this.line.type && this.linePosition === LINE_POSITION_RIGHT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.showCommentButton && this.hasDiscussions;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
...mapActions('diffs', ['loadMoreLines', 'showCommentForm']),
|
||||
handleCommentButton() {
|
||||
this.showCommentForm({ lineCode: this.lineCode });
|
||||
this.showCommentForm({ lineCode: this.line.lineCode });
|
||||
},
|
||||
handleLoadMoreLines() {
|
||||
if (this.isRequesting) {
|
||||
|
|
@ -125,8 +108,8 @@ export default {
|
|||
|
||||
this.isRequesting = true;
|
||||
const endpoint = this.contextLinesPath;
|
||||
const oldLineNumber = this.metaData.oldPos || 0;
|
||||
const newLineNumber = this.metaData.newPos || 0;
|
||||
const oldLineNumber = this.line.metaData.oldPos || 0;
|
||||
const newLineNumber = this.line.metaData.newPos || 0;
|
||||
const offset = newLineNumber - oldLineNumber;
|
||||
const bottom = this.isBottom;
|
||||
const { fileHash } = this;
|
||||
|
|
@ -201,7 +184,7 @@ export default {
|
|||
</a>
|
||||
<diff-gutter-avatars
|
||||
v-if="shouldShowAvatarsOnGutter"
|
||||
:discussions="discussions"
|
||||
:discussions="line.discussions"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import noteForm from '../../notes/components/note_form.vue';
|
|||
import { getNoteFormData } from '../store/utils';
|
||||
import autosave from '../../notes/mixins/autosave';
|
||||
import { DIFF_NOTE_TYPE } from '../constants';
|
||||
import { reduceDiscussionsToLineCodes } from '../../notes/stores/utils';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
|
@ -52,7 +53,7 @@ export default {
|
|||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions('diffs', ['cancelCommentForm']),
|
||||
...mapActions('diffs', ['cancelCommentForm', 'assignDiscussionsToDiff']),
|
||||
...mapActions(['saveNote', 'refetchDiscussionById']),
|
||||
handleCancelCommentForm(shouldConfirm, isDirty) {
|
||||
if (shouldConfirm && isDirty) {
|
||||
|
|
@ -88,7 +89,10 @@ export default {
|
|||
const endpoint = this.getNotesDataByProp('discussionsPath');
|
||||
|
||||
this.refetchDiscussionById({ path: endpoint, discussionId: result.discussion_id })
|
||||
.then(() => {
|
||||
.then(selectedDiscussion => {
|
||||
const lineCodeDiscussions = reduceDiscussionsToLineCodes([selectedDiscussion]);
|
||||
this.assignDiscussionsToDiff(lineCodeDiscussions);
|
||||
|
||||
this.handleCancelCommentForm();
|
||||
})
|
||||
.catch(() => {
|
||||
|
|
|
|||
|
|
@ -11,8 +11,6 @@ import {
|
|||
LINE_HOVER_CLASS_NAME,
|
||||
LINE_UNFOLD_CLASS_NAME,
|
||||
INLINE_DIFF_VIEW_TYPE,
|
||||
LINE_POSITION_LEFT,
|
||||
LINE_POSITION_RIGHT,
|
||||
} from '../constants';
|
||||
|
||||
export default {
|
||||
|
|
@ -67,42 +65,24 @@ export default {
|
|||
required: false,
|
||||
default: false,
|
||||
},
|
||||
discussions: {
|
||||
type: Array,
|
||||
required: false,
|
||||
default: () => [],
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['isLoggedIn']),
|
||||
normalizedLine() {
|
||||
let normalizedLine;
|
||||
|
||||
if (this.diffViewType === INLINE_DIFF_VIEW_TYPE) {
|
||||
normalizedLine = this.line;
|
||||
} else if (this.linePosition === LINE_POSITION_LEFT) {
|
||||
normalizedLine = this.line.left;
|
||||
} else if (this.linePosition === LINE_POSITION_RIGHT) {
|
||||
normalizedLine = this.line.right;
|
||||
}
|
||||
|
||||
return normalizedLine;
|
||||
},
|
||||
isMatchLine() {
|
||||
return this.normalizedLine.type === MATCH_LINE_TYPE;
|
||||
return this.line.type === MATCH_LINE_TYPE;
|
||||
},
|
||||
isContextLine() {
|
||||
return this.normalizedLine.type === CONTEXT_LINE_TYPE;
|
||||
return this.line.type === CONTEXT_LINE_TYPE;
|
||||
},
|
||||
isMetaLine() {
|
||||
const { type } = this.normalizedLine;
|
||||
const { type } = this.line;
|
||||
|
||||
return (
|
||||
type === OLD_NO_NEW_LINE_TYPE || type === NEW_NO_NEW_LINE_TYPE || type === EMPTY_CELL_TYPE
|
||||
);
|
||||
},
|
||||
classNameMap() {
|
||||
const { type } = this.normalizedLine;
|
||||
const { type } = this.line;
|
||||
|
||||
return {
|
||||
[type]: type,
|
||||
|
|
@ -116,9 +96,9 @@ export default {
|
|||
};
|
||||
},
|
||||
lineNumber() {
|
||||
const { lineType, normalizedLine } = this;
|
||||
const { lineType } = this;
|
||||
|
||||
return lineType === OLD_LINE_TYPE ? normalizedLine.oldLine : normalizedLine.newLine;
|
||||
return lineType === OLD_LINE_TYPE ? this.line.oldLine : this.line.newLine;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -129,20 +109,17 @@ export default {
|
|||
:class="classNameMap"
|
||||
>
|
||||
<diff-line-gutter-content
|
||||
:line="line"
|
||||
:file-hash="fileHash"
|
||||
:context-lines-path="contextLinesPath"
|
||||
:line-type="normalizedLine.type"
|
||||
:line-code="normalizedLine.lineCode"
|
||||
:line-position="linePosition"
|
||||
:line-number="lineNumber"
|
||||
:meta-data="normalizedLine.metaData"
|
||||
:show-comment-button="showCommentButton"
|
||||
:is-hover="isHover"
|
||||
:is-bottom="isBottom"
|
||||
:is-match-line="isMatchLine"
|
||||
:is-context-line="isContentLine"
|
||||
:is-meta-line="isMetaLine"
|
||||
:discussions="discussions"
|
||||
/>
|
||||
</td>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -21,18 +21,13 @@ export default {
|
|||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
discussions: {
|
||||
type: Array,
|
||||
required: false,
|
||||
default: () => [],
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
diffLineCommentForms: state => state.diffs.diffLineCommentForms,
|
||||
}),
|
||||
className() {
|
||||
return this.discussions.length ? '' : 'js-temp-notes-holder';
|
||||
return this.line.discussions.length ? '' : 'js-temp-notes-holder';
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -49,8 +44,8 @@ export default {
|
|||
>
|
||||
<div class="content">
|
||||
<diff-discussions
|
||||
v-if="discussions.length"
|
||||
:discussions="discussions"
|
||||
v-if="line.discussions.length"
|
||||
:discussions="line.discussions"
|
||||
/>
|
||||
<diff-line-note-form
|
||||
v-if="diffLineCommentForms[line.lineCode]"
|
||||
|
|
|
|||
|
|
@ -33,11 +33,6 @@ export default {
|
|||
required: false,
|
||||
default: false,
|
||||
},
|
||||
discussions: {
|
||||
type: Array,
|
||||
required: false,
|
||||
default: () => [],
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
|
@ -94,7 +89,6 @@ export default {
|
|||
:is-bottom="isBottom"
|
||||
:is-hover="isHover"
|
||||
:show-comment-button="true"
|
||||
:discussions="discussions"
|
||||
class="diff-line-num old_line"
|
||||
/>
|
||||
<diff-table-cell
|
||||
|
|
@ -104,7 +98,6 @@ export default {
|
|||
:line-type="newLineType"
|
||||
:is-bottom="isBottom"
|
||||
:is-hover="isHover"
|
||||
:discussions="discussions"
|
||||
class="diff-line-num new_line"
|
||||
/>
|
||||
<td
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
import { mapGetters, mapState } from 'vuex';
|
||||
import inlineDiffTableRow from './inline_diff_table_row.vue';
|
||||
import inlineDiffCommentRow from './inline_diff_comment_row.vue';
|
||||
import { trimFirstCharOfLineContent } from '../store/utils';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
|
@ -20,29 +19,17 @@ export default {
|
|||
},
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('diffs', [
|
||||
'commitId',
|
||||
'shouldRenderInlineCommentRow',
|
||||
'singleDiscussionByLineCode',
|
||||
]),
|
||||
...mapGetters('diffs', ['commitId', 'shouldRenderInlineCommentRow']),
|
||||
...mapState({
|
||||
diffLineCommentForms: state => state.diffs.diffLineCommentForms,
|
||||
}),
|
||||
normalizedDiffLines() {
|
||||
return this.diffLines.map(line => (line.richText ? trimFirstCharOfLineContent(line) : line));
|
||||
},
|
||||
diffLinesLength() {
|
||||
return this.normalizedDiffLines.length;
|
||||
return this.diffLines.length;
|
||||
},
|
||||
userColorScheme() {
|
||||
return window.gon.user_color_scheme;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
discussionsList(line) {
|
||||
return line.lineCode !== undefined ? this.singleDiscussionByLineCode(line.lineCode) : [];
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
@ -53,7 +40,7 @@ export default {
|
|||
class="code diff-wrap-lines js-syntax-highlight text-file js-diff-inline-view">
|
||||
<tbody>
|
||||
<template
|
||||
v-for="(line, index) in normalizedDiffLines"
|
||||
v-for="(line, index) in diffLines"
|
||||
>
|
||||
<inline-diff-table-row
|
||||
:file-hash="diffFile.fileHash"
|
||||
|
|
@ -61,7 +48,6 @@ export default {
|
|||
:line="line"
|
||||
:is-bottom="index + 1 === diffLinesLength"
|
||||
:key="line.lineCode"
|
||||
:discussions="discussionsList(line)"
|
||||
/>
|
||||
<inline-diff-comment-row
|
||||
v-if="shouldRenderInlineCommentRow(line)"
|
||||
|
|
@ -69,7 +55,6 @@ export default {
|
|||
:line="line"
|
||||
:line-index="index"
|
||||
:key="index"
|
||||
:discussions="discussionsList(line)"
|
||||
/>
|
||||
</template>
|
||||
</tbody>
|
||||
|
|
|
|||
|
|
@ -21,51 +21,49 @@ export default {
|
|||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
leftDiscussions: {
|
||||
type: Array,
|
||||
required: false,
|
||||
default: () => [],
|
||||
},
|
||||
rightDiscussions: {
|
||||
type: Array,
|
||||
required: false,
|
||||
default: () => [],
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
diffLineCommentForms: state => state.diffs.diffLineCommentForms,
|
||||
}),
|
||||
leftLineCode() {
|
||||
return this.line.left.lineCode;
|
||||
return this.line.left && this.line.left.lineCode;
|
||||
},
|
||||
rightLineCode() {
|
||||
return this.line.right.lineCode;
|
||||
return this.line.right && this.line.right.lineCode;
|
||||
},
|
||||
hasExpandedDiscussionOnLeft() {
|
||||
const discussions = this.leftDiscussions;
|
||||
|
||||
return discussions ? discussions.every(discussion => discussion.expanded) : false;
|
||||
return this.line.left && this.line.left.discussions
|
||||
? this.line.left.discussions.every(discussion => discussion.expanded)
|
||||
: false;
|
||||
},
|
||||
hasExpandedDiscussionOnRight() {
|
||||
const discussions = this.rightDiscussions;
|
||||
|
||||
return discussions ? discussions.every(discussion => discussion.expanded) : false;
|
||||
return this.line.right && this.line.right.discussions
|
||||
? this.line.right.discussions.every(discussion => discussion.expanded)
|
||||
: false;
|
||||
},
|
||||
hasAnyExpandedDiscussion() {
|
||||
return this.hasExpandedDiscussionOnLeft || this.hasExpandedDiscussionOnRight;
|
||||
},
|
||||
shouldRenderDiscussionsOnLeft() {
|
||||
return this.leftDiscussions && this.hasExpandedDiscussionOnLeft;
|
||||
return this.line.left && this.line.left.discussions && this.hasExpandedDiscussionOnLeft;
|
||||
},
|
||||
shouldRenderDiscussionsOnRight() {
|
||||
return this.rightDiscussions && this.hasExpandedDiscussionOnRight && this.line.right.type;
|
||||
return (
|
||||
this.line.right &&
|
||||
this.line.right.discussions &&
|
||||
this.hasExpandedDiscussionOnRight &&
|
||||
this.line.right.type
|
||||
);
|
||||
},
|
||||
showRightSideCommentForm() {
|
||||
return this.line.right.type && this.diffLineCommentForms[this.rightLineCode];
|
||||
return (
|
||||
this.line.right && this.line.right.type && this.diffLineCommentForms[this.rightLineCode]
|
||||
);
|
||||
},
|
||||
className() {
|
||||
return this.leftDiscussions.length > 0 || this.rightDiscussions.length > 0
|
||||
return (this.left && this.line.left.discussions.length > 0) ||
|
||||
(this.right && this.line.right.discussions.length > 0)
|
||||
? ''
|
||||
: 'js-temp-notes-holder';
|
||||
},
|
||||
|
|
@ -85,8 +83,8 @@ export default {
|
|||
class="content"
|
||||
>
|
||||
<diff-discussions
|
||||
v-if="leftDiscussions.length"
|
||||
:discussions="leftDiscussions"
|
||||
v-if="line.left.discussions.length"
|
||||
:discussions="line.left.discussions"
|
||||
/>
|
||||
</div>
|
||||
<diff-line-note-form
|
||||
|
|
@ -104,8 +102,8 @@ export default {
|
|||
class="content"
|
||||
>
|
||||
<diff-discussions
|
||||
v-if="rightDiscussions.length"
|
||||
:discussions="rightDiscussions"
|
||||
v-if="line.right.discussions.length"
|
||||
:discussions="line.right.discussions"
|
||||
/>
|
||||
</div>
|
||||
<diff-line-note-form
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
<script>
|
||||
import $ from 'jquery';
|
||||
import { mapGetters } from 'vuex';
|
||||
import DiffTableCell from './diff_table_cell.vue';
|
||||
import {
|
||||
NEW_LINE_TYPE,
|
||||
|
|
@ -10,8 +9,7 @@ import {
|
|||
OLD_NO_NEW_LINE_TYPE,
|
||||
PARALLEL_DIFF_VIEW_TYPE,
|
||||
NEW_NO_NEW_LINE_TYPE,
|
||||
LINE_POSITION_LEFT,
|
||||
LINE_POSITION_RIGHT,
|
||||
EMPTY_CELL_TYPE,
|
||||
} from '../constants';
|
||||
|
||||
export default {
|
||||
|
|
@ -36,16 +34,6 @@ export default {
|
|||
required: false,
|
||||
default: false,
|
||||
},
|
||||
leftDiscussions: {
|
||||
type: Array,
|
||||
required: false,
|
||||
default: () => [],
|
||||
},
|
||||
rightDiscussions: {
|
||||
type: Array,
|
||||
required: false,
|
||||
default: () => [],
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
|
@ -54,29 +42,26 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('diffs', ['isParallelView']),
|
||||
isContextLine() {
|
||||
return this.line.left.type === CONTEXT_LINE_TYPE;
|
||||
return this.line.left && this.line.left.type === CONTEXT_LINE_TYPE;
|
||||
},
|
||||
classNameMap() {
|
||||
return {
|
||||
[CONTEXT_LINE_CLASS_NAME]: this.isContextLine,
|
||||
[PARALLEL_DIFF_VIEW_TYPE]: this.isParallelView,
|
||||
[PARALLEL_DIFF_VIEW_TYPE]: true,
|
||||
};
|
||||
},
|
||||
parallelViewLeftLineType() {
|
||||
if (this.line.right.type === NEW_NO_NEW_LINE_TYPE) {
|
||||
if (this.line.right && this.line.right.type === NEW_NO_NEW_LINE_TYPE) {
|
||||
return OLD_NO_NEW_LINE_TYPE;
|
||||
}
|
||||
|
||||
return this.line.left.type;
|
||||
return this.line.left ? this.line.left.type : EMPTY_CELL_TYPE;
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.newLineType = NEW_LINE_TYPE;
|
||||
this.oldLineType = OLD_LINE_TYPE;
|
||||
this.linePositionLeft = LINE_POSITION_LEFT;
|
||||
this.linePositionRight = LINE_POSITION_RIGHT;
|
||||
this.parallelDiffViewType = PARALLEL_DIFF_VIEW_TYPE;
|
||||
},
|
||||
methods: {
|
||||
|
|
@ -116,47 +101,57 @@ export default {
|
|||
@mouseover="handleMouseMove"
|
||||
@mouseout="handleMouseMove"
|
||||
>
|
||||
<diff-table-cell
|
||||
:file-hash="fileHash"
|
||||
:context-lines-path="contextLinesPath"
|
||||
:line="line"
|
||||
:line-type="oldLineType"
|
||||
:line-position="linePositionLeft"
|
||||
:is-bottom="isBottom"
|
||||
:is-hover="isLeftHover"
|
||||
:show-comment-button="true"
|
||||
:diff-view-type="parallelDiffViewType"
|
||||
:discussions="leftDiscussions"
|
||||
class="diff-line-num old_line"
|
||||
/>
|
||||
<td
|
||||
:id="line.left.lineCode"
|
||||
:class="parallelViewLeftLineType"
|
||||
class="line_content parallel left-side"
|
||||
@mousedown.native="handleParallelLineMouseDown"
|
||||
v-html="line.left.richText"
|
||||
>
|
||||
</td>
|
||||
<diff-table-cell
|
||||
:file-hash="fileHash"
|
||||
:context-lines-path="contextLinesPath"
|
||||
:line="line"
|
||||
:line-type="newLineType"
|
||||
:line-position="linePositionRight"
|
||||
:is-bottom="isBottom"
|
||||
:is-hover="isRightHover"
|
||||
:show-comment-button="true"
|
||||
:diff-view-type="parallelDiffViewType"
|
||||
:discussions="rightDiscussions"
|
||||
class="diff-line-num new_line"
|
||||
/>
|
||||
<td
|
||||
:id="line.right.lineCode"
|
||||
:class="line.right.type"
|
||||
class="line_content parallel right-side"
|
||||
@mousedown.native="handleParallelLineMouseDown"
|
||||
v-html="line.right.richText"
|
||||
>
|
||||
</td>
|
||||
<template v-if="line.left">
|
||||
<diff-table-cell
|
||||
:file-hash="fileHash"
|
||||
:context-lines-path="contextLinesPath"
|
||||
:line="line.left"
|
||||
:line-type="oldLineType"
|
||||
:is-bottom="isBottom"
|
||||
:is-hover="isLeftHover"
|
||||
:show-comment-button="true"
|
||||
:diff-view-type="parallelDiffViewType"
|
||||
line-position="left"
|
||||
class="diff-line-num old_line"
|
||||
/>
|
||||
<td
|
||||
:id="line.left.lineCode"
|
||||
:class="parallelViewLeftLineType"
|
||||
class="line_content parallel left-side"
|
||||
@mousedown.native="handleParallelLineMouseDown"
|
||||
v-html="line.left.richText"
|
||||
>
|
||||
</td>
|
||||
</template>
|
||||
<template v-else>
|
||||
<td class="diff-line-num old_line empty-cell"></td>
|
||||
<td class="line_content parallel left-side empty-cell"></td>
|
||||
</template>
|
||||
<template v-if="line.right">
|
||||
<diff-table-cell
|
||||
:file-hash="fileHash"
|
||||
:context-lines-path="contextLinesPath"
|
||||
:line="line.right"
|
||||
:line-type="newLineType"
|
||||
:is-bottom="isBottom"
|
||||
:is-hover="isRightHover"
|
||||
:show-comment-button="true"
|
||||
:diff-view-type="parallelDiffViewType"
|
||||
line-position="right"
|
||||
class="diff-line-num new_line"
|
||||
/>
|
||||
<td
|
||||
:id="line.right.lineCode"
|
||||
:class="line.right.type"
|
||||
class="line_content parallel right-side"
|
||||
@mousedown.native="handleParallelLineMouseDown"
|
||||
v-html="line.right.richText"
|
||||
>
|
||||
</td>
|
||||
</template>
|
||||
<template v-else>
|
||||
<td class="diff-line-num old_line empty-cell"></td>
|
||||
<td class="line_content parallel right-side empty-cell"></td>
|
||||
</template>
|
||||
</tr>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
import { mapState, mapGetters } from 'vuex';
|
||||
import parallelDiffTableRow from './parallel_diff_table_row.vue';
|
||||
import parallelDiffCommentRow from './parallel_diff_comment_row.vue';
|
||||
import { EMPTY_CELL_TYPE } from '../constants';
|
||||
import { trimFirstCharOfLineContent } from '../store/utils';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
|
@ -21,46 +19,17 @@ export default {
|
|||
},
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('diffs', [
|
||||
'commitId',
|
||||
'singleDiscussionByLineCode',
|
||||
'shouldRenderParallelCommentRow',
|
||||
]),
|
||||
...mapGetters('diffs', ['commitId', 'shouldRenderParallelCommentRow']),
|
||||
...mapState({
|
||||
diffLineCommentForms: state => state.diffs.diffLineCommentForms,
|
||||
}),
|
||||
parallelDiffLines() {
|
||||
return this.diffLines.map(line => {
|
||||
const parallelLine = Object.assign({}, line);
|
||||
|
||||
if (line.left) {
|
||||
parallelLine.left = trimFirstCharOfLineContent(line.left);
|
||||
} else {
|
||||
parallelLine.left = { type: EMPTY_CELL_TYPE };
|
||||
}
|
||||
|
||||
if (line.right) {
|
||||
parallelLine.right = trimFirstCharOfLineContent(line.right);
|
||||
} else {
|
||||
parallelLine.right = { type: EMPTY_CELL_TYPE };
|
||||
}
|
||||
|
||||
return parallelLine;
|
||||
});
|
||||
},
|
||||
diffLinesLength() {
|
||||
return this.parallelDiffLines.length;
|
||||
return this.diffLines.length;
|
||||
},
|
||||
userColorScheme() {
|
||||
return window.gon.user_color_scheme;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
discussionsByLine(line, leftOrRight) {
|
||||
return line[leftOrRight] && line[leftOrRight].lineCode !== undefined ?
|
||||
this.singleDiscussionByLineCode(line[leftOrRight].lineCode) : [];
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
@ -73,7 +42,7 @@ export default {
|
|||
<table>
|
||||
<tbody>
|
||||
<template
|
||||
v-for="(line, index) in parallelDiffLines"
|
||||
v-for="(line, index) in diffLines"
|
||||
>
|
||||
<parallel-diff-table-row
|
||||
:file-hash="diffFile.fileHash"
|
||||
|
|
@ -81,8 +50,6 @@ export default {
|
|||
:line="line"
|
||||
:is-bottom="index + 1 === diffLinesLength"
|
||||
:key="index"
|
||||
:left-discussions="discussionsByLine(line, 'left')"
|
||||
:right-discussions="discussionsByLine(line, 'right')"
|
||||
/>
|
||||
<parallel-diff-comment-row
|
||||
v-if="shouldRenderParallelCommentRow(line)"
|
||||
|
|
@ -90,8 +57,6 @@ export default {
|
|||
:line="line"
|
||||
:diff-file-hash="diffFile.fileHash"
|
||||
:line-index="index"
|
||||
:left-discussions="discussionsByLine(line, 'left')"
|
||||
:right-discussions="discussionsByLine(line, 'right')"
|
||||
/>
|
||||
</template>
|
||||
</tbody>
|
||||
|
|
|
|||
|
|
@ -29,25 +29,47 @@ export const fetchDiffFiles = ({ state, commit }) => {
|
|||
.then(handleLocationHash);
|
||||
};
|
||||
|
||||
export const startRenderDiffsQueue = ({ state, commit }) => {
|
||||
const checkItem = () => {
|
||||
const nextFile = state.diffFiles.find(
|
||||
file => !file.renderIt && (!file.collapsed || !file.text),
|
||||
);
|
||||
if (nextFile) {
|
||||
requestAnimationFrame(() => {
|
||||
commit(types.RENDER_FILE, nextFile);
|
||||
});
|
||||
requestIdleCallback(
|
||||
() => {
|
||||
checkItem();
|
||||
},
|
||||
{ timeout: 1000 },
|
||||
);
|
||||
// This is adding line discussions to the actual lines in the diff tree
|
||||
// once for parallel and once for inline mode
|
||||
export const assignDiscussionsToDiff = ({ commit }, allLineDiscussions) => {
|
||||
Object.values(allLineDiscussions).forEach(discussions => {
|
||||
if (discussions.length > 0) {
|
||||
const { fileHash } = discussions[0];
|
||||
commit(types.SET_LINE_DISCUSSIONS_FOR_FILE, { fileHash, discussions });
|
||||
}
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
checkItem();
|
||||
export const removeDiscussionsFromDiff = ({ commit }, removeDiscussion) => {
|
||||
const { fileHash, line_code } = removeDiscussion;
|
||||
commit(types.REMOVE_LINE_DISCUSSIONS_FOR_FILE, { fileHash, lineCode: line_code });
|
||||
};
|
||||
|
||||
export const startRenderDiffsQueue = ({ state, commit }) => {
|
||||
const checkItem = () =>
|
||||
new Promise(resolve => {
|
||||
const nextFile = state.diffFiles.find(
|
||||
file => !file.renderIt && (!file.collapsed || !file.text),
|
||||
);
|
||||
|
||||
if (nextFile) {
|
||||
requestAnimationFrame(() => {
|
||||
commit(types.RENDER_FILE, nextFile);
|
||||
});
|
||||
requestIdleCallback(
|
||||
() => {
|
||||
checkItem()
|
||||
.then(resolve)
|
||||
.catch(() => {});
|
||||
},
|
||||
{ timeout: 1000 },
|
||||
);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
|
||||
return checkItem();
|
||||
};
|
||||
|
||||
export const setInlineDiffViewType = ({ commit }) => {
|
||||
|
|
|
|||
|
|
@ -17,7 +17,10 @@ export const commitId = state => (state.commit && state.commit.id ? state.commit
|
|||
export const diffHasAllExpandedDiscussions = (state, getters) => diff => {
|
||||
const discussions = getters.getDiffFileDiscussions(diff);
|
||||
|
||||
return (discussions.length && discussions.every(discussion => discussion.expanded)) || false;
|
||||
return (
|
||||
(discussions && discussions.length && discussions.every(discussion => discussion.expanded)) ||
|
||||
false
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -28,7 +31,10 @@ export const diffHasAllExpandedDiscussions = (state, getters) => diff => {
|
|||
export const diffHasAllCollpasedDiscussions = (state, getters) => diff => {
|
||||
const discussions = getters.getDiffFileDiscussions(diff);
|
||||
|
||||
return (discussions.length && discussions.every(discussion => !discussion.expanded)) || false;
|
||||
return (
|
||||
(discussions && discussions.length && discussions.every(discussion => !discussion.expanded)) ||
|
||||
false
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -40,7 +46,9 @@ export const diffHasExpandedDiscussions = (state, getters) => diff => {
|
|||
const discussions = getters.getDiffFileDiscussions(diff);
|
||||
|
||||
return (
|
||||
(discussions.length && discussions.find(discussion => discussion.expanded) !== undefined) ||
|
||||
(discussions &&
|
||||
discussions.length &&
|
||||
discussions.find(discussion => discussion.expanded) !== undefined) ||
|
||||
false
|
||||
);
|
||||
};
|
||||
|
|
@ -64,45 +72,38 @@ export const getDiffFileDiscussions = (state, getters, rootState, rootGetters) =
|
|||
discussion.diff_discussion && _.isEqual(discussion.diff_file.file_hash, diff.fileHash),
|
||||
) || [];
|
||||
|
||||
export const singleDiscussionByLineCode = (state, getters, rootState, rootGetters) => lineCode => {
|
||||
if (!lineCode || lineCode === undefined) return [];
|
||||
const discussions = rootGetters.discussionsByLineCode;
|
||||
return discussions[lineCode] || [];
|
||||
};
|
||||
export const shouldRenderParallelCommentRow = state => line => {
|
||||
const hasDiscussion =
|
||||
(line.left && line.left.discussions && line.left.discussions.length) ||
|
||||
(line.right && line.right.discussions && line.right.discussions.length);
|
||||
|
||||
export const shouldRenderParallelCommentRow = (state, getters) => line => {
|
||||
const leftLineCode = line.left.lineCode;
|
||||
const rightLineCode = line.right.lineCode;
|
||||
const leftDiscussions = getters.singleDiscussionByLineCode(leftLineCode);
|
||||
const rightDiscussions = getters.singleDiscussionByLineCode(rightLineCode);
|
||||
const hasDiscussion = leftDiscussions.length || rightDiscussions.length;
|
||||
|
||||
const hasExpandedDiscussionOnLeft = leftDiscussions.length
|
||||
? leftDiscussions.every(discussion => discussion.expanded)
|
||||
: false;
|
||||
const hasExpandedDiscussionOnRight = rightDiscussions.length
|
||||
? rightDiscussions.every(discussion => discussion.expanded)
|
||||
: false;
|
||||
const hasExpandedDiscussionOnLeft =
|
||||
line.left && line.left.discussions && line.left.discussions.length
|
||||
? line.left.discussions.every(discussion => discussion.expanded)
|
||||
: false;
|
||||
const hasExpandedDiscussionOnRight =
|
||||
line.right && line.right.discussions && line.right.discussions.length
|
||||
? line.right.discussions.every(discussion => discussion.expanded)
|
||||
: false;
|
||||
|
||||
if (hasDiscussion && (hasExpandedDiscussionOnLeft || hasExpandedDiscussionOnRight)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const hasCommentFormOnLeft = state.diffLineCommentForms[leftLineCode];
|
||||
const hasCommentFormOnRight = state.diffLineCommentForms[rightLineCode];
|
||||
const hasCommentFormOnLeft = line.left && state.diffLineCommentForms[line.left.lineCode];
|
||||
const hasCommentFormOnRight = line.right && state.diffLineCommentForms[line.right.lineCode];
|
||||
|
||||
return hasCommentFormOnLeft || hasCommentFormOnRight;
|
||||
};
|
||||
|
||||
export const shouldRenderInlineCommentRow = (state, getters) => line => {
|
||||
export const shouldRenderInlineCommentRow = state => line => {
|
||||
if (state.diffLineCommentForms[line.lineCode]) return true;
|
||||
|
||||
const lineDiscussions = getters.singleDiscussionByLineCode(line.lineCode);
|
||||
if (lineDiscussions.length === 0) {
|
||||
if (!line.discussions || line.discussions.length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return lineDiscussions.every(discussion => discussion.expanded);
|
||||
return line.discussions.every(discussion => discussion.expanded);
|
||||
};
|
||||
|
||||
// prevent babel-plugin-rewire from generating an invalid default during karma∂ tests
|
||||
|
|
|
|||
|
|
@ -9,3 +9,5 @@ export const ADD_CONTEXT_LINES = 'ADD_CONTEXT_LINES';
|
|||
export const ADD_COLLAPSED_DIFFS = 'ADD_COLLAPSED_DIFFS';
|
||||
export const EXPAND_ALL_FILES = 'EXPAND_ALL_FILES';
|
||||
export const RENDER_FILE = 'RENDER_FILE';
|
||||
export const SET_LINE_DISCUSSIONS_FOR_FILE = 'SET_LINE_DISCUSSIONS_FOR_FILE';
|
||||
export const REMOVE_LINE_DISCUSSIONS_FOR_FILE = 'REMOVE_LINE_DISCUSSIONS_FOR_FILE';
|
||||
|
|
|
|||
|
|
@ -1,8 +1,12 @@
|
|||
import Vue from 'vue';
|
||||
import _ from 'underscore';
|
||||
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
|
||||
import { findDiffFile, addLineReferences, removeMatchLine, addContextLines } from './utils';
|
||||
import { LINES_TO_BE_RENDERED_DIRECTLY, MAX_LINES_TO_BE_RENDERED } from '../constants';
|
||||
import {
|
||||
findDiffFile,
|
||||
addLineReferences,
|
||||
removeMatchLine,
|
||||
addContextLines,
|
||||
prepareDiffData,
|
||||
} from './utils';
|
||||
import * as types from './mutation_types';
|
||||
|
||||
export default {
|
||||
|
|
@ -17,38 +21,7 @@ export default {
|
|||
|
||||
[types.SET_DIFF_DATA](state, data) {
|
||||
const diffData = convertObjectPropsToCamelCase(data, { deep: true });
|
||||
let showingLines = 0;
|
||||
const filesLength = diffData.diffFiles.length;
|
||||
let i;
|
||||
for (i = 0; i < filesLength; i += 1) {
|
||||
const file = diffData.diffFiles[i];
|
||||
if (file.parallelDiffLines) {
|
||||
const linesLength = file.parallelDiffLines.length;
|
||||
let u = 0;
|
||||
for (u = 0; u < linesLength; u += 1) {
|
||||
const line = file.parallelDiffLines[u];
|
||||
if (line.left) delete line.left.text;
|
||||
if (line.right) delete line.right.text;
|
||||
}
|
||||
}
|
||||
|
||||
if (file.highlightedDiffLines) {
|
||||
const linesLength = file.highlightedDiffLines.length;
|
||||
let u;
|
||||
for (u = 0; u < linesLength; u += 1) {
|
||||
const line = file.highlightedDiffLines[u];
|
||||
delete line.text;
|
||||
}
|
||||
}
|
||||
|
||||
if (file.highlightedDiffLines) {
|
||||
showingLines += file.parallelDiffLines.length;
|
||||
}
|
||||
Object.assign(file, {
|
||||
renderIt: showingLines < LINES_TO_BE_RENDERED_DIRECTLY,
|
||||
collapsed: file.text && showingLines > MAX_LINES_TO_BE_RENDERED,
|
||||
});
|
||||
}
|
||||
prepareDiffData(diffData);
|
||||
|
||||
Object.assign(state, {
|
||||
...diffData,
|
||||
|
|
@ -98,12 +71,10 @@ export default {
|
|||
|
||||
[types.ADD_COLLAPSED_DIFFS](state, { file, data }) {
|
||||
const normalizedData = convertObjectPropsToCamelCase(data, { deep: true });
|
||||
prepareDiffData(normalizedData);
|
||||
const [newFileData] = normalizedData.diffFiles.filter(f => f.fileHash === file.fileHash);
|
||||
|
||||
if (newFileData) {
|
||||
const index = _.findIndex(state.diffFiles, f => f.fileHash === file.fileHash);
|
||||
state.diffFiles.splice(index, 1, newFileData);
|
||||
}
|
||||
const selectedFile = state.diffFiles.find(f => f.fileHash === file.fileHash);
|
||||
Object.assign(selectedFile, { ...newFileData });
|
||||
},
|
||||
|
||||
[types.EXPAND_ALL_FILES](state) {
|
||||
|
|
@ -112,4 +83,69 @@ export default {
|
|||
collapsed: false,
|
||||
}));
|
||||
},
|
||||
|
||||
[types.SET_LINE_DISCUSSIONS_FOR_FILE](state, { fileHash, discussions }) {
|
||||
const selectedFile = state.diffFiles.find(f => f.fileHash === fileHash);
|
||||
if (selectedFile) {
|
||||
const firstDiscussion = discussions[0];
|
||||
const targetLine = selectedFile.parallelDiffLines.find(
|
||||
line =>
|
||||
(line.left && line.left.lineCode === firstDiscussion.line_code) ||
|
||||
(line.right && line.right.lineCode === firstDiscussion.line_code),
|
||||
);
|
||||
if (targetLine) {
|
||||
if (targetLine.left && targetLine.left.lineCode === firstDiscussion.line_code) {
|
||||
Object.assign(targetLine.left, {
|
||||
discussions,
|
||||
});
|
||||
} else {
|
||||
Object.assign(targetLine.right, {
|
||||
discussions,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedFile.highlightedDiffLines) {
|
||||
const targetInlineLine = selectedFile.highlightedDiffLines.find(
|
||||
line => line.lineCode === firstDiscussion.line_code,
|
||||
);
|
||||
|
||||
if (targetInlineLine) {
|
||||
Object.assign(targetInlineLine, {
|
||||
discussions,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
[types.REMOVE_LINE_DISCUSSIONS_FOR_FILE](state, { fileHash, lineCode }) {
|
||||
const selectedFile = state.diffFiles.find(f => f.fileHash === fileHash);
|
||||
if (selectedFile) {
|
||||
const targetLine = selectedFile.parallelDiffLines.find(
|
||||
line =>
|
||||
(line.left && line.left.lineCode === lineCode) ||
|
||||
(line.right && line.right.lineCode === lineCode),
|
||||
);
|
||||
if (targetLine) {
|
||||
const side = targetLine.left && targetLine.left.lineCode === lineCode ? 'left' : 'right';
|
||||
|
||||
Object.assign(targetLine[side], {
|
||||
discussions: [],
|
||||
});
|
||||
}
|
||||
|
||||
if (selectedFile.highlightedDiffLines) {
|
||||
const targetInlineLine = selectedFile.highlightedDiffLines.find(
|
||||
line => line.lineCode === lineCode,
|
||||
);
|
||||
|
||||
if (targetInlineLine) {
|
||||
Object.assign(targetInlineLine, {
|
||||
discussions: [],
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ import {
|
|||
NEW_LINE_TYPE,
|
||||
OLD_LINE_TYPE,
|
||||
MATCH_LINE_TYPE,
|
||||
LINES_TO_BE_RENDERED_DIRECTLY,
|
||||
MAX_LINES_TO_BE_RENDERED,
|
||||
} from '../constants';
|
||||
|
||||
export function findDiffFile(files, hash) {
|
||||
|
|
@ -161,6 +163,11 @@ export function addContextLines(options) {
|
|||
* @returns {Object}
|
||||
*/
|
||||
export function trimFirstCharOfLineContent(line = {}) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
delete line.text;
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
line.discussions = [];
|
||||
|
||||
const parsedLine = Object.assign({}, line);
|
||||
|
||||
if (line.richText) {
|
||||
|
|
@ -174,6 +181,42 @@ export function trimFirstCharOfLineContent(line = {}) {
|
|||
return parsedLine;
|
||||
}
|
||||
|
||||
// This prepares and optimizes the incoming diff data from the server
|
||||
// by setting up incremental rendering and removing unneeded data
|
||||
export function prepareDiffData(diffData) {
|
||||
const filesLength = diffData.diffFiles.length;
|
||||
let showingLines = 0;
|
||||
for (let i = 0; i < filesLength; i += 1) {
|
||||
const file = diffData.diffFiles[i];
|
||||
|
||||
if (file.parallelDiffLines) {
|
||||
const linesLength = file.parallelDiffLines.length;
|
||||
for (let u = 0; u < linesLength; u += 1) {
|
||||
const line = file.parallelDiffLines[u];
|
||||
if (line.left) {
|
||||
line.left = trimFirstCharOfLineContent(line.left);
|
||||
}
|
||||
if (line.right) {
|
||||
line.right = trimFirstCharOfLineContent(line.right);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (file.highlightedDiffLines) {
|
||||
const linesLength = file.highlightedDiffLines.length;
|
||||
for (let u = 0; u < linesLength; u += 1) {
|
||||
trimFirstCharOfLineContent(file.highlightedDiffLines[u]);
|
||||
}
|
||||
showingLines += file.parallelDiffLines.length;
|
||||
}
|
||||
|
||||
Object.assign(file, {
|
||||
renderIt: showingLines < LINES_TO_BE_RENDERED_DIRECTLY,
|
||||
collapsed: file.text && showingLines > MAX_LINES_TO_BE_RENDERED,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function getDiffRefsByLineCode(diffFiles) {
|
||||
return diffFiles.reduce((acc, diffFile) => {
|
||||
const { baseSha, headSha, startSha } = diffFile.diffRefs;
|
||||
|
|
|
|||
|
|
@ -154,7 +154,11 @@ export default class Notes {
|
|||
this.$wrapperEl.on('click', '.system-note-commit-list-toggler', this.toggleCommitList);
|
||||
|
||||
this.$wrapperEl.on('click', '.js-toggle-lazy-diff', this.loadLazyDiff);
|
||||
this.$wrapperEl.on('click', '.js-toggle-lazy-diff-retry-button', this.onClickRetryLazyLoad.bind(this));
|
||||
this.$wrapperEl.on(
|
||||
'click',
|
||||
'.js-toggle-lazy-diff-retry-button',
|
||||
this.onClickRetryLazyLoad.bind(this),
|
||||
);
|
||||
|
||||
// fetch notes when tab becomes visible
|
||||
this.$wrapperEl.on('visibilitychange', this.visibilityChange);
|
||||
|
|
@ -252,9 +256,7 @@ export default class Notes {
|
|||
discussionNoteForm = $textarea.closest('.js-discussion-note-form');
|
||||
if (discussionNoteForm.length) {
|
||||
if ($textarea.val() !== '') {
|
||||
if (
|
||||
!window.confirm('Are you sure you want to cancel creating this comment?')
|
||||
) {
|
||||
if (!window.confirm('Are you sure you want to cancel creating this comment?')) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -266,9 +268,7 @@ export default class Notes {
|
|||
originalText = $textarea.closest('form').data('originalNote');
|
||||
newText = $textarea.val();
|
||||
if (originalText !== newText) {
|
||||
if (
|
||||
!window.confirm('Are you sure you want to cancel editing this comment?')
|
||||
) {
|
||||
if (!window.confirm('Are you sure you want to cancel editing this comment?')) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -1316,8 +1316,7 @@ export default class Notes {
|
|||
|
||||
$retryButton.prop('disabled', true);
|
||||
|
||||
return this.loadLazyDiff(e)
|
||||
.then(() => {
|
||||
return this.loadLazyDiff(e).then(() => {
|
||||
$retryButton.prop('disabled', false);
|
||||
});
|
||||
}
|
||||
|
|
@ -1343,18 +1342,18 @@ export default class Notes {
|
|||
*/
|
||||
if (url) {
|
||||
return axios
|
||||
.get(url)
|
||||
.then(({ data }) => {
|
||||
// Reset state in case last request returned error
|
||||
$successContainer.removeClass('hidden');
|
||||
$errorContainer.addClass('hidden');
|
||||
.get(url)
|
||||
.then(({ data }) => {
|
||||
// Reset state in case last request returned error
|
||||
$successContainer.removeClass('hidden');
|
||||
$errorContainer.addClass('hidden');
|
||||
|
||||
Notes.renderDiffContent($container, data);
|
||||
})
|
||||
.catch(() => {
|
||||
$successContainer.addClass('hidden');
|
||||
$errorContainer.removeClass('hidden');
|
||||
});
|
||||
Notes.renderDiffContent($container, data);
|
||||
})
|
||||
.catch(() => {
|
||||
$successContainer.addClass('hidden');
|
||||
$errorContainer.removeClass('hidden');
|
||||
});
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
|
@ -1545,12 +1544,8 @@ export default class Notes {
|
|||
<div class="note-header">
|
||||
<div class="note-header-info">
|
||||
<a href="/${_.escape(currentUsername)}">
|
||||
<span class="d-none d-sm-inline-block">${_.escape(
|
||||
currentUsername,
|
||||
)}</span>
|
||||
<span class="note-headline-light">${_.escape(
|
||||
currentUsername,
|
||||
)}</span>
|
||||
<span class="d-none d-sm-inline-block">${_.escape(currentUsername)}</span>
|
||||
<span class="note-headline-light">${_.escape(currentUsername)}</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1565,9 +1560,7 @@ export default class Notes {
|
|||
);
|
||||
|
||||
$tempNote.find('.d-none.d-sm-inline-block').text(_.escape(currentUserFullname));
|
||||
$tempNote
|
||||
.find('.note-headline-light')
|
||||
.text(`@${_.escape(currentUsername)}`);
|
||||
$tempNote.find('.note-headline-light').text(`@${_.escape(currentUsername)}`);
|
||||
|
||||
return $tempNote;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -137,8 +137,10 @@ export default {
|
|||
return this.unresolvedDiscussions.length > 1;
|
||||
},
|
||||
showJumpToNextDiscussion() {
|
||||
return this.hasMultipleUnresolvedDiscussions &&
|
||||
!this.isLastUnresolvedDiscussion(this.discussion.id, this.discussionsByDiffOrder);
|
||||
return (
|
||||
this.hasMultipleUnresolvedDiscussions &&
|
||||
!this.isLastUnresolvedDiscussion(this.discussion.id, this.discussionsByDiffOrder)
|
||||
);
|
||||
},
|
||||
shouldRenderDiffs() {
|
||||
const { diffDiscussion, diffFile } = this.transformedDiscussion;
|
||||
|
|
@ -256,11 +258,16 @@ Please check your network connection and try again.`;
|
|||
});
|
||||
},
|
||||
jumpToNextDiscussion() {
|
||||
const nextId =
|
||||
this.nextUnresolvedDiscussionId(this.discussion.id, this.discussionsByDiffOrder);
|
||||
const nextId = this.nextUnresolvedDiscussionId(
|
||||
this.discussion.id,
|
||||
this.discussionsByDiffOrder,
|
||||
);
|
||||
|
||||
this.jumpToDiscussion(nextId);
|
||||
},
|
||||
deleteNoteHandler(note) {
|
||||
this.$emit('noteDeleted', this.discussion, note);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
@ -270,6 +277,7 @@ Please check your network connection and try again.`;
|
|||
<div class="timeline-entry-inner">
|
||||
<div class="timeline-icon">
|
||||
<user-avatar-link
|
||||
v-if="author"
|
||||
:link-href="author.path"
|
||||
:img-src="author.avatar_url"
|
||||
:img-alt="author.name"
|
||||
|
|
@ -344,6 +352,7 @@ Please check your network connection and try again.`;
|
|||
:is="componentName(note)"
|
||||
:note="componentData(note)"
|
||||
:key="note.id"
|
||||
@handleDeleteNote="deleteNoteHandler"
|
||||
/>
|
||||
</ul>
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@ export default {
|
|||
// eslint-disable-next-line no-alert
|
||||
if (window.confirm('Are you sure you want to delete this comment?')) {
|
||||
this.isDeleting = true;
|
||||
this.$emit('handleDeleteNote', this.note);
|
||||
|
||||
this.deleteNote(this.note)
|
||||
.then(() => {
|
||||
|
|
|
|||
|
|
@ -138,6 +138,7 @@ export default {
|
|||
.then(() => {
|
||||
this.isLoading = false;
|
||||
this.setNotesFetchedState(true);
|
||||
eventHub.$emit('fetchedNotesData');
|
||||
})
|
||||
.then(() => this.$nextTick())
|
||||
.then(() => this.checkLocationHash())
|
||||
|
|
|
|||
|
|
@ -43,14 +43,23 @@ export const fetchDiscussions = ({ commit }, path) =>
|
|||
commit(types.SET_INITIAL_DISCUSSIONS, discussions);
|
||||
});
|
||||
|
||||
export const refetchDiscussionById = ({ commit }, { path, discussionId }) =>
|
||||
service
|
||||
.fetchDiscussions(path)
|
||||
.then(res => res.json())
|
||||
.then(discussions => {
|
||||
const selectedDiscussion = discussions.find(discussion => discussion.id === discussionId);
|
||||
if (selectedDiscussion) commit(types.UPDATE_DISCUSSION, selectedDiscussion);
|
||||
});
|
||||
export const refetchDiscussionById = ({ commit, state }, { path, discussionId }) =>
|
||||
new Promise(resolve => {
|
||||
service
|
||||
.fetchDiscussions(path)
|
||||
.then(res => res.json())
|
||||
.then(discussions => {
|
||||
const selectedDiscussion = discussions.find(discussion => discussion.id === discussionId);
|
||||
if (selectedDiscussion) {
|
||||
commit(types.UPDATE_DISCUSSION, selectedDiscussion);
|
||||
// We need to refetch as it is now the transformed one in state
|
||||
const discussion = utils.findNoteObjectById(state.discussions, discussionId);
|
||||
|
||||
resolve(discussion);
|
||||
}
|
||||
})
|
||||
.catch(() => {});
|
||||
});
|
||||
|
||||
export const deleteNote = ({ commit }, note) =>
|
||||
service.deleteNote(note.path).then(() => {
|
||||
|
|
@ -152,26 +161,28 @@ export const saveNote = ({ commit, dispatch }, noteData) => {
|
|||
const replyId = noteData.data.in_reply_to_discussion_id;
|
||||
const methodToDispatch = replyId ? 'replyToDiscussion' : 'createNewNote';
|
||||
|
||||
commit(types.REMOVE_PLACEHOLDER_NOTES); // remove previous placeholders
|
||||
$('.notes-form .flash-container').hide(); // hide previous flash notification
|
||||
commit(types.REMOVE_PLACEHOLDER_NOTES); // remove previous placeholders
|
||||
|
||||
if (hasQuickActions) {
|
||||
placeholderText = utils.stripQuickActions(placeholderText);
|
||||
}
|
||||
if (replyId) {
|
||||
if (hasQuickActions) {
|
||||
placeholderText = utils.stripQuickActions(placeholderText);
|
||||
}
|
||||
|
||||
if (placeholderText.length) {
|
||||
commit(types.SHOW_PLACEHOLDER_NOTE, {
|
||||
noteBody: placeholderText,
|
||||
replyId,
|
||||
});
|
||||
}
|
||||
if (placeholderText.length) {
|
||||
commit(types.SHOW_PLACEHOLDER_NOTE, {
|
||||
noteBody: placeholderText,
|
||||
replyId,
|
||||
});
|
||||
}
|
||||
|
||||
if (hasQuickActions) {
|
||||
commit(types.SHOW_PLACEHOLDER_NOTE, {
|
||||
isSystemNote: true,
|
||||
noteBody: utils.getQuickActionText(note),
|
||||
replyId,
|
||||
});
|
||||
if (hasQuickActions) {
|
||||
commit(types.SHOW_PLACEHOLDER_NOTE, {
|
||||
isSystemNote: true,
|
||||
noteBody: utils.getQuickActionText(note),
|
||||
replyId,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return dispatch(methodToDispatch, noteData).then(res => {
|
||||
|
|
@ -211,7 +222,9 @@ export const saveNote = ({ commit, dispatch }, noteData) => {
|
|||
if (errors && errors.commands_only) {
|
||||
Flash(errors.commands_only, 'notice', noteData.flashContainer);
|
||||
}
|
||||
commit(types.REMOVE_PLACEHOLDER_NOTES);
|
||||
if (replyId) {
|
||||
commit(types.REMOVE_PLACEHOLDER_NOTES);
|
||||
}
|
||||
|
||||
return res;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import _ from 'underscore';
|
||||
import * as constants from '../constants';
|
||||
import { reduceDiscussionsToLineCodes } from './utils';
|
||||
import { collapseSystemNotes } from './collapse_utils';
|
||||
|
||||
export const discussions = state => collapseSystemNotes(state.discussions);
|
||||
|
|
@ -28,17 +29,8 @@ export const notesById = state =>
|
|||
return acc;
|
||||
}, {});
|
||||
|
||||
export const discussionsByLineCode = state =>
|
||||
state.discussions.reduce((acc, note) => {
|
||||
if (note.diff_discussion && note.line_code && note.resolvable) {
|
||||
// For context about line notes: there might be multiple notes with the same line code
|
||||
const items = acc[note.line_code] || [];
|
||||
items.push(note);
|
||||
|
||||
Object.assign(acc, { [note.line_code]: items });
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
export const discussionsStructuredByLineCode = state =>
|
||||
reduceDiscussionsToLineCodes(state.discussions);
|
||||
|
||||
export const noteableType = state => {
|
||||
const { ISSUE_NOTEABLE_TYPE, MERGE_REQUEST_NOTEABLE_TYPE, EPIC_NOTEABLE_TYPE } = constants;
|
||||
|
|
|
|||
|
|
@ -54,13 +54,12 @@ export default {
|
|||
|
||||
[types.EXPAND_DISCUSSION](state, { discussionId }) {
|
||||
const discussion = utils.findNoteObjectById(state.discussions, discussionId);
|
||||
|
||||
discussion.expanded = true;
|
||||
Object.assign(discussion, { expanded: true });
|
||||
},
|
||||
|
||||
[types.COLLAPSE_DISCUSSION](state, { discussionId }) {
|
||||
const discussion = utils.findNoteObjectById(state.discussions, discussionId);
|
||||
discussion.expanded = false;
|
||||
Object.assign(discussion, { expanded: false });
|
||||
},
|
||||
|
||||
[types.REMOVE_PLACEHOLDER_NOTES](state) {
|
||||
|
|
@ -95,10 +94,15 @@ export default {
|
|||
[types.SET_USER_DATA](state, data) {
|
||||
Object.assign(state, { userData: data });
|
||||
},
|
||||
|
||||
[types.SET_INITIAL_DISCUSSIONS](state, discussionsData) {
|
||||
const discussions = [];
|
||||
|
||||
discussionsData.forEach(discussion => {
|
||||
if (discussion.diff_file) {
|
||||
Object.assign(discussion, { fileHash: discussion.diff_file.file_hash });
|
||||
}
|
||||
|
||||
// To support legacy notes, should be very rare case.
|
||||
if (discussion.individual_note && discussion.notes.length > 1) {
|
||||
discussion.notes.forEach(n => {
|
||||
|
|
@ -168,8 +172,7 @@ export default {
|
|||
|
||||
[types.TOGGLE_DISCUSSION](state, { discussionId }) {
|
||||
const discussion = utils.findNoteObjectById(state.discussions, discussionId);
|
||||
|
||||
discussion.expanded = !discussion.expanded;
|
||||
Object.assign(discussion, { expanded: !discussion.expanded });
|
||||
},
|
||||
|
||||
[types.UPDATE_NOTE](state, note) {
|
||||
|
|
@ -185,16 +188,12 @@ export default {
|
|||
|
||||
[types.UPDATE_DISCUSSION](state, noteData) {
|
||||
const note = noteData;
|
||||
let index = 0;
|
||||
|
||||
state.discussions.forEach((n, i) => {
|
||||
if (n.id === note.id) {
|
||||
index = i;
|
||||
}
|
||||
});
|
||||
|
||||
const selectedDiscussion = state.discussions.find(disc => disc.id === note.id);
|
||||
note.expanded = true; // override expand flag to prevent collapse
|
||||
state.discussions.splice(index, 1, note);
|
||||
if (note.diff_file) {
|
||||
Object.assign(note, { fileHash: note.diff_file.file_hash });
|
||||
}
|
||||
Object.assign(selectedDiscussion, { ...note });
|
||||
},
|
||||
|
||||
[types.CLOSE_ISSUE](state) {
|
||||
|
|
|
|||
|
|
@ -2,13 +2,11 @@ import AjaxCache from '~/lib/utils/ajax_cache';
|
|||
|
||||
const REGEX_QUICK_ACTIONS = /^\/\w+.*$/gm;
|
||||
|
||||
export const findNoteObjectById = (notes, id) =>
|
||||
notes.filter(n => n.id === id)[0];
|
||||
export const findNoteObjectById = (notes, id) => notes.filter(n => n.id === id)[0];
|
||||
|
||||
export const getQuickActionText = note => {
|
||||
let text = 'Applying command';
|
||||
const quickActions =
|
||||
AjaxCache.get(gl.GfmAutoComplete.dataSources.commands) || [];
|
||||
const quickActions = AjaxCache.get(gl.GfmAutoComplete.dataSources.commands) || [];
|
||||
|
||||
const executedCommands = quickActions.filter(command => {
|
||||
const commandRegex = new RegExp(`/${command.name}`);
|
||||
|
|
@ -27,7 +25,18 @@ export const getQuickActionText = note => {
|
|||
return text;
|
||||
};
|
||||
|
||||
export const reduceDiscussionsToLineCodes = selectedDiscussions =>
|
||||
selectedDiscussions.reduce((acc, note) => {
|
||||
if (note.diff_discussion && note.line_code && note.resolvable) {
|
||||
// For context about line notes: there might be multiple notes with the same line code
|
||||
const items = acc[note.line_code] || [];
|
||||
items.push(note);
|
||||
|
||||
Object.assign(acc, { [note.line_code]: items });
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
export const hasQuickActions = note => REGEX_QUICK_ACTIONS.test(note);
|
||||
|
||||
export const stripQuickActions = note =>
|
||||
note.replace(REGEX_QUICK_ACTIONS, '').trim();
|
||||
export const stripQuickActions = note => note.replace(REGEX_QUICK_ACTIONS, '').trim();
|
||||
|
|
|
|||
|
|
@ -186,11 +186,8 @@ describe 'Merge request > User posts diff notes', :js do
|
|||
|
||||
describe 'posting a note' do
|
||||
it 'adds as discussion' do
|
||||
expect(page).to have_css('.js-temp-notes-holder', count: 2)
|
||||
|
||||
should_allow_commenting(find('[id="6eb14e00385d2fb284765eb1cd8d420d33d63fc9_22_22"]'), asset_form_reset: false)
|
||||
expect(page).to have_css('.notes_holder .note.note-discussion', count: 1)
|
||||
expect(page).to have_css('.js-temp-notes-holder', count: 1)
|
||||
expect(page).to have_button('Reply...')
|
||||
end
|
||||
end
|
||||
|
|
@ -267,7 +264,7 @@ describe 'Merge request > User posts diff notes', :js do
|
|||
def assert_comment_persistence(line_holder, asset_form_reset:)
|
||||
notes_holder_saved = line_holder.find(:xpath, notes_holder_input_xpath)
|
||||
|
||||
expect(notes_holder_saved[:class]).not_to include(notes_holder_input_class)
|
||||
expect(notes_holder_saved[:class]).not_to include('note-edit-form')
|
||||
expect(notes_holder_saved).to have_content test_note_comment
|
||||
|
||||
assert_form_is_reset if asset_form_reset
|
||||
|
|
@ -281,6 +278,6 @@ describe 'Merge request > User posts diff notes', :js do
|
|||
end
|
||||
|
||||
def assert_form_is_reset
|
||||
expect(page).to have_no_css('.js-temp-notes-holder')
|
||||
expect(page).to have_no_css('.note-edit-form')
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -51,7 +51,9 @@ describe('DiffFile', () => {
|
|||
});
|
||||
|
||||
it('should have collapsed text and link', done => {
|
||||
vm.file.collapsed = true;
|
||||
vm.file.renderIt = true;
|
||||
vm.file.collapsed = false;
|
||||
vm.file.highlightedDiffLines = null;
|
||||
|
||||
vm.$nextTick(() => {
|
||||
expect(vm.$el.innerText).toContain('This diff is collapsed');
|
||||
|
|
|
|||
|
|
@ -6,61 +6,61 @@ import discussionsMockData from '../mock_data/diff_discussions';
|
|||
import diffFileMockData from '../mock_data/diff_file';
|
||||
|
||||
describe('DiffLineGutterContent', () => {
|
||||
const getDiscussionsMockData = () => [Object.assign({}, discussionsMockData)];
|
||||
const getDiffFileMock = () => Object.assign({}, diffFileMockData);
|
||||
const createComponent = (options = {}) => {
|
||||
const cmp = Vue.extend(DiffLineGutterContent);
|
||||
const props = Object.assign({}, options);
|
||||
props.line = {
|
||||
lineCode: 'LC_42',
|
||||
type: 'new',
|
||||
oldLine: null,
|
||||
newLine: 1,
|
||||
discussions: [],
|
||||
text: '+<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n',
|
||||
richText: '+<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n',
|
||||
metaData: null,
|
||||
};
|
||||
props.fileHash = getDiffFileMock().fileHash;
|
||||
props.contextLinesPath = '/context/lines/path';
|
||||
|
||||
return createComponentWithStore(cmp, store, props).$mount();
|
||||
};
|
||||
const setDiscussions = component => {
|
||||
component.$store.dispatch('setInitialNotes', getDiscussionsMockData());
|
||||
};
|
||||
|
||||
const resetDiscussions = component => {
|
||||
component.$store.dispatch('setInitialNotes', []);
|
||||
};
|
||||
|
||||
describe('computed', () => {
|
||||
describe('lineHref', () => {
|
||||
it('should prepend # to lineCode', () => {
|
||||
const lineCode = 'LC_42';
|
||||
const component = createComponent({ lineCode });
|
||||
const component = createComponent();
|
||||
expect(component.lineHref).toEqual(`#${lineCode}`);
|
||||
});
|
||||
|
||||
it('should return # if there is no lineCode', () => {
|
||||
const component = createComponent({ lineCode: null });
|
||||
const component = createComponent();
|
||||
component.line.lineCode = '';
|
||||
expect(component.lineHref).toEqual('#');
|
||||
});
|
||||
});
|
||||
|
||||
describe('discussions, hasDiscussions, shouldShowAvatarsOnGutter', () => {
|
||||
it('should return empty array when there is no discussion', () => {
|
||||
const component = createComponent({ lineCode: 'LC_42' });
|
||||
expect(component.discussions).toEqual([]);
|
||||
const component = createComponent();
|
||||
expect(component.hasDiscussions).toEqual(false);
|
||||
expect(component.shouldShowAvatarsOnGutter).toEqual(false);
|
||||
});
|
||||
|
||||
it('should return discussions for the given lineCode', () => {
|
||||
const { lineCode } = getDiffFileMock().highlightedDiffLines[1];
|
||||
const component = createComponent({
|
||||
lineCode,
|
||||
const cmp = Vue.extend(DiffLineGutterContent);
|
||||
const props = {
|
||||
line: getDiffFileMock().highlightedDiffLines[1],
|
||||
fileHash: getDiffFileMock().fileHash,
|
||||
showCommentButton: true,
|
||||
discussions: getDiscussionsMockData(),
|
||||
});
|
||||
contextLinesPath: '/context/lines/path',
|
||||
};
|
||||
props.line.discussions = [Object.assign({}, discussionsMockData)];
|
||||
const component = createComponentWithStore(cmp, store, props).$mount();
|
||||
|
||||
setDiscussions(component);
|
||||
|
||||
expect(component.discussions).toEqual(getDiscussionsMockData());
|
||||
expect(component.hasDiscussions).toEqual(true);
|
||||
expect(component.shouldShowAvatarsOnGutter).toEqual(true);
|
||||
|
||||
resetDiscussions(component);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -104,9 +104,7 @@ describe('DiffLineGutterContent', () => {
|
|||
lineCode: getDiffFileMock().highlightedDiffLines[1].lineCode,
|
||||
});
|
||||
|
||||
setDiscussions(component);
|
||||
expect(component.$el.querySelector('.diff-comment-avatar-holders')).toBeDefined();
|
||||
resetDiscussions(component);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -18,11 +18,11 @@ describe('ParallelDiffView', () => {
|
|||
}).$mount();
|
||||
});
|
||||
|
||||
describe('computed', () => {
|
||||
describe('parallelDiffLines', () => {
|
||||
describe('assigned', () => {
|
||||
describe('diffLines', () => {
|
||||
it('should normalize lines for empty cells', () => {
|
||||
expect(component.parallelDiffLines[0].left.type).toEqual(constants.EMPTY_CELL_TYPE);
|
||||
expect(component.parallelDiffLines[1].left.type).toEqual(constants.EMPTY_CELL_TYPE);
|
||||
expect(component.diffLines[0].left.type).toEqual(constants.EMPTY_CELL_TYPE);
|
||||
expect(component.diffLines[1].left.type).toEqual(constants.EMPTY_CELL_TYPE);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ export default {
|
|||
type: 'new',
|
||||
oldLine: null,
|
||||
newLine: 1,
|
||||
discussions: [],
|
||||
text: '+<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n',
|
||||
richText: '+<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n',
|
||||
metaData: null,
|
||||
|
|
@ -58,6 +59,7 @@ export default {
|
|||
type: 'new',
|
||||
oldLine: null,
|
||||
newLine: 2,
|
||||
discussions: [],
|
||||
text: '+<span id="LC2" class="line" lang="plaintext"></span>\n',
|
||||
richText: '+<span id="LC2" class="line" lang="plaintext"></span>\n',
|
||||
metaData: null,
|
||||
|
|
@ -67,6 +69,7 @@ export default {
|
|||
type: null,
|
||||
oldLine: 1,
|
||||
newLine: 3,
|
||||
discussions: [],
|
||||
text: ' <span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n',
|
||||
richText: ' <span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n',
|
||||
metaData: null,
|
||||
|
|
@ -76,6 +79,7 @@ export default {
|
|||
type: null,
|
||||
oldLine: 2,
|
||||
newLine: 4,
|
||||
discussions: [],
|
||||
text: ' <span id="LC4" class="line" lang="plaintext"></span>\n',
|
||||
richText: ' <span id="LC4" class="line" lang="plaintext"></span>\n',
|
||||
metaData: null,
|
||||
|
|
@ -85,6 +89,7 @@ export default {
|
|||
type: null,
|
||||
oldLine: 3,
|
||||
newLine: 5,
|
||||
discussions: [],
|
||||
text: ' <span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n',
|
||||
richText: ' <span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n',
|
||||
metaData: null,
|
||||
|
|
@ -94,6 +99,7 @@ export default {
|
|||
type: 'match',
|
||||
oldLine: null,
|
||||
newLine: null,
|
||||
discussions: [],
|
||||
text: '',
|
||||
richText: '',
|
||||
metaData: {
|
||||
|
|
@ -112,6 +118,7 @@ export default {
|
|||
type: 'new',
|
||||
oldLine: null,
|
||||
newLine: 1,
|
||||
discussions: [],
|
||||
text: '+<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n',
|
||||
richText: '<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n',
|
||||
metaData: null,
|
||||
|
|
@ -126,6 +133,7 @@ export default {
|
|||
type: 'new',
|
||||
oldLine: null,
|
||||
newLine: 2,
|
||||
discussions: [],
|
||||
text: '+<span id="LC2" class="line" lang="plaintext"></span>\n',
|
||||
richText: '<span id="LC2" class="line" lang="plaintext"></span>\n',
|
||||
metaData: null,
|
||||
|
|
@ -137,6 +145,7 @@ export default {
|
|||
type: null,
|
||||
oldLine: 1,
|
||||
newLine: 3,
|
||||
discussions: [],
|
||||
text: ' <span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n',
|
||||
richText: '<span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n',
|
||||
metaData: null,
|
||||
|
|
@ -146,6 +155,7 @@ export default {
|
|||
type: null,
|
||||
oldLine: 1,
|
||||
newLine: 3,
|
||||
discussions: [],
|
||||
text: ' <span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n',
|
||||
richText: '<span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n',
|
||||
metaData: null,
|
||||
|
|
@ -157,6 +167,7 @@ export default {
|
|||
type: null,
|
||||
oldLine: 2,
|
||||
newLine: 4,
|
||||
discussions: [],
|
||||
text: ' <span id="LC4" class="line" lang="plaintext"></span>\n',
|
||||
richText: '<span id="LC4" class="line" lang="plaintext"></span>\n',
|
||||
metaData: null,
|
||||
|
|
@ -166,6 +177,7 @@ export default {
|
|||
type: null,
|
||||
oldLine: 2,
|
||||
newLine: 4,
|
||||
discussions: [],
|
||||
text: ' <span id="LC4" class="line" lang="plaintext"></span>\n',
|
||||
richText: '<span id="LC4" class="line" lang="plaintext"></span>\n',
|
||||
metaData: null,
|
||||
|
|
@ -177,6 +189,7 @@ export default {
|
|||
type: null,
|
||||
oldLine: 3,
|
||||
newLine: 5,
|
||||
discussions: [],
|
||||
text: ' <span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n',
|
||||
richText: '<span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n',
|
||||
metaData: null,
|
||||
|
|
@ -186,6 +199,7 @@ export default {
|
|||
type: null,
|
||||
oldLine: 3,
|
||||
newLine: 5,
|
||||
discussions: [],
|
||||
text: ' <span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n',
|
||||
richText: '<span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n',
|
||||
metaData: null,
|
||||
|
|
@ -197,6 +211,7 @@ export default {
|
|||
type: 'match',
|
||||
oldLine: null,
|
||||
newLine: null,
|
||||
discussions: [],
|
||||
text: '',
|
||||
richText: '',
|
||||
metaData: {
|
||||
|
|
@ -209,6 +224,7 @@ export default {
|
|||
type: 'match',
|
||||
oldLine: null,
|
||||
newLine: null,
|
||||
discussions: [],
|
||||
text: '',
|
||||
richText: '',
|
||||
metaData: {
|
||||
|
|
|
|||
|
|
@ -7,10 +7,30 @@ import {
|
|||
} from '~/diffs/constants';
|
||||
import * as actions from '~/diffs/store/actions';
|
||||
import * as types from '~/diffs/store/mutation_types';
|
||||
import { reduceDiscussionsToLineCodes } from '~/notes/stores/utils';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import testAction from '../../helpers/vuex_action_helper';
|
||||
|
||||
describe('DiffsStoreActions', () => {
|
||||
const originalMethods = {
|
||||
requestAnimationFrame: global.requestAnimationFrame,
|
||||
requestIdleCallback: global.requestIdleCallback,
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
['requestAnimationFrame', 'requestIdleCallback'].forEach(method => {
|
||||
global[method] = cb => {
|
||||
cb();
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
['requestAnimationFrame', 'requestIdleCallback'].forEach(method => {
|
||||
global[method] = originalMethods[method];
|
||||
});
|
||||
});
|
||||
|
||||
describe('setBaseConfig', () => {
|
||||
it('should set given endpoint and project path', done => {
|
||||
const endpoint = '/diffs/set/endpoint';
|
||||
|
|
@ -53,6 +73,162 @@ describe('DiffsStoreActions', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('assignDiscussionsToDiff', () => {
|
||||
it('should merge discussions into diffs', done => {
|
||||
const state = {
|
||||
diffFiles: [
|
||||
{
|
||||
fileHash: 'ABC',
|
||||
parallelDiffLines: [
|
||||
{
|
||||
left: {
|
||||
lineCode: 'ABC_1_1',
|
||||
discussions: [],
|
||||
},
|
||||
right: {
|
||||
lineCode: 'ABC_1_1',
|
||||
discussions: [],
|
||||
},
|
||||
},
|
||||
],
|
||||
highlightedDiffLines: [
|
||||
{
|
||||
lineCode: 'ABC_1_1',
|
||||
discussions: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const singleDiscussion = {
|
||||
line_code: 'ABC_1_1',
|
||||
diff_discussion: {},
|
||||
diff_file: {
|
||||
file_hash: 'ABC',
|
||||
},
|
||||
resolvable: true,
|
||||
fileHash: 'ABC',
|
||||
};
|
||||
|
||||
const discussions = reduceDiscussionsToLineCodes([singleDiscussion]);
|
||||
|
||||
testAction(
|
||||
actions.assignDiscussionsToDiff,
|
||||
discussions,
|
||||
state,
|
||||
[
|
||||
{
|
||||
type: types.SET_LINE_DISCUSSIONS_FOR_FILE,
|
||||
payload: {
|
||||
fileHash: 'ABC',
|
||||
discussions: [singleDiscussion],
|
||||
},
|
||||
},
|
||||
],
|
||||
[],
|
||||
() => {
|
||||
done();
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('removeDiscussionsFromDiff', () => {
|
||||
it('should remove discussions from diffs', done => {
|
||||
const state = {
|
||||
diffFiles: [
|
||||
{
|
||||
fileHash: 'ABC',
|
||||
parallelDiffLines: [
|
||||
{
|
||||
left: {
|
||||
lineCode: 'ABC_1_1',
|
||||
discussions: [
|
||||
{
|
||||
id: 1,
|
||||
},
|
||||
],
|
||||
},
|
||||
right: {
|
||||
lineCode: 'ABC_1_1',
|
||||
discussions: [],
|
||||
},
|
||||
},
|
||||
],
|
||||
highlightedDiffLines: [
|
||||
{
|
||||
lineCode: 'ABC_1_1',
|
||||
discussions: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
const singleDiscussion = {
|
||||
fileHash: 'ABC',
|
||||
line_code: 'ABC_1_1',
|
||||
};
|
||||
|
||||
testAction(
|
||||
actions.removeDiscussionsFromDiff,
|
||||
singleDiscussion,
|
||||
state,
|
||||
[
|
||||
{
|
||||
type: types.REMOVE_LINE_DISCUSSIONS_FOR_FILE,
|
||||
payload: {
|
||||
fileHash: 'ABC',
|
||||
lineCode: 'ABC_1_1',
|
||||
},
|
||||
},
|
||||
],
|
||||
[],
|
||||
() => {
|
||||
done();
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('startRenderDiffsQueue', () => {
|
||||
it('should set all files to RENDER_FILE', done => {
|
||||
const state = {
|
||||
diffFiles: [
|
||||
{
|
||||
id: 1,
|
||||
renderIt: false,
|
||||
collapsed: false,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
renderIt: false,
|
||||
collapsed: false,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const pseudoCommit = (commitType, file) => {
|
||||
expect(commitType).toBe(types.RENDER_FILE);
|
||||
Object.assign(file, {
|
||||
renderIt: true,
|
||||
});
|
||||
};
|
||||
|
||||
actions
|
||||
.startRenderDiffsQueue({ state, commit: pseudoCommit })
|
||||
.then(() => {
|
||||
expect(state.diffFiles[0].renderIt).toBeTruthy();
|
||||
expect(state.diffFiles[1].renderIt).toBeTruthy();
|
||||
|
||||
done();
|
||||
})
|
||||
.catch(() => {
|
||||
done.fail();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('setInlineDiffViewType', () => {
|
||||
it('should set diff view type to inline and also set the cookie properly', done => {
|
||||
testAction(
|
||||
|
|
@ -204,7 +380,11 @@ describe('DiffsStoreActions', () => {
|
|||
|
||||
actions.toggleFileDiscussions({ getters, dispatch });
|
||||
|
||||
expect(dispatch).toHaveBeenCalledWith('collapseDiscussion', { discussionId: 1 }, { root: true });
|
||||
expect(dispatch).toHaveBeenCalledWith(
|
||||
'collapseDiscussion',
|
||||
{ discussionId: 1 },
|
||||
{ root: true },
|
||||
);
|
||||
});
|
||||
|
||||
it('should dispatch expandDiscussion when all discussions are collapsed', () => {
|
||||
|
|
@ -218,7 +398,11 @@ describe('DiffsStoreActions', () => {
|
|||
|
||||
actions.toggleFileDiscussions({ getters, dispatch });
|
||||
|
||||
expect(dispatch).toHaveBeenCalledWith('expandDiscussion', { discussionId: 1 }, { root: true });
|
||||
expect(dispatch).toHaveBeenCalledWith(
|
||||
'expandDiscussion',
|
||||
{ discussionId: 1 },
|
||||
{ root: true },
|
||||
);
|
||||
});
|
||||
|
||||
it('should dispatch expandDiscussion when some discussions are collapsed and others are expanded for the collapsed discussion', () => {
|
||||
|
|
@ -232,7 +416,11 @@ describe('DiffsStoreActions', () => {
|
|||
|
||||
actions.toggleFileDiscussions({ getters, dispatch });
|
||||
|
||||
expect(dispatch).toHaveBeenCalledWith('expandDiscussion', { discussionId: 1 }, { root: true });
|
||||
expect(dispatch).toHaveBeenCalledWith(
|
||||
'expandDiscussion',
|
||||
{ discussionId: 1 },
|
||||
{ root: true },
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -184,101 +184,73 @@ describe('Diffs Module Getters', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('singleDiscussionByLineCode', () => {
|
||||
it('returns found discussion per line Code', () => {
|
||||
const discussionsMock = {};
|
||||
discussionsMock.ABC = discussionMock;
|
||||
|
||||
expect(
|
||||
getters.singleDiscussionByLineCode(localState, {}, null, {
|
||||
discussionsByLineCode: () => discussionsMock,
|
||||
})('DEF'),
|
||||
).toEqual([]);
|
||||
});
|
||||
|
||||
it('returns empty array when no discussions match', () => {
|
||||
expect(
|
||||
getters.singleDiscussionByLineCode(localState, {}, null, {
|
||||
discussionsByLineCode: () => {},
|
||||
})('DEF'),
|
||||
).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('shouldRenderParallelCommentRow', () => {
|
||||
let line;
|
||||
|
||||
beforeEach(() => {
|
||||
line = {};
|
||||
|
||||
discussionMock.expanded = true;
|
||||
|
||||
line.left = {
|
||||
lineCode: 'ABC',
|
||||
discussions: [discussionMock],
|
||||
};
|
||||
|
||||
line.right = {
|
||||
lineCode: 'DEF',
|
||||
discussions: [discussionMock1],
|
||||
};
|
||||
});
|
||||
|
||||
it('returns true when discussion is expanded', () => {
|
||||
discussionMock.expanded = true;
|
||||
|
||||
expect(
|
||||
getters.shouldRenderParallelCommentRow(localState, {
|
||||
singleDiscussionByLineCode: () => [discussionMock],
|
||||
})(line),
|
||||
).toEqual(true);
|
||||
expect(getters.shouldRenderParallelCommentRow(localState)(line)).toEqual(true);
|
||||
});
|
||||
|
||||
it('returns false when no discussion was found', () => {
|
||||
line.left.discussions = [];
|
||||
line.right.discussions = [];
|
||||
|
||||
localState.diffLineCommentForms.ABC = false;
|
||||
localState.diffLineCommentForms.DEF = false;
|
||||
|
||||
expect(
|
||||
getters.shouldRenderParallelCommentRow(localState, {
|
||||
singleDiscussionByLineCode: () => [],
|
||||
})(line),
|
||||
).toEqual(false);
|
||||
expect(getters.shouldRenderParallelCommentRow(localState)(line)).toEqual(false);
|
||||
});
|
||||
|
||||
it('returns true when discussionForm was found', () => {
|
||||
localState.diffLineCommentForms.ABC = {};
|
||||
|
||||
expect(
|
||||
getters.shouldRenderParallelCommentRow(localState, {
|
||||
singleDiscussionByLineCode: () => [discussionMock],
|
||||
})(line),
|
||||
).toEqual(true);
|
||||
expect(getters.shouldRenderParallelCommentRow(localState)(line)).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('shouldRenderInlineCommentRow', () => {
|
||||
let line;
|
||||
|
||||
beforeEach(() => {
|
||||
discussionMock.expanded = true;
|
||||
|
||||
line = {
|
||||
lineCode: 'ABC',
|
||||
discussions: [discussionMock],
|
||||
};
|
||||
});
|
||||
|
||||
it('returns true when diffLineCommentForms has form', () => {
|
||||
localState.diffLineCommentForms.ABC = {};
|
||||
|
||||
expect(
|
||||
getters.shouldRenderInlineCommentRow(localState)({
|
||||
lineCode: 'ABC',
|
||||
}),
|
||||
).toEqual(true);
|
||||
expect(getters.shouldRenderInlineCommentRow(localState)(line)).toEqual(true);
|
||||
});
|
||||
|
||||
it('returns false when no line discussions were found', () => {
|
||||
expect(
|
||||
getters.shouldRenderInlineCommentRow(localState, {
|
||||
singleDiscussionByLineCode: () => [],
|
||||
})('DEF'),
|
||||
).toEqual(false);
|
||||
line.discussions = [];
|
||||
expect(getters.shouldRenderInlineCommentRow(localState)(line)).toEqual(false);
|
||||
});
|
||||
|
||||
it('returns true if all found discussions are expanded', () => {
|
||||
discussionMock.expanded = true;
|
||||
|
||||
expect(
|
||||
getters.shouldRenderInlineCommentRow(localState, {
|
||||
singleDiscussionByLineCode: () => [discussionMock],
|
||||
})('ABC'),
|
||||
).toEqual(true);
|
||||
expect(getters.shouldRenderInlineCommentRow(localState)(line)).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -138,10 +138,9 @@ describe('DiffsStoreMutations', () => {
|
|||
|
||||
const fileHash = 123;
|
||||
const state = { diffFiles: [{}, { fileHash, existingField: 0 }] };
|
||||
const file = { fileHash };
|
||||
const data = { diff_files: [{ file_hash: fileHash, extra_field: 1, existingField: 1 }] };
|
||||
|
||||
mutations[types.ADD_COLLAPSED_DIFFS](state, { file, data });
|
||||
mutations[types.ADD_COLLAPSED_DIFFS](state, { file: state.diffFiles[1], data });
|
||||
expect(spy).toHaveBeenCalledWith(data, { deep: true });
|
||||
|
||||
expect(state.diffFiles[1].fileHash).toEqual(fileHash);
|
||||
|
|
@ -149,4 +148,107 @@ describe('DiffsStoreMutations', () => {
|
|||
expect(state.diffFiles[1].extraField).toEqual(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('SET_LINE_DISCUSSIONS_FOR_FILE', () => {
|
||||
it('should add discussions to the given line', () => {
|
||||
const state = {
|
||||
diffFiles: [
|
||||
{
|
||||
fileHash: 'ABC',
|
||||
parallelDiffLines: [
|
||||
{
|
||||
left: {
|
||||
lineCode: 'ABC_1',
|
||||
discussions: [],
|
||||
},
|
||||
right: {
|
||||
lineCode: 'ABC_1',
|
||||
discussions: [],
|
||||
},
|
||||
},
|
||||
],
|
||||
highlightedDiffLines: [
|
||||
{
|
||||
lineCode: 'ABC_1',
|
||||
discussions: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
const discussions = [
|
||||
{
|
||||
id: 1,
|
||||
line_code: 'ABC_1',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
line_code: 'ABC_1',
|
||||
},
|
||||
];
|
||||
|
||||
mutations[types.SET_LINE_DISCUSSIONS_FOR_FILE](state, { fileHash: 'ABC', discussions });
|
||||
|
||||
expect(state.diffFiles[0].parallelDiffLines[0].left.discussions.length).toEqual(2);
|
||||
expect(state.diffFiles[0].parallelDiffLines[0].left.discussions[1].id).toEqual(2);
|
||||
|
||||
expect(state.diffFiles[0].highlightedDiffLines[0].discussions.length).toEqual(2);
|
||||
expect(state.diffFiles[0].highlightedDiffLines[0].discussions[1].id).toEqual(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('REMOVE_LINE_DISCUSSIONS', () => {
|
||||
it('should remove the existing discussions on the given line', () => {
|
||||
const state = {
|
||||
diffFiles: [
|
||||
{
|
||||
fileHash: 'ABC',
|
||||
parallelDiffLines: [
|
||||
{
|
||||
left: {
|
||||
lineCode: 'ABC_1',
|
||||
discussions: [
|
||||
{
|
||||
id: 1,
|
||||
line_code: 'ABC_1',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
line_code: 'ABC_1',
|
||||
},
|
||||
],
|
||||
},
|
||||
right: {
|
||||
lineCode: 'ABC_1',
|
||||
discussions: [],
|
||||
},
|
||||
},
|
||||
],
|
||||
highlightedDiffLines: [
|
||||
{
|
||||
lineCode: 'ABC_1',
|
||||
discussions: [
|
||||
{
|
||||
id: 1,
|
||||
line_code: 'ABC_1',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
line_code: 'ABC_1',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
mutations[types.REMOVE_LINE_DISCUSSIONS_FOR_FILE](state, {
|
||||
fileHash: 'ABC',
|
||||
lineCode: 'ABC_1',
|
||||
});
|
||||
expect(state.diffFiles[0].parallelDiffLines[0].left.discussions.length).toEqual(0);
|
||||
expect(state.diffFiles[0].highlightedDiffLines[0].discussions.length).toEqual(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -179,32 +179,64 @@ describe('DiffsStoreUtils', () => {
|
|||
|
||||
describe('trimFirstCharOfLineContent', () => {
|
||||
it('trims the line when it starts with a space', () => {
|
||||
expect(utils.trimFirstCharOfLineContent({ richText: ' diff' })).toEqual({ richText: 'diff' });
|
||||
expect(utils.trimFirstCharOfLineContent({ richText: ' diff' })).toEqual({
|
||||
discussions: [],
|
||||
richText: 'diff',
|
||||
});
|
||||
});
|
||||
|
||||
it('trims the line when it starts with a +', () => {
|
||||
expect(utils.trimFirstCharOfLineContent({ richText: '+diff' })).toEqual({ richText: 'diff' });
|
||||
expect(utils.trimFirstCharOfLineContent({ richText: '+diff' })).toEqual({
|
||||
discussions: [],
|
||||
richText: 'diff',
|
||||
});
|
||||
});
|
||||
|
||||
it('trims the line when it starts with a -', () => {
|
||||
expect(utils.trimFirstCharOfLineContent({ richText: '-diff' })).toEqual({ richText: 'diff' });
|
||||
expect(utils.trimFirstCharOfLineContent({ richText: '-diff' })).toEqual({
|
||||
discussions: [],
|
||||
richText: 'diff',
|
||||
});
|
||||
});
|
||||
|
||||
it('does not trims the line when it starts with a letter', () => {
|
||||
expect(utils.trimFirstCharOfLineContent({ richText: 'diff' })).toEqual({ richText: 'diff' });
|
||||
expect(utils.trimFirstCharOfLineContent({ richText: 'diff' })).toEqual({
|
||||
discussions: [],
|
||||
richText: 'diff',
|
||||
});
|
||||
});
|
||||
|
||||
it('does not modify the provided object', () => {
|
||||
const lineObj = {
|
||||
discussions: [],
|
||||
richText: ' diff',
|
||||
};
|
||||
|
||||
utils.trimFirstCharOfLineContent(lineObj);
|
||||
expect(lineObj).toEqual({ richText: ' diff' });
|
||||
expect(lineObj).toEqual({ discussions: [], richText: ' diff' });
|
||||
});
|
||||
|
||||
it('handles a undefined or null parameter', () => {
|
||||
expect(utils.trimFirstCharOfLineContent()).toEqual({});
|
||||
expect(utils.trimFirstCharOfLineContent()).toEqual({ discussions: [] });
|
||||
});
|
||||
});
|
||||
|
||||
describe('prepareDiffData', () => {
|
||||
it('sets the renderIt and collapsed attribute on files', () => {
|
||||
const preparedDiff = { diffFiles: [getDiffFileMock()] };
|
||||
utils.prepareDiffData(preparedDiff);
|
||||
|
||||
const firstParallelDiffLine = preparedDiff.diffFiles[0].parallelDiffLines[2];
|
||||
expect(firstParallelDiffLine.left.discussions.length).toBe(0);
|
||||
expect(firstParallelDiffLine.left).not.toHaveAttr('text');
|
||||
expect(firstParallelDiffLine.right.discussions.length).toBe(0);
|
||||
expect(firstParallelDiffLine.right).not.toHaveAttr('text');
|
||||
|
||||
expect(preparedDiff.diffFiles[0].highlightedDiffLines[0].discussions.length).toBe(0);
|
||||
expect(preparedDiff.diffFiles[0].highlightedDiffLines[0]).not.toHaveAttr('text');
|
||||
|
||||
expect(preparedDiff.diffFiles[0].renderIt).toBeTruthy();
|
||||
expect(preparedDiff.diffFiles[0].collapsed).toBeFalsy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@ import LazyLoader from '~/lazy_loader';
|
|||
|
||||
let lazyLoader = null;
|
||||
|
||||
describe('LazyLoader', function () {
|
||||
describe('LazyLoader', function() {
|
||||
preloadFixtures('issues/issue_with_comment.html.raw');
|
||||
|
||||
beforeEach(function () {
|
||||
beforeEach(function() {
|
||||
loadFixtures('issues/issue_with_comment.html.raw');
|
||||
lazyLoader = new LazyLoader({
|
||||
observerNode: 'body',
|
||||
|
|
@ -13,8 +13,8 @@ describe('LazyLoader', function () {
|
|||
// Doing everything that happens normally in onload
|
||||
lazyLoader.loadCheck();
|
||||
});
|
||||
describe('behavior', function () {
|
||||
it('should copy value from data-src to src for img 1', function (done) {
|
||||
describe('behavior', function() {
|
||||
it('should copy value from data-src to src for img 1', function(done) {
|
||||
const img = document.querySelectorAll('img[data-src]')[0];
|
||||
const originalDataSrc = img.getAttribute('data-src');
|
||||
img.scrollIntoView();
|
||||
|
|
@ -26,7 +26,7 @@ describe('LazyLoader', function () {
|
|||
}, 100);
|
||||
});
|
||||
|
||||
it('should lazy load dynamically added data-src images', function (done) {
|
||||
it('should lazy load dynamically added data-src images', function(done) {
|
||||
const newImg = document.createElement('img');
|
||||
const testPath = '/img/testimg.png';
|
||||
newImg.className = 'lazy';
|
||||
|
|
@ -41,7 +41,7 @@ describe('LazyLoader', function () {
|
|||
}, 100);
|
||||
});
|
||||
|
||||
it('should not alter normal images', function (done) {
|
||||
it('should not alter normal images', function(done) {
|
||||
const newImg = document.createElement('img');
|
||||
const testPath = '/img/testimg.png';
|
||||
newImg.setAttribute('src', testPath);
|
||||
|
|
|
|||
Loading…
Reference in New Issue