debian-mirror-gitlab/app/assets/javascripts/merge_conflicts/merge_conflict_store.js
2020-03-13 15:44:24 +05:30

434 lines
12 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* eslint-disable no-param-reassign, babel/camelcase, no-nested-ternary, no-continue */
import $ from 'jquery';
import Vue from 'vue';
import Cookies from 'js-cookie';
import { s__ } from '~/locale';
(global => {
global.mergeConflicts = global.mergeConflicts || {};
const diffViewType = Cookies.get('diff_view');
const HEAD_HEADER_TEXT = s__('MergeConflict|HEAD//our changes');
const ORIGIN_HEADER_TEXT = s__('MergeConflict|origin//their changes');
const HEAD_BUTTON_TITLE = s__('MergeConflict|Use ours');
const ORIGIN_BUTTON_TITLE = s__('MergeConflict|Use theirs');
const INTERACTIVE_RESOLVE_MODE = 'interactive';
const EDIT_RESOLVE_MODE = 'edit';
const DEFAULT_RESOLVE_MODE = INTERACTIVE_RESOLVE_MODE;
const VIEW_TYPES = {
INLINE: 'inline',
PARALLEL: 'parallel',
};
const CONFLICT_TYPES = {
TEXT: 'text',
TEXT_EDITOR: 'text-editor',
};
global.mergeConflicts.mergeConflictsStore = {
state: {
isLoading: true,
hasError: false,
isSubmitting: false,
isParallel: diffViewType === VIEW_TYPES.PARALLEL,
diffViewType,
conflictsData: {},
},
setConflictsData(data) {
this.decorateFiles(data.files);
this.state.conflictsData = {
files: data.files,
commitMessage: data.commit_message,
sourceBranch: data.source_branch,
targetBranch: data.target_branch,
shortCommitSha: data.commit_sha.slice(0, 7),
};
},
decorateFiles(files) {
files.forEach(file => {
file.content = '';
file.resolutionData = {};
file.promptDiscardConfirmation = false;
file.resolveMode = DEFAULT_RESOLVE_MODE;
file.filePath = this.getFilePath(file);
file.iconClass = `fa-${file.blob_icon}`;
file.blobPath = file.blob_path;
if (file.type === CONFLICT_TYPES.TEXT) {
file.showEditor = false;
file.loadEditor = false;
this.setInlineLine(file);
this.setParallelLine(file);
} else if (file.type === CONFLICT_TYPES.TEXT_EDITOR) {
file.showEditor = true;
file.loadEditor = true;
}
});
},
setInlineLine(file) {
file.inlineLines = [];
file.sections.forEach(section => {
let currentLineType = 'new';
const { conflict, lines, id } = section;
if (conflict) {
file.inlineLines.push(this.getHeadHeaderLine(id));
}
lines.forEach(line => {
const { type } = line;
if ((type === 'new' || type === 'old') && currentLineType !== type) {
currentLineType = type;
file.inlineLines.push({ lineType: 'emptyLine', richText: '' });
}
this.decorateLineForInlineView(line, id, conflict);
file.inlineLines.push(line);
});
if (conflict) {
file.inlineLines.push(this.getOriginHeaderLine(id));
}
});
},
setParallelLine(file) {
file.parallelLines = [];
const linesObj = { left: [], right: [] };
file.sections.forEach(section => {
const { conflict, lines, id } = section;
if (conflict) {
linesObj.left.push(this.getOriginHeaderLine(id));
linesObj.right.push(this.getHeadHeaderLine(id));
}
lines.forEach(line => {
const { type } = line;
if (conflict) {
if (type === 'old') {
linesObj.left.push(this.getLineForParallelView(line, id, 'conflict'));
} else if (type === 'new') {
linesObj.right.push(this.getLineForParallelView(line, id, 'conflict', true));
}
} else {
const lineType = type || 'context';
linesObj.left.push(this.getLineForParallelView(line, id, lineType));
linesObj.right.push(this.getLineForParallelView(line, id, lineType, true));
}
});
this.checkLineLengths(linesObj);
});
for (let i = 0, len = linesObj.left.length; i < len; i += 1) {
file.parallelLines.push([linesObj.right[i], linesObj.left[i]]);
}
},
setLoadingState(state) {
this.state.isLoading = state;
},
setErrorState(state) {
this.state.hasError = state;
},
setFailedRequest(message) {
this.state.hasError = true;
this.state.conflictsData.errorMessage = message;
},
getConflictsCount() {
if (!this.state.conflictsData.files.length) {
return 0;
}
const { files } = this.state.conflictsData;
let count = 0;
files.forEach(file => {
if (file.type === CONFLICT_TYPES.TEXT) {
file.sections.forEach(section => {
if (section.conflict) {
count += 1;
}
});
} else {
count += 1;
}
});
return count;
},
getConflictsCountText() {
const count = this.getConflictsCount();
const text = count > 1 ? s__('MergeConflict|conflicts') : s__('MergeConflict|conflict');
return `${count} ${text}`;
},
setViewType(viewType) {
this.state.diffView = viewType;
this.state.isParallel = viewType === VIEW_TYPES.PARALLEL;
Cookies.set('diff_view', viewType);
},
getHeadHeaderLine(id) {
return {
id,
richText: HEAD_HEADER_TEXT,
buttonTitle: HEAD_BUTTON_TITLE,
type: 'new',
section: 'head',
isHeader: true,
isHead: true,
isSelected: false,
isUnselected: false,
};
},
decorateLineForInlineView(line, id, conflict) {
const { type } = line;
line.id = id;
line.hasConflict = conflict;
line.isHead = type === 'new';
line.isOrigin = type === 'old';
line.hasMatch = type === 'match';
line.richText = line.rich_text;
line.isSelected = false;
line.isUnselected = false;
},
getLineForParallelView(line, id, lineType, isHead) {
const { old_line, new_line, rich_text } = line;
const hasConflict = lineType === 'conflict';
return {
id,
lineType,
hasConflict,
isHead: hasConflict && isHead,
isOrigin: hasConflict && !isHead,
hasMatch: lineType === 'match',
lineNumber: isHead ? new_line : old_line,
section: isHead ? 'head' : 'origin',
richText: rich_text,
isSelected: false,
isUnselected: false,
};
},
getOriginHeaderLine(id) {
return {
id,
richText: ORIGIN_HEADER_TEXT,
buttonTitle: ORIGIN_BUTTON_TITLE,
type: 'old',
section: 'origin',
isHeader: true,
isOrigin: true,
isSelected: false,
isUnselected: false,
};
},
getFilePath(file) {
const { old_path, new_path } = file;
return old_path === new_path ? new_path : `${old_path}${new_path}`;
},
checkLineLengths(linesObj) {
const { left, right } = linesObj;
if (left.length !== right.length) {
if (left.length > right.length) {
const diff = left.length - right.length;
for (let i = 0; i < diff; i += 1) {
right.push({ lineType: 'emptyLine', richText: '' });
}
} else {
const diff = right.length - left.length;
for (let i = 0; i < diff; i += 1) {
left.push({ lineType: 'emptyLine', richText: '' });
}
}
}
},
setPromptConfirmationState(file, state) {
file.promptDiscardConfirmation = state;
},
setFileResolveMode(file, mode) {
if (mode === INTERACTIVE_RESOLVE_MODE) {
file.showEditor = false;
} else if (mode === EDIT_RESOLVE_MODE) {
// Restore Interactive mode when switching to Edit mode
file.showEditor = true;
file.loadEditor = true;
file.resolutionData = {};
this.restoreFileLinesState(file);
}
file.resolveMode = mode;
},
restoreFileLinesState(file) {
file.inlineLines.forEach(line => {
if (line.hasConflict || line.isHeader) {
line.isSelected = false;
line.isUnselected = false;
}
});
file.parallelLines.forEach(lines => {
const left = lines[0];
const right = lines[1];
const isLeftMatch = left.hasConflict || left.isHeader;
const isRightMatch = right.hasConflict || right.isHeader;
if (isLeftMatch || isRightMatch) {
left.isSelected = false;
left.isUnselected = false;
right.isSelected = false;
right.isUnselected = false;
}
});
},
isReadyToCommit() {
const { files } = this.state.conflictsData;
const hasCommitMessage = $.trim(this.state.conflictsData.commitMessage).length;
let unresolved = 0;
for (let i = 0, l = files.length; i < l; i += 1) {
const file = files[i];
if (file.resolveMode === INTERACTIVE_RESOLVE_MODE) {
let numberConflicts = 0;
const resolvedConflicts = Object.keys(file.resolutionData).length;
// We only check for conflicts type 'text'
// since conflicts `text_editor` can´t be resolved in interactive mode
if (file.type === CONFLICT_TYPES.TEXT) {
for (let j = 0, k = file.sections.length; j < k; j += 1) {
if (file.sections[j].conflict) {
numberConflicts += 1;
}
}
if (resolvedConflicts !== numberConflicts) {
unresolved += 1;
}
}
} else if (file.resolveMode === EDIT_RESOLVE_MODE) {
// Unlikely to happen since switching to Edit mode saves content automatically.
// Checking anyway in case the save strategy changes in the future
if (!file.content) {
unresolved += 1;
continue;
}
}
}
return !this.state.isSubmitting && hasCommitMessage && !unresolved;
},
getCommitButtonText() {
const initial = s__('MergeConflict|Commit to source branch');
const inProgress = s__('MergeConflict|Committing...');
return this.state ? (this.state.isSubmitting ? inProgress : initial) : initial;
},
getCommitData() {
let commitData = {};
commitData = {
commit_message: this.state.conflictsData.commitMessage,
files: [],
};
this.state.conflictsData.files.forEach(file => {
const addFile = {
old_path: file.old_path,
new_path: file.new_path,
};
if (file.type === CONFLICT_TYPES.TEXT) {
// Submit only one data for type of editing
if (file.resolveMode === INTERACTIVE_RESOLVE_MODE) {
addFile.sections = file.resolutionData;
} else if (file.resolveMode === EDIT_RESOLVE_MODE) {
addFile.content = file.content;
}
} else if (file.type === CONFLICT_TYPES.TEXT_EDITOR) {
addFile.content = file.content;
}
commitData.files.push(addFile);
});
return commitData;
},
handleSelected(file, sectionId, selection) {
Vue.set(file.resolutionData, sectionId, selection);
file.inlineLines.forEach(line => {
if (line.id === sectionId && (line.hasConflict || line.isHeader)) {
this.markLine(line, selection);
}
});
file.parallelLines.forEach(lines => {
const left = lines[0];
const right = lines[1];
const hasSameId = right.id === sectionId || left.id === sectionId;
const isLeftMatch = left.hasConflict || left.isHeader;
const isRightMatch = right.hasConflict || right.isHeader;
if (hasSameId && (isLeftMatch || isRightMatch)) {
this.markLine(left, selection);
this.markLine(right, selection);
}
});
},
markLine(line, selection) {
if (selection === 'head' && line.isHead) {
line.isSelected = true;
line.isUnselected = false;
} else if (selection === 'origin' && line.isOrigin) {
line.isSelected = true;
line.isUnselected = false;
} else {
line.isSelected = false;
line.isUnselected = true;
}
},
setSubmitState(state) {
this.state.isSubmitting = state;
},
fileTextTypePresent() {
return this.state.conflictsData.files.some(f => f.type === CONFLICT_TYPES.TEXT);
},
};
})(window.gl || (window.gl = {}));