Commit 3c49f96b authored by Heinrich Lee Yu's avatar Heinrich Lee Yu

Fix position when creating issue in issue boards

This sends the moveAfterId param when creating issues in boards.

This sets the correct position of the issue in the backend so that the
newly created issue does not move to the end after a refresh.

Changelog: fixed
parent 5a018bed
...@@ -25,7 +25,7 @@ export default { ...@@ -25,7 +25,7 @@ export default {
}, },
computed: { computed: {
...mapState(['selectedProject', 'fullPath']), ...mapState(['selectedProject', 'fullPath']),
...mapGetters(['isGroupBoard']), ...mapGetters(['isGroupBoard', 'getBoardItemsByList']),
formEventPrefix() { formEventPrefix() {
return toggleFormEventPrefix.issue; return toggleFormEventPrefix.issue;
}, },
...@@ -42,6 +42,7 @@ export default { ...@@ -42,6 +42,7 @@ export default {
const labels = this.list.label ? [this.list.label] : []; const labels = this.list.label ? [this.list.label] : [];
const assignees = this.list.assignee ? [this.list.assignee] : []; const assignees = this.list.assignee ? [this.list.assignee] : [];
const milestone = getMilestone(this.list); const milestone = getMilestone(this.list);
const firstItemId = this.getBoardItemsByList(this.list.id)[0]?.id;
return this.addListNewIssue({ return this.addListNewIssue({
list: this.list, list: this.list,
...@@ -51,6 +52,7 @@ export default { ...@@ -51,6 +52,7 @@ export default {
assigneeIds: assignees?.map((a) => a?.id), assigneeIds: assignees?.map((a) => a?.id),
milestoneId: milestone?.id, milestoneId: milestone?.id,
projectPath: this.projectPath, projectPath: this.projectPath,
moveAfterId: firstItemId,
}, },
}).then(() => { }).then(() => {
this.cancel(); this.cancel();
......
...@@ -9,6 +9,7 @@ RSpec.describe 'Issue Boards new issue', :js do ...@@ -9,6 +9,7 @@ RSpec.describe 'Issue Boards new issue', :js do
let_it_be(:label) { create(:label, project: project, name: 'Label 1') } let_it_be(:label) { create(:label, project: project, name: 'Label 1') }
let_it_be(:list) { create(:list, board: board, label: label, position: 0) } let_it_be(:list) { create(:list, board: board, label: label, position: 0) }
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
let_it_be(:existing_issue) { create(:issue, project: project, title: 'other issue', relative_position: 50) }
let(:board_list_header) { first('[data-testid="board-list-header"]') } let(:board_list_header) { first('[data-testid="board-list-header"]') }
let(:project_select_dropdown) { find('[data-testid="project-select-dropdown"]') } let(:project_select_dropdown) { find('[data-testid="project-select-dropdown"]') }
...@@ -56,7 +57,7 @@ RSpec.describe 'Issue Boards new issue', :js do ...@@ -56,7 +57,7 @@ RSpec.describe 'Issue Boards new issue', :js do
end end
end end
it 'creates new issue and opens sidebar' do it 'creates new issue, places it on top of the list, and opens sidebar' do
page.within(first('.board')) do page.within(first('.board')) do
click_button 'New issue' click_button 'New issue'
end end
...@@ -69,12 +70,14 @@ RSpec.describe 'Issue Boards new issue', :js do ...@@ -69,12 +70,14 @@ RSpec.describe 'Issue Boards new issue', :js do
wait_for_requests wait_for_requests
page.within(first('.board [data-testid="issue-count-badge"]')) do page.within(first('.board [data-testid="issue-count-badge"]')) do
expect(page).to have_content('1') expect(page).to have_content('2')
end end
page.within(first('.board-card')) do page.within(first('.board-card')) do
issue = project.issues.find_by_title('bug') issue = project.issues.find_by_title('bug')
expect(issue.relative_position).to be < existing_issue.relative_position
expect(page).to have_content(issue.to_reference) expect(page).to have_content(issue.to_reference)
expect(page).to have_link(issue.title, href: /#{issue_path(issue)}/) expect(page).to have_link(issue.title, href: /#{issue_path(issue)}/)
end end
......
...@@ -6,7 +6,7 @@ import BoardNewItem from '~/boards/components/board_new_item.vue'; ...@@ -6,7 +6,7 @@ import BoardNewItem from '~/boards/components/board_new_item.vue';
import ProjectSelect from '~/boards/components/project_select.vue'; import ProjectSelect from '~/boards/components/project_select.vue';
import eventHub from '~/boards/eventhub'; import eventHub from '~/boards/eventhub';
import { mockList, mockGroupProjects } from '../mock_data'; import { mockList, mockGroupProjects, mockIssue, mockIssue2 } from '../mock_data';
Vue.use(Vuex); Vue.use(Vuex);
...@@ -16,7 +16,7 @@ const mockActions = { addListNewIssue: addListNewIssuesSpy }; ...@@ -16,7 +16,7 @@ const mockActions = { addListNewIssue: addListNewIssuesSpy };
const createComponent = ({ const createComponent = ({
state = { selectedProject: mockGroupProjects[0], fullPath: mockGroupProjects[0].fullPath }, state = { selectedProject: mockGroupProjects[0], fullPath: mockGroupProjects[0].fullPath },
actions = mockActions, actions = mockActions,
getters = { isGroupBoard: () => true, isProjectBoard: () => false }, getters = { isGroupBoard: () => true, getBoardItemsByList: () => () => [] },
} = {}) => } = {}) =>
shallowMount(BoardNewIssue, { shallowMount(BoardNewIssue, {
store: new Vuex.Store({ store: new Vuex.Store({
...@@ -75,10 +75,39 @@ describe('Issue boards new issue form', () => { ...@@ -75,10 +75,39 @@ describe('Issue boards new issue form', () => {
assigneeIds: [], assigneeIds: [],
milestoneId: undefined, milestoneId: undefined,
projectPath: mockGroupProjects[0].fullPath, projectPath: mockGroupProjects[0].fullPath,
moveAfterId: undefined,
}, },
}); });
}); });
describe('when list has an existing issues', () => {
beforeEach(() => {
wrapper = createComponent({
getters: {
isGroupBoard: () => true,
getBoardItemsByList: () => () => [mockIssue, mockIssue2],
},
});
});
it('it uses the first issue ID as moveAfterId', async () => {
findBoardNewItem().vm.$emit('form-submit', { title: 'Foo' });
await nextTick();
expect(addListNewIssuesSpy).toHaveBeenCalledWith(expect.any(Object), {
list: mockList,
issueInput: {
title: 'Foo',
labelIds: [],
assigneeIds: [],
milestoneId: undefined,
projectPath: mockGroupProjects[0].fullPath,
moveAfterId: mockIssue.id,
},
});
});
});
it('emits event `toggle-issue-form` with current list Id suffix on eventHub when `board-new-item` emits form-cancel event', async () => { it('emits event `toggle-issue-form` with current list Id suffix on eventHub when `board-new-item` emits form-cancel event', async () => {
jest.spyOn(eventHub, '$emit').mockImplementation(); jest.spyOn(eventHub, '$emit').mockImplementation();
findBoardNewItem().vm.$emit('form-cancel'); findBoardNewItem().vm.$emit('form-cancel');
...@@ -99,7 +128,7 @@ describe('Issue boards new issue form', () => { ...@@ -99,7 +128,7 @@ describe('Issue boards new issue form', () => {
describe('when in project issue board', () => { describe('when in project issue board', () => {
beforeEach(() => { beforeEach(() => {
wrapper = createComponent({ wrapper = createComponent({
getters: { isGroupBoard: () => false, isProjectBoard: () => true }, getters: { isGroupBoard: () => 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