diff options
8 files changed, 94 insertions, 13 deletions
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: ` - <div class="mr-widget-body"> - <button - type="button" - class="btn btn-success btn-small" - disabled="true"> - Merge - </button> - <span class="bold"> - There is nothing to merge from source branch into target branch. - Please push new commits or use a different branch. - </span> + <div class="mr-widget-body empty-state"> + <div class="row"> + <div class="artwork col-sm-5 col-sm-push-7 col-xs-12 text-center"> + <span v-html="emptyStateSVG"></span> + </div> + <div class="text col-sm-7 col-sm-pull-5 col-xs-12"> + <span> + Merge requests are a place to propose changes you have made to a project + and discuss those changes with others. + </span> + <p> + Interested parties can even contribute by pushing commits if they want to. + </p> + <p> + Currently there are no changes in this merge request's source branch. + Please push new commits or use a different branch. + </p> + <a + v-if="mr.newBlobPath" + :href="mr.newBlobPath" + class="btn btn-inverted btn-save"> + Create file + </a> + </div> + </div> </div> `, }; 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 @@ +<svg width="256" height="146" viewBox="0 0 256 146" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><title>illustration</title><defs><rect id="a" width="178.714" height="115.389" rx="10"/><mask id="d" x="0" y="0" width="178.714" height="115.389" fill="#fff"><use xlink:href="#a"/></mask><path d="M8.796 31.515c.395.047.8.072 1.207.072h23.065c5.536 0 10.003-4.475 10.003-9.994v-11.6C43.07 4.476 38.594 0 33.07 0H10.003C4.467 0 0 4.475 0 9.994v11.6c0 1.248.23 2.444.65 3.547H0v7.414c0 4.094 2.394 5.113 5.342 2.28l3.454-3.32z" id="b"/><mask id="e" x="0" y="0" width="43.071" height="36.437" fill="#fff"><use xlink:href="#b"/></mask><path d="M8.796 31.515c.395.047.8.072 1.207.072h23.065c5.536 0 10.003-4.475 10.003-9.994v-11.6C43.07 4.476 38.594 0 33.07 0H10.003C4.467 0 0 4.475 0 9.994v11.6c0 1.248.23 2.444.65 3.547H0v7.414c0 4.094 2.394 5.113 5.342 2.28l3.454-3.32z" id="c"/><mask id="f" x="0" y="0" width="43.071" height="36.437" fill="#fff"><use xlink:href="#c"/></mask></defs><g fill="none" fill-rule="evenodd"><g transform="translate(0 3.868)" fill="#F9F9F9"><rect x="19.286" width="77.143" height="14.182" rx="7.091"/><rect y="28.364" width="84.857" height="14.182" rx="7.091"/><rect x="133.714" y="42.546" width="122.143" height="14.182" rx="7.091"/><rect x="82.929" y="126.992" width="101.571" height="14.182" rx="7.091"/><rect x="42.429" y="99.273" width="101.571" height="14.182" rx="7.091"/><rect x="19.929" y="70.909" width="225" height="14.182" rx="7.091"/><path d="M98.37 14.182H13.488h13.81a7.098 7.098 0 0 1 7.094 7.09 7.09 7.09 0 0 1-7.094 7.092h-13.81 84.88-23.452a7.098 7.098 0 0 1-7.095-7.09 7.09 7.09 0 0 1 7.096-7.092h23.452zm162 42.545h-75.238 23.452a7.098 7.098 0 0 1 7.095 7.09 7.09 7.09 0 0 1-7.096 7.092h-23.452 75.237-23.453a7.098 7.098 0 0 1-7.095-7.09 7.09 7.09 0 0 1 7.095-7.093h23.452zM103.512 85.09H28.275h23.452a7.098 7.098 0 0 1 7.095 7.092 7.09 7.09 0 0 1-7.095 7.09H28.275h75.237H80.06a7.098 7.098 0 0 1-7.095-7.09 7.09 7.09 0 0 1 7.095-7.09h23.452zm48.215 28.365H76.49 90.3a7.098 7.098 0 0 1 7.093 7.09 7.09 7.09 0 0 1-7.094 7.092H76.49h75.237-33.096a7.098 7.098 0 0 1-7.094-7.09 7.09 7.09 0 0 1 7.095-7.092h33.097z"/></g><g transform="translate(38.57 12.248)"><use stroke="#EEE" mask="url(#d)" stroke-width="8" fill="#FFF" xlink:href="#a"/><path fill="#EEE" d="M2.57 18.694h174.215v2.58H2.57z"/><g transform="translate(21.857 38.678)"><rect fill="#B5A7DD" y=".645" width="3.857" height="1.289" rx=".645"/><rect fill="#EEE" x="9.643" width="9.643" height="2.579" rx="1.289"/><rect fill="#EEE" x="46.286" width="9.643" height="2.579" rx="1.289"/><rect fill="#EEE" x="25.071" y="14.182" width="9.643" height="2.579" rx="1.289"/><rect fill="#FC6D26" x="34.071" y="7.091" width="9.643" height="2.579" rx="1.289"/><rect fill="#FC6D26" opacity=".5" x="30.857" width="12.857" height="2.579" rx="1.289"/><rect fill="#EEE" x="9.643" y="14.182" width="12.857" height="2.579" rx="1.289"/><rect fill="#EEE" x="18.643" y="7.091" width="12.857" height="2.579" rx="1.289"/><rect fill="#FC6D26" x="21.857" width="6.429" height="2.579" rx="1.289"/><rect fill="#EEE" x="9.643" y="7.091" width="6.429" height="2.579" rx="1.289"/><rect fill="#B5A7DD" y="7.736" width="3.857" height="1.289" rx=".645"/><rect fill="#B5A7DD" y="14.826" width="3.857" height="1.289" rx=".645"/></g><g transform="translate(21.857 59.95)"><rect fill="#B5A7DD" y=".645" width="3.857" height="1.289" rx=".645"/><rect fill="#FC6D26" x="9.643" width="9.643" height="2.579" rx="1.289"/><rect fill="#EEE" x="46.286" width="9.643" height="2.579" rx="1.289"/><rect fill="#FC6D26" opacity=".5" x="25.071" y="14.182" width="9.643" height="2.579" rx="1.289"/><rect fill="#EEE" x="34.071" y="7.091" width="9.643" height="2.579" rx="1.289"/><rect fill="#FC6D26" x="30.857" width="12.857" height="2.579" rx="1.289"/><rect fill="#FC6D26" x="9.643" y="14.182" width="12.857" height="2.579" rx="1.289"/><rect fill="#EEE" x="18.643" y="7.091" width="12.857" height="2.579" rx="1.289"/><rect fill="#FC6D26" opacity=".5" x="21.857" width="6.429" height="2.579" rx="1.289"/><rect fill="#EEE" x="9.643" y="7.091" width="6.429" height="2.579" rx="1.289"/><rect fill="#B5A7DD" y="7.736" width="3.857" height="1.289" rx=".645"/><rect fill="#B5A7DD" y="14.826" width="3.857" height="1.289" rx=".645"/></g><g transform="translate(21.857 81.223)"><rect fill="#B5A7DD" y=".645" width="3.857" height="1.289" rx=".645"/><rect fill="#EEE" x="9.643" width="9.643" height="2.579" rx="1.289"/><rect fill="#EEE" x="46.286" width="9.643" height="2.579" rx="1.289"/><rect fill="#EEE" x="25.071" y="14.182" width="9.643" height="2.579" rx="1.289"/><rect fill="#EEE" x="34.071" y="7.091" width="9.643" height="2.579" rx="1.289"/><rect fill="#FC6D26" x="30.857" width="12.857" height="2.579" rx="1.289"/><rect fill="#EEE" x="9.643" y="14.182" width="12.857" height="2.579" rx="1.289"/><rect fill="#EEE" x="18.643" y="7.091" width="12.857" height="2.579" rx="1.289"/><rect fill="#FC6D26" opacity=".5" x="21.857" width="6.429" height="2.579" rx="1.289"/><rect fill="#EEE" x="9.643" y="7.091" width="6.429" height="2.579" rx="1.289"/><rect fill="#B5A7DD" y="7.736" width="3.857" height="1.289" rx=".645"/><rect fill="#B5A7DD" y="14.826" width="3.857" height="1.289" rx=".645"/></g><g transform="translate(100.93 38.033)"><rect fill="#FDE5D8" y=".645" width="3.857" height="1.289" rx=".645"/><rect fill="#EEE" x="9.643" width="9.643" height="2.579" rx="1.289"/><rect fill="#EEE" x="46.286" width="9.643" height="2.579" rx="1.289"/><rect fill="#6B4FBB" opacity=".5" x="25.071" y="14.182" width="9.643" height="2.579" rx="1.289"/><rect fill="#6B4FBB" x="34.071" y="7.091" width="9.643" height="2.579" rx="1.289"/><rect fill="#6B4FBB" opacity=".5" x="30.857" width="12.857" height="2.579" rx="1.289"/><rect fill="#6B4FBB" x="9.643" y="14.182" width="12.857" height="2.579" rx="1.289"/><rect fill="#EEE" x="18.643" y="7.091" width="12.857" height="2.579" rx="1.289"/><rect fill="#6B4FBB" x="21.857" width="6.429" height="2.579" rx="1.289"/><rect fill="#EEE" x="9.643" y="7.091" width="6.429" height="2.579" rx="1.289"/><rect fill="#FDE5D8" y="7.736" width="3.857" height="1.289" rx=".645"/><rect fill="#FDE5D8" y="14.826" width="3.857" height="1.289" rx=".645"/><rect fill="#FDE5D8" y="21.917" width="3.857" height="1.289" rx=".645"/><rect fill="#EEE" x="9.643" y="21.273" width="9.643" height="2.579" rx="1.289"/><rect fill="#EEE" x="37.286" y="14.182" width="9.643" height="2.579" rx="1.289"/><rect fill="#6B4FBB" opacity=".5" x="25.071" y="35.455" width="9.643" height="2.579" rx="1.289"/><rect fill="#6B4FBB" x="18.643" y="28.364" width="9.643" height="2.579" rx="1.289"/><rect fill="#6B4FBB" x="30.857" y="21.273" width="12.857" height="2.579" rx="1.289"/><rect fill="#EEE" x="9.643" y="35.455" width="12.857" height="2.579" rx="1.289"/><rect fill="#EEE" x="21.857" y="21.273" width="6.429" height="2.579" rx="1.289"/><rect fill="#EEE" x="9.643" y="28.364" width="6.429" height="2.579" rx="1.289"/><rect fill="#EEE" x="30.857" y="28.364" width="6.429" height="2.579" rx="1.289"/><rect fill="#EEE" x="39.857" y="28.364" width="6.429" height="2.579" rx="1.289"/><rect fill="#EEE" x="49.5" y="14.182" width="6.429" height="2.579" rx="1.289"/><rect fill="#FDE5D8" y="29.008" width="3.857" height="1.289" rx=".645"/><rect fill="#FDE5D8" y="36.099" width="3.857" height="1.289" rx=".645"/><rect fill="#FDE5D8" y="43.19" width="3.857" height="1.289" rx=".645"/><rect fill="#6B4FBB" x="9.643" y="42.546" width="9.643" height="2.579" rx="1.289"/><rect fill="#EEE" x="25.071" y="56.727" width="9.643" height="2.579" rx="1.289"/><rect fill="#6B4FBB" opacity=".5" x="34.071" y="49.636" width="9.643" height="2.579" rx="1.289"/><rect fill="#EEE" x="9.643" y="56.727" width="12.857" height="2.579" rx="1.289"/><rect fill="#6B4FBB" x="18.643" y="49.636" width="12.857" height="2.579" rx="1.289"/><rect fill="#EEE" x="21.857" y="42.546" width="6.429" height="2.579" rx="1.289"/><rect fill="#EEE" x="46.286" y="49.636" width="6.429" height="2.579" rx="1.289"/><rect fill="#EEE" x="9.643" y="49.636" width="6.429" height="2.579" rx="1.289"/><rect fill="#FDE5D8" y="50.281" width="3.857" height="1.289" rx=".645"/><rect fill="#FDE5D8" y="57.372" width="3.857" height="1.289" rx=".645"/></g></g><g transform="translate(196.07)"><use stroke="#FDE5D8" mask="url(#e)" stroke-width="8" fill="#FFF" xlink:href="#b"/><rect fill="#FDB692" x="9" y="9.025" width="18.643" height="1.934" rx=".967"/><rect fill="#FDB692" x="9" y="14.826" width="25.071" height="1.934" rx=".967"/><rect fill="#FDB692" x="9" y="20.628" width="18.643" height="1.934" rx=".967"/></g><g transform="translate(189 41.256)"><ellipse stroke="#FC6D26" stroke-width="3" fill="#FFF7F4" cx="10.286" cy="9.669" rx="9.643" ry="9.669"/><path d="M.023 9.002a8.352 8.352 0 0 0 7.94-4.308M9 .644c0-.21-.008-.416-.023-.62" stroke="#FC6D26" stroke-width="2"/><path d="M5.045 2.008A10.266 10.266 0 0 0 13.5 6.446c2.112 0 4.076-.638 5.71-1.733" stroke="#FC6D26" stroke-width="2"/><ellipse fill="#FC6D26" cx="6.75" cy="11.281" rx=".964" ry=".967"/><ellipse fill="#FC6D26" cx="13.821" cy="11.281" rx=".964" ry=".967"/></g><g transform="translate(46.93 96.05)"><ellipse stroke="#6B4FBB" stroke-width="3" fill="#F4F1FA" cx="9.643" cy="10.314" rx="9.643" ry="9.669"/><path d="M12.86 4.51h-.005L11.25 2.58 9.645 4.51H9.64L8.036 2.58 6.43 4.51h-.002L4.82 2.58 3.215 4.512h-1.75A9.646 9.646 0 0 1 9.642 0c3.447 0 6.47 1.8 8.176 4.508h-1.75l-1.605-1.93L12.86 4.51z" fill="#6B4FBB"/><ellipse fill="#6B4FBB" cx="6.107" cy="11.281" rx=".964" ry=".967"/><ellipse fill="#6B4FBB" cx="13.179" cy="11.281" rx=".964" ry=".967"/></g><g transform="matrix(-1 0 0 1 56.57 54.794)"><use stroke="#E2DCF2" mask="url(#f)" stroke-width="8" fill="#FFF" xlink:href="#c"/><rect fill="#6B4FBB" opacity=".5" x="15.429" y="9.025" width="18.643" height="1.934" rx=".967"/><rect fill="#6B4FBB" opacity=".5" x="21.857" y="14.826" width="12.214" height="1.934" rx=".967"/><rect fill="#6B4FBB" opacity=".5" x="21.857" y="20.628" width="12.214" height="1.934" rx=".967"/></g></g></svg> 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' } |