341 lines
8.6 KiB
JavaScript
341 lines
8.6 KiB
JavaScript
const HEAD_HEADER_TEXT = 'HEAD//our changes';
|
|
const ORIGIN_HEADER_TEXT = 'origin//their changes';
|
|
const HEAD_BUTTON_TITLE = 'Use ours';
|
|
const ORIGIN_BUTTON_TITLE = 'Use theirs';
|
|
|
|
|
|
class MergeConflictDataProvider {
|
|
|
|
getInitialData() {
|
|
const diffViewType = $.cookie('diff_view');
|
|
|
|
return {
|
|
isLoading : true,
|
|
hasError : false,
|
|
isParallel : diffViewType === 'parallel',
|
|
diffViewType : diffViewType,
|
|
isSubmitting : false,
|
|
conflictsData : {},
|
|
resolutionData : {}
|
|
}
|
|
}
|
|
|
|
|
|
decorateData(vueInstance, data) {
|
|
this.vueInstance = vueInstance;
|
|
|
|
if (data.type === 'error') {
|
|
vueInstance.hasError = true;
|
|
data.errorMessage = data.message;
|
|
}
|
|
else {
|
|
data.shortCommitSha = data.commit_sha.slice(0, 7);
|
|
data.commitMessage = data.commit_message;
|
|
|
|
this.setParallelLines(data);
|
|
this.setInlineLines(data);
|
|
this.updateResolutionsData(data);
|
|
}
|
|
|
|
vueInstance.conflictsData = data;
|
|
vueInstance.isSubmitting = false;
|
|
|
|
const conflictsText = this.getConflictsCount() > 1 ? 'conflicts' : 'conflict';
|
|
vueInstance.conflictsData.conflictsText = conflictsText;
|
|
}
|
|
|
|
|
|
updateResolutionsData(data) {
|
|
const vi = this.vueInstance;
|
|
|
|
data.files.forEach( (file) => {
|
|
file.sections.forEach( (section) => {
|
|
if (section.conflict) {
|
|
vi.$set(`resolutionData['${section.id}']`, false);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
|
|
setParallelLines(data) {
|
|
data.files.forEach( (file) => {
|
|
file.filePath = this.getFilePath(file);
|
|
file.iconClass = `fa-${file.blob_icon}`;
|
|
file.blobPath = file.blob_path;
|
|
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++) {
|
|
file.parallelLines.push([
|
|
linesObj.right[i],
|
|
linesObj.left[i]
|
|
]);
|
|
}
|
|
|
|
});
|
|
}
|
|
|
|
|
|
checkLineLengths(linesObj) {
|
|
let { 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++) {
|
|
right.push({ lineType: 'emptyLine', richText: '' });
|
|
}
|
|
}
|
|
else {
|
|
const diff = right.length - left.length;
|
|
for (let i = 0; i < diff; i++) {
|
|
left.push({ lineType: 'emptyLine', richText: '' });
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
setInlineLines(data) {
|
|
data.files.forEach( (file) => {
|
|
file.iconClass = `fa-${file.blob_icon}`;
|
|
file.blobPath = file.blob_path;
|
|
file.filePath = this.getFilePath(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));
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
|
|
handleSelected(sectionId, selection) {
|
|
const vi = this.vueInstance;
|
|
|
|
vi.resolutionData[sectionId] = selection;
|
|
vi.conflictsData.files.forEach( (file) => {
|
|
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);
|
|
}
|
|
})
|
|
});
|
|
}
|
|
|
|
|
|
updateViewType(newType) {
|
|
const vi = this.vueInstance;
|
|
|
|
if (newType === vi.diffView || !(newType === 'parallel' || newType === 'inline')) {
|
|
return;
|
|
}
|
|
|
|
vi.diffView = newType;
|
|
vi.isParallel = newType === 'parallel';
|
|
$.cookie('diff_view', newType); // TODO: Make sure that cookie path added.
|
|
$('.content-wrapper .container-fluid').toggleClass('container-limited');
|
|
}
|
|
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
|
|
getConflictsCount() {
|
|
return Object.keys(this.vueInstance.resolutionData).length;
|
|
}
|
|
|
|
|
|
getResolvedCount() {
|
|
let count = 0;
|
|
const data = this.vueInstance.resolutionData;
|
|
|
|
for (const id in data) {
|
|
const resolution = data[id];
|
|
if (resolution) {
|
|
count++;
|
|
}
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
|
|
isReadyToCommit() {
|
|
const { conflictsData, isSubmitting } = this.vueInstance
|
|
const allResolved = this.getConflictsCount() === this.getResolvedCount();
|
|
const hasCommitMessage = $.trim(conflictsData.commitMessage).length;
|
|
|
|
return !isSubmitting && hasCommitMessage && allResolved;
|
|
}
|
|
|
|
|
|
getCommitButtonText() {
|
|
const initial = 'Commit conflict resolution';
|
|
const inProgress = 'Committing...';
|
|
const vue = this.vueInstance;
|
|
|
|
return vue ? vue.isSubmitting ? inProgress : initial : initial;
|
|
}
|
|
|
|
|
|
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
|
|
}
|
|
}
|
|
|
|
|
|
getHeadHeaderLine(id) {
|
|
return {
|
|
id : id,
|
|
richText : HEAD_HEADER_TEXT,
|
|
buttonTitle : HEAD_BUTTON_TITLE,
|
|
type : 'new',
|
|
section : 'head',
|
|
isHeader : true,
|
|
isHead : true,
|
|
isSelected : false,
|
|
isUnselected: false
|
|
}
|
|
}
|
|
|
|
|
|
getOriginHeaderLine(id) {
|
|
return {
|
|
id : id,
|
|
richText : ORIGIN_HEADER_TEXT,
|
|
buttonTitle : ORIGIN_BUTTON_TITLE,
|
|
type : 'old',
|
|
section : 'origin',
|
|
isHeader : true,
|
|
isOrigin : true,
|
|
isSelected : false,
|
|
isUnselected: false
|
|
}
|
|
}
|
|
|
|
|
|
handleFailedRequest(vueInstance, data) {
|
|
vueInstance.hasError = true;
|
|
vueInstance.conflictsData.errorMessage = 'Something went wrong!';
|
|
}
|
|
|
|
|
|
getCommitData() {
|
|
return {
|
|
commit_message: this.vueInstance.conflictsData.commitMessage,
|
|
sections: this.vueInstance.resolutionData
|
|
}
|
|
}
|
|
|
|
|
|
getFilePath(file) {
|
|
const { old_path, new_path } = file;
|
|
return old_path === new_path ? new_path : `${old_path} → ${new_path}`;
|
|
}
|
|
|
|
}
|