summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Knox <psimyn@gmail.com>2017-09-06 15:02:30 +1000
committerSimon Knox <psimyn@gmail.com>2017-09-06 15:41:00 +1000
commitc28d52a3a5e745d20981151b89bfcad07c68fa9c (patch)
treed51df26c80701f8e7b8a178119ffd09a895ad063
parentb9aa55e1ea2ba226bd9bf4c6fb08fdec30e046c5 (diff)
downloadgitlab-ce-c28d52a3a5e745d20981151b89bfcad07c68fa9c.tar.gz
FE backport of group boards to reduce CE conflicts
-rw-r--r--app/assets/javascripts/api.js14
-rw-r--r--app/assets/javascripts/boards/boards_bundle.js51
-rw-r--r--app/assets/javascripts/boards/components/board_list.js10
-rw-r--r--app/assets/javascripts/boards/components/board_new_issue.js5
-rw-r--r--app/assets/javascripts/boards/components/issue_card_inner.js7
-rw-r--r--app/assets/javascripts/boards/components/modal/footer.js2
-rw-r--r--app/assets/javascripts/boards/components/new_list_dropdown.js2
-rw-r--r--app/assets/javascripts/boards/components/sidebar/remove_issue.js23
-rw-r--r--app/assets/javascripts/boards/models/issue.js4
-rw-r--r--app/assets/javascripts/boards/models/label.js1
-rw-r--r--app/assets/javascripts/boards/models/list.js27
-rw-r--r--spec/javascripts/api_spec.js23
12 files changed, 116 insertions, 53 deletions
diff --git a/app/assets/javascripts/api.js b/app/assets/javascripts/api.js
index 8acddd6194c..501cc43d552 100644
--- a/app/assets/javascripts/api.js
+++ b/app/assets/javascripts/api.js
@@ -6,7 +6,8 @@ const Api = {
namespacesPath: '/api/:version/namespaces.json',
groupProjectsPath: '/api/:version/groups/:id/projects.json',
projectsPath: '/api/:version/projects.json',
- labelsPath: '/:namespace_path/:project_path/labels',
+ projectLabelsPath: '/:namespace_path/:project_path/labels',
+ groupLabelsPath: '/groups/:namespace_path/labels',
licensePath: '/api/:version/templates/licenses/:key',
gitignorePath: '/api/:version/templates/gitignores/:key',
gitlabCiYmlPath: '/api/:version/templates/gitlab_ci_ymls/:key',
@@ -74,9 +75,14 @@ const Api = {
},
newLabel(namespacePath, projectPath, data, callback) {
- const url = Api.buildUrl(Api.labelsPath)
- .replace(':namespace_path', namespacePath)
- .replace(':project_path', projectPath);
+ let url;
+ if (projectPath) {
+ url = Api.buildUrl(Api.projectLabelsPath)
+ .replace(':namespace_path', namespacePath)
+ .replace(':project_path', projectPath);
+ } else {
+ url = Api.buildUrl(Api.groupLabelsPath).replace(':namespace_path', namespacePath);
+ }
return $.ajax({
url,
type: 'POST',
diff --git a/app/assets/javascripts/boards/boards_bundle.js b/app/assets/javascripts/boards/boards_bundle.js
index 89c14180149..ea00efe4b46 100644
--- a/app/assets/javascripts/boards/boards_bundle.js
+++ b/app/assets/javascripts/boards/boards_bundle.js
@@ -53,7 +53,8 @@ $(() => {
data: {
state: Store.state,
loading: true,
- endpoint: $boardApp.dataset.endpoint,
+ boardsEndpoint: $boardApp.dataset.boardsEndpoint,
+ listsEndpoint: $boardApp.dataset.listsEndpoint,
boardId: $boardApp.dataset.boardId,
disabled: $boardApp.dataset.disabled === 'true',
issueLinkBase: $boardApp.dataset.issueLinkBase,
@@ -68,7 +69,13 @@ $(() => {
},
},
created () {
- gl.boardService = new BoardService(this.endpoint, this.bulkUpdatePath, this.boardId);
+ gl.boardService = new BoardService({
+ boardsEndpoint: this.boardsEndpoint,
+ listsEndpoint: this.listsEndpoint,
+ bulkUpdatePath: this.bulkUpdatePath,
+ boardId: this.boardId,
+ });
+ Store.rootPath = this.boardsEndpoint;
this.filterManager = new FilteredSearchBoards(Store.filter, true);
this.filterManager.setup();
@@ -112,19 +119,21 @@ $(() => {
gl.IssueBoardsSearch = new Vue({
el: document.getElementById('js-add-list'),
data: {
- filters: Store.state.filters
+ filters: Store.state.filters,
},
mounted () {
gl.issueBoards.newListDropdownInit();
- }
+ },
});
gl.IssueBoardsModalAddBtn = new Vue({
mixins: [gl.issueBoards.ModalMixins],
el: document.getElementById('js-add-issues-btn'),
- data: {
- modal: ModalStore.store,
- store: Store.state,
+ data() {
+ return {
+ modal: ModalStore.store,
+ store: Store.state,
+ };
},
watch: {
disabled() {
@@ -133,6 +142,9 @@ $(() => {
},
computed: {
disabled() {
+ if (!this.store) {
+ return true;
+ }
return !this.store.lists.filter(list => !list.preset).length;
},
tooltipTitle() {
@@ -145,7 +157,7 @@ $(() => {
},
methods: {
updateTooltip() {
- const $tooltip = $(this.$el);
+ const $tooltip = $(this.$refs.addIssuesButton);
this.$nextTick(() => {
if (this.disabled) {
@@ -165,16 +177,19 @@ $(() => {
this.updateTooltip();
},
template: `
- <button
- class="btn btn-create pull-right prepend-left-10"
- type="button"
- data-placement="bottom"
- :class="{ 'disabled': disabled }"
- :title="tooltipTitle"
- :aria-disabled="disabled"
- @click="openModal">
- Add issues
- </button>
+ <div class="board-extra-actions">
+ <button
+ class="btn btn-create prepend-left-10"
+ type="button"
+ data-placement="bottom"
+ ref="addIssuesButton"
+ :class="{ 'disabled': disabled }"
+ :title="tooltipTitle"
+ :aria-disabled="disabled"
+ @click="openModal">
+ Add issues
+ </button>
+ </div>
`,
});
});
diff --git a/app/assets/javascripts/boards/components/board_list.js b/app/assets/javascripts/boards/components/board_list.js
index bebca17fb1e..6159680f1e6 100644
--- a/app/assets/javascripts/boards/components/board_list.js
+++ b/app/assets/javascripts/boards/components/board_list.js
@@ -77,7 +77,7 @@ export default {
this.showIssueForm = !this.showIssueForm;
},
onScroll() {
- if ((this.scrollTop() > this.scrollHeight() - this.scrollOffset) && !this.list.loadingMore) {
+ if (!this.loadingMore && (this.scrollTop() > this.scrollHeight() - this.scrollOffset)) {
this.loadNextPage();
}
},
@@ -165,11 +165,9 @@ export default {
v-if="loading">
<loading-icon />
</div>
- <transition name="slide-down">
- <board-new-issue
- :list="list"
- v-if="list.type !== 'closed' && showIssueForm"/>
- </transition>
+ <board-new-issue
+ :list="list"
+ v-if="list.type !== 'closed' && showIssueForm"/>
<ul
class="board-list"
v-show="!loading"
diff --git a/app/assets/javascripts/boards/components/board_new_issue.js b/app/assets/javascripts/boards/components/board_new_issue.js
index 4af8b0c7713..541b8049855 100644
--- a/app/assets/javascripts/boards/components/board_new_issue.js
+++ b/app/assets/javascripts/boards/components/board_new_issue.js
@@ -6,7 +6,10 @@ const Store = gl.issueBoards.BoardsStore;
export default {
name: 'BoardNewIssue',
props: {
- list: Object,
+ list: {
+ type: Object,
+ required: true,
+ },
},
data() {
return {
diff --git a/app/assets/javascripts/boards/components/issue_card_inner.js b/app/assets/javascripts/boards/components/issue_card_inner.js
index 9a5d87ede7e..26f0a41c0ca 100644
--- a/app/assets/javascripts/boards/components/issue_card_inner.js
+++ b/app/assets/javascripts/boards/components/issue_card_inner.js
@@ -67,7 +67,10 @@ gl.issueBoards.IssueCardInner = Vue.extend({
return `${this.issueLinkBase}/${this.issue.id}`;
},
issueId() {
- return `#${this.issue.id}`;
+ if (this.issue.iid) {
+ return `#${this.issue.iid}`;
+ }
+ return false;
},
showLabelFooter() {
return this.issue.labels.find(l => this.showLabel(l)) !== undefined;
@@ -143,7 +146,7 @@ gl.issueBoards.IssueCardInner = Vue.extend({
:title="issue.title">{{ issue.title }}</a>
<span
class="card-number"
- v-if="issue.id"
+ v-if="issueId"
>
{{ issueId }}
</span>
diff --git a/app/assets/javascripts/boards/components/modal/footer.js b/app/assets/javascripts/boards/components/modal/footer.js
index 478a1335b2b..a656f0546c0 100644
--- a/app/assets/javascripts/boards/components/modal/footer.js
+++ b/app/assets/javascripts/boards/components/modal/footer.js
@@ -29,7 +29,7 @@ gl.issueBoards.ModalFooter = Vue.extend({
const firstListIndex = 1;
const list = this.modal.selectedList || this.state.lists[firstListIndex];
const selectedIssues = ModalStore.getSelectedIssues();
- const issueIds = selectedIssues.map(issue => issue.globalId);
+ const issueIds = selectedIssues.map(issue => issue.id);
// Post the data to the backend
gl.boardService.bulkUpdate(issueIds, {
diff --git a/app/assets/javascripts/boards/components/new_list_dropdown.js b/app/assets/javascripts/boards/components/new_list_dropdown.js
index 72bb9e10fbc..d7f203b3f96 100644
--- a/app/assets/javascripts/boards/components/new_list_dropdown.js
+++ b/app/assets/javascripts/boards/components/new_list_dropdown.js
@@ -27,7 +27,7 @@ gl.issueBoards.newListDropdownInit = () => {
$this.glDropdown({
data(term, callback) {
- $.get($this.attr('data-labels'))
+ $.get($this.attr('data-list-labels-path'))
.then((resp) => {
callback(resp);
});
diff --git a/app/assets/javascripts/boards/components/sidebar/remove_issue.js b/app/assets/javascripts/boards/components/sidebar/remove_issue.js
index 6a900d4abd0..b44e87b051d 100644
--- a/app/assets/javascripts/boards/components/sidebar/remove_issue.js
+++ b/app/assets/javascripts/boards/components/sidebar/remove_issue.js
@@ -18,17 +18,32 @@ gl.issueBoards.RemoveIssueBtn = Vue.extend({
type: Object,
required: true,
},
+ issueUpdate: {
+ type: String,
+ required: true,
+ },
+ },
+ computed: {
+ updateUrl() {
+ return this.issueUpdate;
+ },
},
methods: {
removeIssue() {
const issue = this.issue;
const lists = issue.getLists();
- const labelIds = lists.map(list => list.label.id);
+ const listLabelIds = lists.map(list => list.label.id);
+ const labelIds = this.issue.labels
+ .map(label => label.id)
+ .filter(id => !listLabelIds.includes(id));
// Post the remove data
- gl.boardService.bulkUpdate([issue.globalId], {
- remove_label_ids: labelIds,
- }).catch(() => {
+ const data = {
+ issue: {
+ label_ids: labelIds,
+ },
+ };
+ Vue.http.patch(this.updateUrl, data).catch(() => {
new Flash('Failed to remove issue from board, please try again.', 'alert');
lists.forEach((list) => {
diff --git a/app/assets/javascripts/boards/models/issue.js b/app/assets/javascripts/boards/models/issue.js
index 6c2d8a3781b..407db176446 100644
--- a/app/assets/javascripts/boards/models/issue.js
+++ b/app/assets/javascripts/boards/models/issue.js
@@ -7,8 +7,8 @@ import Vue from 'vue';
class ListIssue {
constructor (obj, defaultAvatar) {
- this.globalId = obj.id;
- this.id = obj.iid;
+ this.id = obj.id;
+ this.iid = obj.iid;
this.title = obj.title;
this.confidential = obj.confidential;
this.dueDate = obj.due_date;
diff --git a/app/assets/javascripts/boards/models/label.js b/app/assets/javascripts/boards/models/label.js
index 9af88d167d6..98c1ec014c4 100644
--- a/app/assets/javascripts/boards/models/label.js
+++ b/app/assets/javascripts/boards/models/label.js
@@ -4,6 +4,7 @@ class ListLabel {
constructor (obj) {
this.id = obj.id;
this.title = obj.title;
+ this.type = obj.type;
this.color = obj.color;
this.textColor = obj.text_color;
this.description = obj.description;
diff --git a/app/assets/javascripts/boards/models/list.js b/app/assets/javascripts/boards/models/list.js
index 08f7c5ddcd2..787f5eae64d 100644
--- a/app/assets/javascripts/boards/models/list.js
+++ b/app/assets/javascripts/boards/models/list.js
@@ -110,11 +110,12 @@ class List {
return gl.boardService.newIssue(this.id, issue)
.then(resp => resp.json())
.then((data) => {
- issue.id = data.iid;
+ issue.id = data.id;
+ issue.iid = data.iid;
if (this.issuesSize > 1) {
- const moveBeforeIid = this.issues[1].id;
- gl.boardService.moveIssue(issue.id, null, null, null, moveBeforeIid);
+ const moveBeforeId = this.issues[1].id;
+ gl.boardService.moveIssue(issue.id, null, null, null, moveBeforeId);
}
});
}
@@ -126,19 +127,19 @@ class List {
}
addIssue (issue, listFrom, newIndex) {
- let moveBeforeIid = null;
- let moveAfterIid = null;
+ let moveBeforeId = null;
+ let moveAfterId = null;
if (!this.findIssue(issue.id)) {
if (newIndex !== undefined) {
this.issues.splice(newIndex, 0, issue);
if (this.issues[newIndex - 1]) {
- moveBeforeIid = this.issues[newIndex - 1].id;
+ moveBeforeId = this.issues[newIndex - 1].id;
}
if (this.issues[newIndex + 1]) {
- moveAfterIid = this.issues[newIndex + 1].id;
+ moveAfterId = this.issues[newIndex + 1].id;
}
} else {
this.issues.push(issue);
@@ -151,30 +152,30 @@ class List {
if (listFrom) {
this.issuesSize += 1;
- this.updateIssueLabel(issue, listFrom, moveBeforeIid, moveAfterIid);
+ this.updateIssueLabel(issue, listFrom, moveBeforeId, moveAfterId);
}
}
}
- moveIssue (issue, oldIndex, newIndex, moveBeforeIid, moveAfterIid) {
+ moveIssue (issue, oldIndex, newIndex, moveBeforeId, moveAfterId) {
this.issues.splice(oldIndex, 1);
this.issues.splice(newIndex, 0, issue);
- gl.boardService.moveIssue(issue.id, null, null, moveBeforeIid, moveAfterIid)
+ gl.boardService.moveIssue(issue.id, null, null, moveBeforeId, moveAfterId)
.catch(() => {
// TODO: handle request error
});
}
- updateIssueLabel(issue, listFrom, moveBeforeIid, moveAfterIid) {
- gl.boardService.moveIssue(issue.id, listFrom.id, this.id, moveBeforeIid, moveAfterIid)
+ updateIssueLabel(issue, listFrom, moveBeforeId, moveAfterId) {
+ gl.boardService.moveIssue(issue.id, listFrom.id, this.id, moveBeforeId, moveAfterId)
.catch(() => {
// TODO: handle request error
});
}
findIssue (id) {
- return this.issues.filter(issue => issue.id === id)[0];
+ return this.issues.find(issue => issue.id === id);
}
removeIssue (removeIssue) {
diff --git a/spec/javascripts/api_spec.js b/spec/javascripts/api_spec.js
index 2aa4fb1f6c6..72d1b8423ff 100644
--- a/spec/javascripts/api_spec.js
+++ b/spec/javascripts/api_spec.js
@@ -145,7 +145,7 @@ describe('Api', () => {
});
});
- describe('newLabel', () => {
+ fdescribe('newLabel', () => {
it('creates a new label', (done) => {
const namespace = 'some namespace';
const project = 'some project';
@@ -167,6 +167,27 @@ describe('Api', () => {
done();
});
});
+
+ it('creates a new group label', (done) => {
+ const namespace = 'some namespace';
+ const labelData = { some: 'data' };
+ const expectedUrl = `${dummyUrlRoot}/${namespace}/labels`;
+ const expectedData = {
+ label: labelData,
+ };
+ spyOn(jQuery, 'ajax').and.callFake((request) => {
+ expect(request.url).toEqual(expectedUrl);
+ expect(request.dataType).toEqual('json');
+ expect(request.type).toEqual('POST');
+ expect(request.data).toEqual(expectedData);
+ return sendDummyResponse();
+ });
+
+ Api.newLabel(namespace, null, labelData, (response) => {
+ expect(response).toBe(dummyResponse);
+ done();
+ });
+ });
});
describe('groupProjects', () => {