Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Jérome Perrin
gitlab-ce
Commits
197ac5eb
Commit
197ac5eb
authored
Sep 29, 2016
by
Alfredo Sumaran
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Ability to resolve conflicts for files with `text-editor` as conflict type
parent
a8ac9089
Changes
7
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
213 additions
and
159 deletions
+213
-159
app/assets/javascripts/merge_conflicts/components/diff_file_editor.js.es6
...cripts/merge_conflicts/components/diff_file_editor.js.es6
+24
-19
app/assets/javascripts/merge_conflicts/merge_conflict_store.js.es6
...s/javascripts/merge_conflicts/merge_conflict_store.js.es6
+126
-114
app/views/projects/merge_requests/conflicts/_diff_file_editor.html.haml
...ects/merge_requests/conflicts/_diff_file_editor.html.haml
+2
-4
app/views/projects/merge_requests/conflicts/_file_actions.html.haml
...projects/merge_requests/conflicts/_file_actions.html.haml
+1
-1
app/views/projects/merge_requests/conflicts/_inline_view.html.haml
.../projects/merge_requests/conflicts/_inline_view.html.haml
+22
-19
app/views/projects/merge_requests/conflicts/_parallel_view.html.haml
...rojects/merge_requests/conflicts/_parallel_view.html.haml
+1
-1
spec/features/merge_requests/conflicts_spec.rb
spec/features/merge_requests/conflicts_spec.rb
+37
-1
No files found.
app/assets/javascripts/merge_conflicts/components/diff_file_editor.js.es6
View file @
197ac5eb
...
@@ -7,10 +7,10 @@
...
@@ -7,10 +7,10 @@
template: '#diff-file-editor',
template: '#diff-file-editor',
data() {
data() {
return {
return {
originalContent: '',
saved: false,
saved: false,
loading: false,
loading: false,
fileLoaded: false
fileLoaded: false,
originalContent: '',
}
}
},
},
computed: {
computed: {
...
@@ -23,43 +23,48 @@
...
@@ -23,43 +23,48 @@
}
}
},
},
watch: {
watch: {
loadFile(val) {
['file.showEditor'](val) {
const self = this;
this.resetEditorContent();
this.resetEditorContent();
if (!val || this.fileLoaded || this.loading) {
if (!val || this.fileLoaded || this.loading) {
return
return
;
}
}
this.loadEditor();
}
},
ready() {
if (this.file.loadEditor) {
this.loadEditor();
}
},
methods: {
loadEditor() {
this.loading = true;
this.loading = true;
$.get(this.file.content_path)
$.get(this.file.content_path)
.done((file) => {
.done((file) => {
let content = this.$el.querySelector('pre');
let content = self.$el.querySelector('pre');
let fileContent = document.createTextNode(file.content);
let fileContent = document.createTextNode(file.content);
content.textContent = fileContent.textContent;
content.textContent = fileContent.textContent;
self
.originalContent = file.content;
this
.originalContent = file.content;
self
.fileLoaded = true;
this
.fileLoaded = true;
self
.editor = ace.edit(content);
this
.editor = ace.edit(content);
self
.editor.$blockScrolling = Infinity; // Turn off annoying warning
this
.editor.$blockScrolling = Infinity; // Turn off annoying warning
self
.editor.on('change', () => {
this
.editor.on('change', () => {
self
.saveDiffResolution();
this
.saveDiffResolution();
});
});
self
.saveDiffResolution();
this
.saveDiffResolution();
})
})
.fail(() => {
.fail(() => {
console.log('error');
console.log('error');
})
})
.always(() => {
.always(() => {
self
.loading = false;
this
.loading = false;
});
});
}
},
},
methods: {
saveDiffResolution() {
saveDiffResolution() {
this.saved = true;
this.saved = true;
...
...
app/assets/javascripts/merge_conflicts/merge_conflict_store.js.es6
View file @
197ac5eb
...
@@ -13,6 +13,10 @@
...
@@ -13,6 +13,10 @@
INLINE: 'inline',
INLINE: 'inline',
PARALLEL: 'parallel'
PARALLEL: 'parallel'
};
};
const CONFLICT_TYPES = {
TEXT: 'text',
TEXT_EDITOR: 'text-editor'
};
global.mergeConflicts.mergeConflictsStore = {
global.mergeConflicts.mergeConflictsStore = {
state: {
state: {
...
@@ -26,8 +30,6 @@
...
@@ -26,8 +30,6 @@
setConflictsData(data) {
setConflictsData(data) {
this.decorateFiles(data.files);
this.decorateFiles(data.files);
this.setInlineLines(data.files);
this.setParallelLines(data.files);
this.state.conflictsData = {
this.state.conflictsData = {
files: data.files,
files: data.files,
...
@@ -45,14 +47,24 @@
...
@@ -45,14 +47,24 @@
file.resolutionData = {};
file.resolutionData = {};
file.promptDiscardConfirmation = false;
file.promptDiscardConfirmation = false;
file.resolveMode = DEFAULT_RESOLVE_MODE;
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;
}
});
});
},
},
setInlineLines(files) {
setInlineLine(file) {
files.forEach((file) => {
file.iconClass = `fa-${file.blob_icon}`;
file.blobPath = file.blob_path;
file.filePath = this.getFilePath(file);
file.inlineLines = [];
file.inlineLines = [];
file.sections.forEach((section) => {
file.sections.forEach((section) => {
...
@@ -79,14 +91,9 @@
...
@@ -79,14 +91,9 @@
file.inlineLines.push(this.getOriginHeaderLine(id));
file.inlineLines.push(this.getOriginHeaderLine(id));
}
}
});
});
});
},
},
setParallelLines(files) {
setParallelLine(file) {
files.forEach((file) => {
file.filePath = this.getFilePath(file);
file.iconClass = `fa-${file.blob_icon}`;
file.blobPath = file.blob_path;
file.parallelLines = [];
file.parallelLines = [];
const linesObj = { left: [], right: [] };
const linesObj = { left: [], right: [] };
...
@@ -104,12 +111,10 @@
...
@@ -104,12 +111,10 @@
if (conflict) {
if (conflict) {
if (type === 'old') {
if (type === 'old') {
linesObj.left.push(this.getLineForParallelView(line, id, 'conflict'));
linesObj.left.push(this.getLineForParallelView(line, id, 'conflict'));
}
} else if (type === 'new') {
else if (type === 'new') {
linesObj.right.push(this.getLineForParallelView(line, id, 'conflict', true));
linesObj.right.push(this.getLineForParallelView(line, id, 'conflict', true));
}
}
}
} else {
else {
const lineType = type || 'context';
const lineType = type || 'context';
linesObj.left.push (this.getLineForParallelView(line, id, lineType));
linesObj.left.push (this.getLineForParallelView(line, id, lineType));
...
@@ -126,9 +131,6 @@
...
@@ -126,9 +131,6 @@
linesObj.left[i]
linesObj.left[i]
]);
]);
}
}
return file;
});
},
},
setLoadingState(state) {
setLoadingState(state) {
...
@@ -140,13 +142,12 @@
...
@@ -140,13 +142,12 @@
},
},
setFailedRequest(message) {
setFailedRequest(message) {
console.log('setFailedRequest');
this.state.hasError = true;
this.state.hasError = true;
this.state.conflictsData.errorMessage = message;
this.state.conflictsData.errorMessage = message;
},
},
getConflictsCount() {
getConflictsCount() {
if (!this.state.conflictsData.files) {
if (!this.state.conflictsData.files
.length
) {
return 0;
return 0;
}
}
...
@@ -154,11 +155,15 @@
...
@@ -154,11 +155,15 @@
let count = 0;
let count = 0;
files.forEach((file) => {
files.forEach((file) => {
if (file.type === CONFLICT_TYPES.TEXT) {
file.sections.forEach((section) => {
file.sections.forEach((section) => {
if (section.conflict) {
if (section.conflict) {
count++;
count++;
}
}
});
});
} else {
count++;
}
});
});
return count;
return count;
...
@@ -253,8 +258,7 @@
...
@@ -253,8 +258,7 @@
for (let i = 0; i < diff; i++) {
for (let i = 0; i < diff; i++) {
right.push({ lineType: 'emptyLine', richText: '' });
right.push({ lineType: 'emptyLine', richText: '' });
}
}
}
} else {
else {
const diff = right.length - left.length;
const diff = right.length - left.length;
for (let i = 0; i < diff; i++) {
for (let i = 0; i < diff; i++) {
left.push({ lineType: 'emptyLine', richText: '' });
left.push({ lineType: 'emptyLine', richText: '' });
...
@@ -268,8 +272,12 @@
...
@@ -268,8 +272,12 @@
},
},
setFileResolveMode(file, mode) {
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
// Restore Interactive mode when switching to Edit mode
if (mode === EDIT_RESOLVE_MODE) {
file.showEditor = true;
file.loadEditor = true;
file.resolutionData = {};
file.resolutionData = {};
this.restoreFileLinesState(file);
this.restoreFileLinesState(file);
...
@@ -313,6 +321,8 @@
...
@@ -313,6 +321,8 @@
let numberConflicts = 0;
let numberConflicts = 0;
let resolvedConflicts = Object.keys(file.resolutionData).length
let resolvedConflicts = Object.keys(file.resolutionData).length
// We only check if
if (file.type === CONFLICT_TYPES.TEXT) {
for (let j = 0, k = file.sections.length; j < k; j++) {
for (let j = 0, k = file.sections.length; j < k; j++) {
if (file.sections[j].conflict) {
if (file.sections[j].conflict) {
numberConflicts++;
numberConflicts++;
...
@@ -322,6 +332,7 @@
...
@@ -322,6 +332,7 @@
if (resolvedConflicts !== numberConflicts) {
if (resolvedConflicts !== numberConflicts) {
unresolved++;
unresolved++;
}
}
}
} else if (file.resolveMode === EDIT_RESOLVE_MODE) {
} else if (file.resolveMode === EDIT_RESOLVE_MODE) {
// Unlikely to happen since switching to Edit mode saves content automatically.
// Unlikely to happen since switching to Edit mode saves content automatically.
// Checking anyway in case the save strategy changes in the future
// Checking anyway in case the save strategy changes in the future
...
@@ -358,12 +369,17 @@
...
@@ -358,12 +369,17 @@
new_path: file.new_path
new_path: file.new_path
};
};
if (file.type === CONFLICT_TYPES.TEXT) {
// Submit only one data for type of editing
// Submit only one data for type of editing
if (file.resolveMode === INTERACTIVE_RESOLVE_MODE) {
if (file.resolveMode === INTERACTIVE_RESOLVE_MODE) {
addFile.sections = file.resolutionData;
addFile.sections = file.resolutionData;
} else if (file.resolveMode === EDIT_RESOLVE_MODE) {
} else if (file.resolveMode === EDIT_RESOLVE_MODE) {
addFile.content = file.content;
addFile.content = file.content;
}
}
} else if (file.type === CONFLICT_TYPES.TEXT_EDITOR) {
addFile.content = file.content;
}
commitData.files.push(addFile);
commitData.files.push(addFile);
});
});
...
@@ -374,7 +390,6 @@
...
@@ -374,7 +390,6 @@
handleSelected(file, sectionId, selection) {
handleSelected(file, sectionId, selection) {
Vue.set(file.resolutionData, sectionId, selection);
Vue.set(file.resolutionData, sectionId, selection);
this.state.conflictsData.files.forEach((file) => {
file.inlineLines.forEach((line) => {
file.inlineLines.forEach((line) => {
if (line.id === sectionId && (line.hasConflict || line.isHeader)) {
if (line.id === sectionId && (line.hasConflict || line.isHeader)) {
this.markLine(line, selection);
this.markLine(line, selection);
...
@@ -392,7 +407,6 @@
...
@@ -392,7 +407,6 @@
this.markLine(left, selection);
this.markLine(left, selection);
this.markLine(right, selection);
this.markLine(right, selection);
}
}
})
});
});
},
},
...
@@ -400,12 +414,10 @@
...
@@ -400,12 +414,10 @@
if (selection === 'head' && line.isHead) {
if (selection === 'head' && line.isHead) {
line.isSelected = true;
line.isSelected = true;
line.isUnselected = false;
line.isUnselected = false;
}
} else if (selection === 'origin' && line.isOrigin) {
else if (selection === 'origin' && line.isOrigin) {
line.isSelected = true;
line.isSelected = true;
line.isUnselected = false;
line.isUnselected = false;
}
} else {
else {
line.isSelected = false;
line.isSelected = false;
line.isUnselected = true;
line.isUnselected = true;
}
}
...
...
app/views/projects/merge_requests/conflicts/_diff_file_editor.html.haml
View file @
197ac5eb
-
if_condition
=
local_assigns
.
fetch
(
:if_condition
,
''
)
.diff-editor-wrap
{
"v-show"
=>
"file.showEditor"
}
.diff-editor-wrap
{
"v-show"
=>
if_condition
}
.discard-changes-alert-wrap
{
"v-if"
=>
"file.promptDiscardConfirmation"
}
.discard-changes-alert-wrap
{
"v-if"
=>
"file.promptDiscardConfirmation"
}
.discard-changes-alert
.discard-changes-alert
Are you sure to discard your changes?
Are you sure to discard your changes?
.discard-actions
.discard-actions
%button
.btn.btn-sm.btn-close
{
"@click"
=>
"acceptDiscardConfirmation(file)"
}
Discard changes
%button
.btn.btn-sm.btn-close
{
"@click"
=>
"acceptDiscardConfirmation(file)"
}
Discard changes
%button
.btn.btn-sm
{
"@click"
=>
"cancelDiscardConfirmation(file)"
}
Cancel
%button
.btn.btn-sm
{
"@click"
=>
"cancelDiscardConfirmation(file)"
}
Cancel
%diff-file-editor
{
":file"
=>
"file"
,
":load-file"
=>
if_condition
}
%diff-file-editor
{
":file"
=>
"file"
}
app/views/projects/merge_requests/conflicts/_file_actions.html.haml
View file @
197ac5eb
.file-actions
.file-actions
.btn-group
.btn-group
{
"v-if"
=>
"file.type === 'text'"
}
%button
.btn
{
":class"
=>
"{ 'active': file.resolveMode == 'interactive' }"
,
%button
.btn
{
":class"
=>
"{ 'active': file.resolveMode == 'interactive' }"
,
'@click'
=>
"onClickResolveModeButton(file, 'interactive')"
,
'@click'
=>
"onClickResolveModeButton(file, 'interactive')"
,
type:
'button'
}
type:
'button'
}
...
...
app/views/projects/merge_requests/conflicts/_inline_view.html.haml
View file @
197ac5eb
...
@@ -4,6 +4,7 @@
...
@@ -4,6 +4,7 @@
%i
.fa.fa-fw
{
":class"
=>
"file.iconClass"
}
%i
.fa.fa-fw
{
":class"
=>
"file.iconClass"
}
%strong
{{file.filePath}}
%strong
{{file.filePath}}
=
render
partial:
'projects/merge_requests/conflicts/file_actions'
=
render
partial:
'projects/merge_requests/conflicts/file_actions'
%template
{
"v-if"
=>
"file.type === 'text'"
}
.diff-content.diff-wrap-lines
.diff-content.diff-wrap-lines
.diff-wrap-lines.code.file-content.js-syntax-highlight
{
'v-show'
=>
"file.resolveMode === 'interactive'"
}
.diff-wrap-lines.code.file-content.js-syntax-highlight
{
'v-show'
=>
"file.resolveMode === 'interactive'"
}
%table
%table
...
@@ -23,4 +24,6 @@
...
@@ -23,4 +24,6 @@
%strong
{{{line.richText}}}
%strong
{{{line.richText}}}
%button
.btn
{
"@click"
=>
"handleSelected(file, line.id, line.section)"
}
%button
.btn
{
"@click"
=>
"handleSelected(file, line.id, line.section)"
}
{{line.buttonTitle}}
{{line.buttonTitle}}
=
render
partial:
'projects/merge_requests/conflicts/diff_file_editor'
,
locals:
{
if_condition:
"file.resolveMode === 'edit' && !isParallel"
}
=
render
partial:
'projects/merge_requests/conflicts/diff_file_editor'
%template
{
"v-else"
=>
true
}
=
render
partial:
'projects/merge_requests/conflicts/diff_file_editor'
app/views/projects/merge_requests/conflicts/_parallel_view.html.haml
View file @
197ac5eb
...
@@ -22,4 +22,4 @@
...
@@ -22,4 +22,4 @@
{{line.lineNumber}}
{{line.lineNumber}}
%td
.line_content.parallel
{
":class"
=>
class_bindings
}
%td
.line_content.parallel
{
":class"
=>
class_bindings
}
{{{line.richText}}}
{{{line.richText}}}
=
render
partial:
'projects/merge_requests/conflicts/diff_file_editor'
,
locals:
{
if_condition:
"file.
resolveMode === 'edit'
&& isParallel"
}
=
render
partial:
'projects/merge_requests/conflicts/diff_file_editor'
,
locals:
{
if_condition:
"file.
loadFile
&& isParallel"
}
spec/features/merge_requests/conflicts_spec.rb
View file @
197ac5eb
...
@@ -66,6 +66,42 @@ feature 'Merge request conflict resolution', js: true, feature: true do
...
@@ -66,6 +66,42 @@ feature 'Merge request conflict resolution', js: true, feature: true do
end
end
end
end
context
'when a merge request can be resolved in the UI'
do
let
(
:merge_request
)
{
create_merge_request
(
'conflict-contains-conflict-markers'
)
}
before
do
project
.
team
<<
[
user
,
:developer
]
login_as
(
user
)
visit
namespace_project_merge_request_path
(
project
.
namespace
,
project
,
merge_request
)
end
context
'a conflict contain markers'
do
before
{
click_link
(
'conflicts'
,
href:
/\/conflicts\Z/
)
}
it
'resolves files manually'
do
within
find
(
'.files-wrapper .diff-file.inline-view'
,
text:
'files/markdown/ruby-style-guide.md'
)
do
wait_for_ajax
execute_script
(
'ace.edit($(".files-wrapper .diff-file.inline-view pre")[0]).setValue("Gregor Samsa woke from troubled dreams");'
)
end
click_button
'Commit conflict resolution'
wait_for_ajax
expect
(
page
).
to
have_content
(
'All merge conflicts were resolved'
)
merge_request
.
reload_diff
click_on
'Changes'
wait_for_ajax
find
(
'.nothing-here-block'
,
visible:
true
).
click
wait_for_ajax
expect
(
page
).
to
have_content
(
'Gregor Samsa woke from troubled dreams'
)
end
end
end
UNRESOLVABLE_CONFLICTS
=
{
UNRESOLVABLE_CONFLICTS
=
{
'conflict-too-large'
=>
'when the conflicts contain a large file'
,
'conflict-too-large'
=>
'when the conflicts contain a large file'
,
'conflict-binary-file'
=>
'when the conflicts contain a binary file'
,
'conflict-binary-file'
=>
'when the conflicts contain a binary file'
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment