Commit a881ffad authored by GitLab Bot's avatar GitLab Bot

Automatic merge of gitlab-org/gitlab-ce master

parents 389d54da 36d1d908
......@@ -23,7 +23,7 @@ export default {
type: Object,
required: true,
},
mouseOver: {
dropdownOpen: {
type: Boolean,
required: true,
},
......@@ -92,8 +92,9 @@ export default {
<new-dropdown
:type="file.type"
:path="file.path"
:mouse-over="mouseOver"
:is-open="dropdownOpen"
class="prepend-left-8"
v-on="$listeners"
/>
</div>
</template>
......@@ -21,38 +21,29 @@ export default {
required: false,
default: '',
},
mouseOver: {
isOpen: {
type: Boolean,
required: true,
required: false,
default: false,
},
},
data() {
return {
dropdownOpen: false,
};
},
watch: {
dropdownOpen() {
isOpen() {
this.$nextTick(() => {
this.$refs.dropdownMenu.scrollIntoView({
block: 'nearest',
});
});
},
mouseOver() {
if (!this.mouseOver) {
this.dropdownOpen = false;
}
},
},
methods: {
...mapActions(['createTempEntry', 'openNewEntryModal', 'deleteEntry']),
createNewItem(type) {
this.openNewEntryModal({ type, path: this.path });
this.dropdownOpen = false;
this.$emit('toggle', false);
},
openDropdown() {
this.dropdownOpen = !this.dropdownOpen;
this.$emit('toggle', !this.isOpen);
},
},
modalTypes,
......@@ -63,7 +54,7 @@ export default {
<div class="ide-new-btn">
<div
:class="{
show: dropdownOpen,
show: isOpen,
}"
class="dropdown d-flex"
>
......
......@@ -4,10 +4,11 @@ import service from '../../services';
import * as types from '../mutation_types';
import { activityBarViews } from '../../constants';
export const getMergeRequestsForBranch = ({ commit }, { projectId, branchId } = {}) =>
export const getMergeRequestsForBranch = ({ commit, state }, { projectId, branchId } = {}) =>
service
.getProjectMergeRequests(`${projectId}`, {
source_branch: branchId,
source_project_id: state.projects[projectId].id,
order_by: 'created_at',
per_page: 1,
})
......
......@@ -39,7 +39,7 @@ export default {
},
data() {
return {
mouseOver: false,
dropdownOpen: false,
};
},
computed: {
......@@ -123,8 +123,8 @@ export default {
return this.$router.currentRoute.path === `/project${this.file.url}`;
},
toggleHover(over) {
this.mouseOver = over;
toggleDropdown(val) {
this.dropdownOpen = val;
},
},
};
......@@ -140,8 +140,7 @@ export default {
class="file-row"
role="button"
@click="clickFile"
@mouseover="toggleHover(true)"
@mouseout="toggleHover(false)"
@mouseleave="toggleDropdown(false)"
>
<div class="file-row-name-container">
<span ref="textOutput" :style="levelIndentation" class="file-row-name str-truncated">
......@@ -160,7 +159,8 @@ export default {
:is="extraComponent"
v-if="extraComponent && !(hideExtraOnTree && file.type === 'tree')"
:file="file"
:mouse-over="mouseOver"
:dropdown-open="dropdownOpen"
@toggle="toggleDropdown($event)"
/>
</div>
</div>
......
......@@ -167,6 +167,23 @@
}
}
.frame {
top: 0;
right: 0;
&.old-diff {
/* only for commit / compare view */
position: absolute;
}
&.deleted {
margin: 0;
display: block;
top: 13px;
right: 7px;
}
}
.swipe-bar {
display: block;
height: 100%;
......
......@@ -40,7 +40,8 @@ class MergeRequestsFinder < IssuableFinder
items = by_commit(super)
items = by_source_branch(items)
items = by_wip(items)
by_target_branch(items)
items = by_target_branch(items)
by_source_project_id(items)
end
private
......@@ -74,6 +75,16 @@ class MergeRequestsFinder < IssuableFinder
items.where(target_branch: target_branch)
end
def source_project_id
@source_project_id ||= params[:source_project_id].presence
end
def by_source_project_id(items)
return items unless source_project_id
items.where(source_project_id: source_project_id)
end
def by_wip(items)
if params[:wip] == 'yes'
items.where(wip_match(items.arel_table))
......
......@@ -35,10 +35,10 @@
.swipe.view.hide
.swipe-frame
.frame.deleted
.frame.deleted.old-diff
= image_tag(old_blob_raw_url, alt: diff_file.old_path, lazy: false)
.swipe-wrap.left-oriented
= render partial: "projects/diffs/image_diff_frame", locals: { class_name: "added js-image-frame #{class_name}", position: position, note_type: DiffNote.name, image_path: blob_raw_url, alt: diff_file.new_path }
= render partial: "projects/diffs/image_diff_frame", locals: { class_name: "added old-diff js-image-frame #{class_name}", position: position, note_type: DiffNote.name, image_path: blob_raw_url, alt: diff_file.new_path }
%span.swipe-bar
%span.top-handle
%span.bottom-handle
......
......@@ -10,5 +10,5 @@
.image.js-single-image{ data: diff_view_data }
.wrap
- single_class_name = diff_file.deleted_file? ? 'deleted' : 'added'
= render partial: "projects/diffs/image_diff_frame", locals: { class_name: "#{single_class_name} #{class_name} js-image-frame", position: position, note_type: DiffNote.name, image_path: blob_raw_url, alt: diff_file.file_path }
= render partial: "projects/diffs/image_diff_frame", locals: { class_name: "#{single_class_name} #{class_name} old-diff js-image-frame", position: position, note_type: DiffNote.name, image_path: blob_raw_url, alt: diff_file.file_path }
%p.image-info= number_to_human_size(blob.size)
---
title: "Fix image diff swipe view on commit and compare pages"
merge_request: 26968
author: ftab
type: fixed
\ No newline at end of file
---
title: Fix IDE detection of MR from fork with same branch name
merge_request: 26986
author:
type: fixed
......@@ -113,6 +113,7 @@ module API
desc: 'Return merge requests for the given scope: `created_by_me`, `assigned_to_me` or `all`'
optional :my_reaction_emoji, type: String, desc: 'Return issues reacted by the authenticated user by the given emoji'
optional :source_branch, type: String, desc: 'Return merge requests with the given source branch'
optional :source_project_id, type: Integer, desc: 'Return merge requests with the given source project id'
optional :target_branch, type: String, desc: 'Return merge requests with the given target branch'
optional :search, type: String, desc: 'Search merge requests for text present in the title, description, or any combination of these'
optional :in, type: String, desc: '`title`, `description`, or a string joining them with comma'
......
......@@ -83,6 +83,14 @@ describe MergeRequestsFinder do
expect(merge_requests).to contain_exactly(merge_request2)
end
it 'filters by source project id' do
params = { source_project_id: merge_request2.source_project_id }
merge_requests = described_class.new(user, params).execute
expect(merge_requests).to contain_exactly(merge_request1, merge_request2, merge_request3)
end
it 'filters by state' do
params = { state: 'locked' }
......
......@@ -20,7 +20,7 @@ describe('IDE extra file row component', () => {
file: {
...file('test'),
},
mouseOver: false,
dropdownOpen: false,
});
spyOnProperty(vm, 'getUnstagedFilesCountForPath').and.returnValue(() => unstagedFilesCount);
......
......@@ -56,11 +56,11 @@ describe('new dropdown component', () => {
});
});
describe('dropdownOpen', () => {
describe('isOpen', () => {
it('scrolls dropdown into view', done => {
spyOn(vm.$refs.dropdownMenu, 'scrollIntoView');
vm.dropdownOpen = true;
vm.isOpen = true;
setTimeout(() => {
expect(vm.$refs.dropdownMenu.scrollIntoView).toHaveBeenCalledWith({
......
......@@ -2,7 +2,6 @@ import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import store from '~/ide/stores';
import actions, {
getMergeRequestsForBranch,
getMergeRequestData,
getMergeRequestChanges,
getMergeRequestVersions,
......@@ -12,13 +11,17 @@ import service from '~/ide/services';
import { activityBarViews } from '~/ide/constants';
import { resetStore } from '../../helpers';
const TEST_PROJECT = 'abcproject';
const TEST_PROJECT_ID = 17;
describe('IDE store merge request actions', () => {
let mock;
beforeEach(() => {
mock = new MockAdapter(axios);
store.state.projects.abcproject = {
store.state.projects[TEST_PROJECT] = {
id: TEST_PROJECT_ID,
mergeRequests: {},
};
});
......@@ -41,10 +44,11 @@ describe('IDE store merge request actions', () => {
it('calls getProjectMergeRequests service method', done => {
store
.dispatch('getMergeRequestsForBranch', { projectId: 'abcproject', branchId: 'bar' })
.dispatch('getMergeRequestsForBranch', { projectId: TEST_PROJECT, branchId: 'bar' })
.then(() => {
expect(service.getProjectMergeRequests).toHaveBeenCalledWith('abcproject', {
expect(service.getProjectMergeRequests).toHaveBeenCalledWith(TEST_PROJECT, {
source_branch: 'bar',
source_project_id: TEST_PROJECT_ID,
order_by: 'created_at',
per_page: 1,
});
......@@ -56,13 +60,11 @@ describe('IDE store merge request actions', () => {
it('sets the "Merge Request" Object', done => {
store
.dispatch('getMergeRequestsForBranch', { projectId: 'abcproject', branchId: 'bar' })
.dispatch('getMergeRequestsForBranch', { projectId: TEST_PROJECT, branchId: 'bar' })
.then(() => {
expect(Object.keys(store.state.projects.abcproject.mergeRequests).length).toEqual(1);
expect(Object.keys(store.state.projects.abcproject.mergeRequests)[0]).toEqual('2');
expect(store.state.projects.abcproject.mergeRequests[2]).toEqual(
jasmine.objectContaining(mrData),
);
expect(store.state.projects.abcproject.mergeRequests).toEqual({
'2': jasmine.objectContaining(mrData),
});
done();
})
.catch(done.fail);
......@@ -70,7 +72,7 @@ describe('IDE store merge request actions', () => {
it('sets "Current Merge Request" object to the most recent MR', done => {
store
.dispatch('getMergeRequestsForBranch', { projectId: 'abcproject', branchId: 'bar' })
.dispatch('getMergeRequestsForBranch', { projectId: TEST_PROJECT, branchId: 'bar' })
.then(() => {
expect(store.state.currentMergeRequestId).toEqual('2');
done();
......@@ -87,9 +89,9 @@ describe('IDE store merge request actions', () => {
it('does not fail if there are no merge requests for current branch', done => {
store
.dispatch('getMergeRequestsForBranch', { projectId: 'abcproject', branchId: 'foo' })
.dispatch('getMergeRequestsForBranch', { projectId: TEST_PROJECT, branchId: 'foo' })
.then(() => {
expect(Object.keys(store.state.projects.abcproject.mergeRequests).length).toEqual(0);
expect(store.state.projects[TEST_PROJECT].mergeRequests).toEqual({});
expect(store.state.currentMergeRequestId).toEqual('');
done();
})
......@@ -106,7 +108,8 @@ describe('IDE store merge request actions', () => {
it('flashes message, if error', done => {
const flashSpy = spyOnDependency(actions, 'flash');
getMergeRequestsForBranch({ commit() {} }, { projectId: 'abcproject', branchId: 'bar' })
store
.dispatch('getMergeRequestsForBranch', { projectId: TEST_PROJECT, branchId: 'bar' })
.then(() => {
fail('Expected getMergeRequestsForBranch to throw an error');
})
......@@ -132,9 +135,9 @@ describe('IDE store merge request actions', () => {
it('calls getProjectMergeRequestData service method', done => {
store
.dispatch('getMergeRequestData', { projectId: 'abcproject', mergeRequestId: 1 })
.dispatch('getMergeRequestData', { projectId: TEST_PROJECT, mergeRequestId: 1 })
.then(() => {
expect(service.getProjectMergeRequestData).toHaveBeenCalledWith('abcproject', 1, {
expect(service.getProjectMergeRequestData).toHaveBeenCalledWith(TEST_PROJECT, 1, {
render_html: true,
});
......@@ -145,10 +148,12 @@ describe('IDE store merge request actions', () => {
it('sets the Merge Request Object', done => {
store
.dispatch('getMergeRequestData', { projectId: 'abcproject', mergeRequestId: 1 })
.dispatch('getMergeRequestData', { projectId: TEST_PROJECT, mergeRequestId: 1 })
.then(() => {
expect(store.state.projects.abcproject.mergeRequests['1'].title).toBe('mergerequest');
expect(store.state.currentMergeRequestId).toBe(1);
expect(store.state.projects[TEST_PROJECT].mergeRequests['1'].title).toBe(
'mergerequest',
);
done();
})
......@@ -170,7 +175,7 @@ describe('IDE store merge request actions', () => {
dispatch,
state: store.state,
},
{ projectId: 'abcproject', mergeRequestId: 1 },
{ projectId: TEST_PROJECT, mergeRequestId: 1 },
)
.then(done.fail)
.catch(() => {
......@@ -179,7 +184,7 @@ describe('IDE store merge request actions', () => {
action: jasmine.any(Function),
actionText: 'Please try again',
actionPayload: {
projectId: 'abcproject',
projectId: TEST_PROJECT,
mergeRequestId: 1,
force: false,
},
......@@ -193,7 +198,7 @@ describe('IDE store merge request actions', () => {
describe('getMergeRequestChanges', () => {
beforeEach(() => {
store.state.projects.abcproject.mergeRequests['1'] = { changes: [] };
store.state.projects[TEST_PROJECT].mergeRequests['1'] = { changes: [] };
});
describe('success', () => {
......@@ -207,9 +212,9 @@ describe('IDE store merge request actions', () => {
it('calls getProjectMergeRequestChanges service method', done => {
store
.dispatch('getMergeRequestChanges', { projectId: 'abcproject', mergeRequestId: 1 })
.dispatch('getMergeRequestChanges', { projectId: TEST_PROJECT, mergeRequestId: 1 })
.then(() => {
expect(service.getProjectMergeRequestChanges).toHaveBeenCalledWith('abcproject', 1);
expect(service.getProjectMergeRequestChanges).toHaveBeenCalledWith(TEST_PROJECT, 1);
done();
})
......@@ -218,9 +223,9 @@ describe('IDE store merge request actions', () => {
it('sets the Merge Request Changes Object', done => {
store
.dispatch('getMergeRequestChanges', { projectId: 'abcproject', mergeRequestId: 1 })
.dispatch('getMergeRequestChanges', { projectId: TEST_PROJECT, mergeRequestId: 1 })
.then(() => {
expect(store.state.projects.abcproject.mergeRequests['1'].changes.title).toBe(
expect(store.state.projects[TEST_PROJECT].mergeRequests['1'].changes.title).toBe(
'mergerequest',
);
done();
......@@ -243,7 +248,7 @@ describe('IDE store merge request actions', () => {
dispatch,
state: store.state,
},
{ projectId: 'abcproject', mergeRequestId: 1 },
{ projectId: TEST_PROJECT, mergeRequestId: 1 },
)
.then(done.fail)
.catch(() => {
......@@ -252,7 +257,7 @@ describe('IDE store merge request actions', () => {
action: jasmine.any(Function),
actionText: 'Please try again',
actionPayload: {
projectId: 'abcproject',
projectId: TEST_PROJECT,
mergeRequestId: 1,
force: false,
},
......@@ -266,7 +271,7 @@ describe('IDE store merge request actions', () => {
describe('getMergeRequestVersions', () => {
beforeEach(() => {
store.state.projects.abcproject.mergeRequests['1'] = { versions: [] };
store.state.projects[TEST_PROJECT].mergeRequests['1'] = { versions: [] };
});
describe('success', () => {
......@@ -279,9 +284,9 @@ describe('IDE store merge request actions', () => {
it('calls getProjectMergeRequestVersions service method', done => {
store
.dispatch('getMergeRequestVersions', { projectId: 'abcproject', mergeRequestId: 1 })
.dispatch('getMergeRequestVersions', { projectId: TEST_PROJECT, mergeRequestId: 1 })
.then(() => {
expect(service.getProjectMergeRequestVersions).toHaveBeenCalledWith('abcproject', 1);
expect(service.getProjectMergeRequestVersions).toHaveBeenCalledWith(TEST_PROJECT, 1);
done();
})
......@@ -290,9 +295,9 @@ describe('IDE store merge request actions', () => {
it('sets the Merge Request Versions Object', done => {
store
.dispatch('getMergeRequestVersions', { projectId: 'abcproject', mergeRequestId: 1 })
.dispatch('getMergeRequestVersions', { projectId: TEST_PROJECT, mergeRequestId: 1 })
.then(() => {
expect(store.state.projects.abcproject.mergeRequests['1'].versions.length).toBe(1);
expect(store.state.projects[TEST_PROJECT].mergeRequests['1'].versions.length).toBe(1);
done();
})
.catch(done.fail);
......@@ -313,7 +318,7 @@ describe('IDE store merge request actions', () => {
dispatch,
state: store.state,
},
{ projectId: 'abcproject', mergeRequestId: 1 },
{ projectId: TEST_PROJECT, mergeRequestId: 1 },
)
.then(done.fail)
.catch(() => {
......@@ -322,7 +327,7 @@ describe('IDE store merge request actions', () => {
action: jasmine.any(Function),
actionText: 'Please try again',
actionPayload: {
projectId: 'abcproject',
projectId: TEST_PROJECT,
mergeRequestId: 1,
force: false,
},
......@@ -336,7 +341,7 @@ describe('IDE store merge request actions', () => {
describe('openMergeRequest', () => {
const mr = {
projectId: 'abcproject',
projectId: TEST_PROJECT,
targetProjectId: 'defproject',
mergeRequestId: 2,
};
......
import Vue from 'vue';
import FileRow from '~/vue_shared/components/file_row.vue';
import FileRowExtra from '~/ide/components/file_row_extra.vue';
import { file } from 'spec/ide/helpers';
import mountComponent from '../../helpers/vue_mount_component_helper';
......@@ -16,6 +17,10 @@ describe('File row component', () => {
vm.$destroy();
});
const findNewDropdown = () => vm.$el.querySelector('.ide-new-btn .dropdown');
const findNewDropdownButton = () => vm.$el.querySelector('.ide-new-btn .dropdown button');
const findFileRow = () => vm.$el.querySelector('.file-row');
it('renders name', () => {
createComponent({
file: file('t4'),
......@@ -84,4 +89,59 @@ describe('File row component', () => {
expect(vm.$el.querySelector('.js-file-row-header')).not.toBe(null);
});
describe('new dropdown', () => {
beforeEach(() => {
createComponent({
file: file('t5'),
level: 1,
extraComponent: FileRowExtra,
});
});
it('renders in extra component', () => {
expect(findNewDropdown()).not.toBe(null);
});
it('is hidden at start', () => {
expect(findNewDropdown()).not.toHaveClass('show');
});
it('is opened when button is clicked', done => {
expect(vm.dropdownOpen).toBe(false);
findNewDropdownButton().dispatchEvent(new Event('click'));
vm.$nextTick()
.then(() => {
expect(vm.dropdownOpen).toBe(true);
expect(findNewDropdown()).toHaveClass('show');
})
.then(done)
.catch(done.fail);
});
describe('when opened', () => {
beforeEach(() => {
vm.dropdownOpen = true;
});
it('stays open when button triggers mouseout', () => {
findNewDropdownButton().dispatchEvent(new Event('mouseout'));
expect(vm.dropdownOpen).toBe(true);
});
it('stays open when button triggers mouseleave', () => {
findNewDropdownButton().dispatchEvent(new Event('mouseleave'));
expect(vm.dropdownOpen).toBe(true);
});
it('closes when row triggers mouseleave', () => {
findFileRow().dispatchEvent(new Event('mouseleave'));
expect(vm.dropdownOpen).toBe(false);
});
});
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment