diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_nothing_to_merge.js b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_nothing_to_merge.js
index 8c4535f1337..375a382615a 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_nothing_to_merge.js
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_nothing_to_merge.js
@@ -1,17 +1,42 @@
+import emptyStateSVG from 'icons/_mr_widget_empty_state.svg';
+
export default {
name: 'MRWidgetNothingToMerge',
+ props: {
+ mr: {
+ type: Object,
+ required: true,
+ },
+ },
+ data() {
+ return { emptyStateSVG };
+ },
template: `
-
-
-
- There is nothing to merge from source branch into target branch.
- Please push new commits or use a different branch.
-
+
+
+
+
+
+
+
+ Merge requests are a place to propose changes you have made to a project
+ and discuss those changes with others.
+
+
+ Interested parties can even contribute by pushing commits if they want to.
+
+
+ Currently there are no changes in this merge request's source branch.
+ Please push new commits or use a different branch.
+
+
+ Create file
+
+
+
`,
};
diff --git a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
index 05e67706983..06661b930e3 100644
--- a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
+++ b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
@@ -58,6 +58,7 @@ export default class MergeRequestStore {
this.statusPath = data.status_path;
this.emailPatchesPath = data.email_patches_path;
this.plainDiffPath = data.plain_diff_path;
+ this.newBlobPath = data.new_blob_path;
this.createIssueToResolveDiscussionsPath = data.create_issue_to_resolve_discussions_path;
this.mergeCheckPath = data.merge_check_path;
this.mergeActionsContentPath = data.commit_change_content_path;
diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss
index fa9d05ee8fd..e5adca658ba 100644
--- a/app/assets/stylesheets/pages/merge_requests.scss
+++ b/app/assets/stylesheets/pages/merge_requests.scss
@@ -353,6 +353,22 @@
margin-top: 10px;
margin-left: 12px;
}
+
+ &.empty-state {
+ .artwork {
+ margin-bottom: $gl-padding;
+ }
+
+ .text {
+ span {
+ font-weight: bold;
+ }
+
+ p {
+ margin-top: $gl-padding;
+ }
+ }
+ }
}
.mr-widget-footer {
diff --git a/app/serializers/merge_request_entity.rb b/app/serializers/merge_request_entity.rb
index a2542c54f7a..a49f4d834cd 100644
--- a/app/serializers/merge_request_entity.rb
+++ b/app/serializers/merge_request_entity.rb
@@ -97,6 +97,14 @@ class MergeRequestEntity < IssuableEntity
presenter(merge_request).target_branch_commits_path
end
+ expose :new_blob_path do |merge_request|
+ if can?(current_user, :push_code, merge_request.project)
+ namespace_project_new_blob_path(merge_request.project.namespace,
+ merge_request.project,
+ merge_request.source_branch)
+ end
+ end
+
expose :conflict_resolution_path do |merge_request|
presenter(merge_request).conflict_resolution_path
end
diff --git a/app/views/shared/icons/_mr_widget_empty_state.svg b/app/views/shared/icons/_mr_widget_empty_state.svg
new file mode 100644
index 00000000000..6a811893b2d
--- /dev/null
+++ b/app/views/shared/icons/_mr_widget_empty_state.svg
@@ -0,0 +1 @@
+
diff --git a/spec/fixtures/api/schemas/entities/merge_request.json b/spec/fixtures/api/schemas/entities/merge_request.json
index 0a7e0e2d5f2..e5df3e7b6d1 100644
--- a/spec/fixtures/api/schemas/entities/merge_request.json
+++ b/spec/fixtures/api/schemas/entities/merge_request.json
@@ -86,6 +86,7 @@
"email_patches_path": { "type": "string" },
"plain_diff_path": { "type": "string" },
"status_path": { "type": "string" },
+ "new_blob_path": { "type": "string" },
"merge_check_path": { "type": "string" },
"ci_environments_status_path": { "type": "string" },
"merge_commit_message_with_description": { "type": "string" },
diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_nothing_to_merge_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_nothing_to_merge_spec.js
index d40c67b189d..a8a02fa6b66 100644
--- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_nothing_to_merge_spec.js
+++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_nothing_to_merge_spec.js
@@ -4,14 +4,26 @@ import nothingToMergeComponent from '~/vue_merge_request_widget/components/state
describe('MRWidgetNothingToMerge', () => {
describe('template', () => {
const Component = Vue.extend(nothingToMergeComponent);
+ const newBlobPath = '/foo';
const vm = new Component({
el: document.createElement('div'),
+ propsData: {
+ mr: { newBlobPath },
+ },
});
+
it('should have correct elements', () => {
expect(vm.$el.classList.contains('mr-widget-body')).toBeTruthy();
- expect(vm.$el.querySelector('button').getAttribute('disabled')).toBeTruthy();
- expect(vm.$el.innerText).toContain('There is nothing to merge from source branch into target branch.');
+ expect(vm.$el.querySelector('a').href).toContain(newBlobPath);
+ expect(vm.$el.innerText).toContain('Currently there are no changes in this merge request\'s source branch');
expect(vm.$el.innerText).toContain('Please push new commits or use a different branch.');
});
+
+ it('should not show new blob link if there is no link available', () => {
+ vm.mr.newBlobPath = null;
+ Vue.nextTick(() => {
+ expect(vm.$el.querySelector('a')).toEqual(null);
+ });
+ });
});
});
diff --git a/spec/serializers/merge_request_entity_spec.rb b/spec/serializers/merge_request_entity_spec.rb
index bb6e83ae4bd..b75c73e78c2 100644
--- a/spec/serializers/merge_request_entity_spec.rb
+++ b/spec/serializers/merge_request_entity_spec.rb
@@ -65,6 +65,23 @@ describe MergeRequestEntity do
.to eq(resource.merge_commit_message(include_description: true))
end
+ describe 'new_blob_path' do
+ context 'when user can push to project' do
+ it 'returns path' do
+ project.add_developer(user)
+
+ expect(subject[:new_blob_path])
+ .to eq("/#{resource.project.full_path}/new/#{resource.source_branch}")
+ end
+ end
+
+ context 'when user cannot push to project' do
+ it 'returns nil' do
+ expect(subject[:new_blob_path]).to be_nil
+ end
+ end
+ end
+
describe 'diff_head_sha' do
before do
allow(resource).to receive(:diff_head_sha) { 'sha' }