summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhil Hughes <me@iamphill.com>2016-11-28 09:28:19 +0000
committerPhil Hughes <me@iamphill.com>2016-12-02 14:39:27 +0000
commita8188b643f6aa72558e56823b4012ff0b78b75ee (patch)
tree07006513398d0dc237bb46e6b14944f5d324e8b3
parent90c0f610e29976608dbfeeb63bc4763982c5dbc3 (diff)
downloadgitlab-ce-a8188b643f6aa72558e56823b4012ff0b78b75ee.tar.gz
Real time issue boards
Lists are added automatically when another user adds them. List data is automatically updated, include title, description tooltip & color Closes #24478
-rw-r--r--app/assets/javascripts/boards/boards_bundle.js.es674
-rw-r--r--app/assets/javascripts/boards/components/board.js.es63
-rw-r--r--app/assets/javascripts/boards/models/list.js.es643
-rw-r--r--app/views/projects/boards/_show.html.haml2
-rw-r--r--changelogs/unreleased/issue-boards-realtime.yml4
5 files changed, 105 insertions, 21 deletions
diff --git a/app/assets/javascripts/boards/boards_bundle.js.es6 b/app/assets/javascripts/boards/boards_bundle.js.es6
index 7ba918a05f8..cb41d5f5864 100644
--- a/app/assets/javascripts/boards/boards_bundle.js.es6
+++ b/app/assets/javascripts/boards/boards_bundle.js.es6
@@ -48,25 +48,69 @@ $(() => {
gl.boardService = new BoardService(this.endpoint, this.boardId);
},
mounted () {
+ const interval = new gl.SmartInterval({
+ callback: () => {
+ this.fetchAll();
+ },
+ startingInterval: 5 * 1000, // 5 seconds
+ maxInterval: 10 * 1000, // 10 seconds
+ incrementByFactorOf: 10,
+ lazyStart: true,
+ });
+
Store.disabled = this.disabled;
- gl.boardService.all()
- .then((resp) => {
- resp.json().forEach((board) => {
- const list = Store.addList(board);
-
- if (list.type === 'done') {
- list.position = Infinity;
- } else if (list.type === 'backlog') {
- list.position = -1;
+
+ this.fetchAll().then(() => {
+ this.loading = false;
+ interval.start();
+ });
+ },
+ methods: {
+ fetchAll() {
+ return gl.boardService.all()
+ .then((resp) => {
+ const data = resp.json();
+
+ // Remove any old lists
+ if (this.state.lists.length) {
+ const dataListIds = data.map( list => list.id );
+
+ this.state.lists.forEach((list) => {
+ if (dataListIds.indexOf(list.id) === -1) {
+ list.destroy(false);
+ }
+ });
}
- });
- this.state.lists = _.sortBy(this.state.lists, 'position');
+ // Create/Update lists
+ data.forEach((board) => {
+ const list = Store.findList('id', board.id, false);
- Store.addBlankState();
- this.loading = false;
- });
- }
+ if (list) {
+ // If list already exists, update the data
+ list.title = board.title;
+
+ if (board.position !== null) {
+ list.position = board.position;
+ }
+
+ if (list.label) {
+ list.label.description = board.label.description;
+ list.label.color = board.label.color;
+ list.label.textColor = board.label.text_color;
+ }
+ } else {
+ // If list doesn't exist, create a new list
+ Store.addList(board);
+ }
+ });
+
+ this.state.lists = _.sortBy(this.state.lists, 'position');
+
+ Store.addBlankState();
+ });
+ },
+ },
});
gl.IssueBoardsSearch = new Vue({
diff --git a/app/assets/javascripts/boards/components/board.js.es6 b/app/assets/javascripts/boards/components/board.js.es6
index 31de3b25284..f4271002743 100644
--- a/app/assets/javascripts/boards/components/board.js.es6
+++ b/app/assets/javascripts/boards/components/board.js.es6
@@ -83,5 +83,8 @@
this.sortable = Sortable.create(this.$el.parentNode, options);
},
+ updated() {
+ $('.has-tooltip', $(this.$el)).tooltip('fixTitle');
+ },
});
})();
diff --git a/app/assets/javascripts/boards/models/list.js.es6 b/app/assets/javascripts/boards/models/list.js.es6
index 429bd27c3fb..aff8dc1931d 100644
--- a/app/assets/javascripts/boards/models/list.js.es6
+++ b/app/assets/javascripts/boards/models/list.js.es6
@@ -3,7 +3,6 @@ class List {
constructor (obj) {
this.id = obj.id;
this._uid = this.guid();
- this.position = obj.position;
this.title = obj.title;
this.type = obj.list_type;
this.preset = ['backlog', 'done', 'blank'].indexOf(this.type) > -1;
@@ -13,13 +12,33 @@ class List {
this.loadingMore = false;
this.issues = [];
this.issuesSize = 0;
+ this._interval = new gl.SmartInterval({
+ callback: () => {
+ this.getIssues(false);
+ },
+ startingInterval: 6 * 1000, // 6 seconds
+ maxInterval: 11 * 1000, // 11 seconds
+ incrementByFactorOf: 10,
+ lazyStart: true,
+ });
+
+ if (this.type === 'done') {
+ this.position = Infinity;
+ } else if (this.type === 'backlog') {
+ this.position = -1;
+ } else {
+ this.position = obj.position;
+ }
if (obj.label) {
this.label = new ListLabel(obj.label);
}
if (this.type !== 'blank' && this.id) {
- this.getIssues();
+ this.getIssues()
+ .then(() => {
+ this._interval.start();
+ });
}
}
@@ -41,12 +60,16 @@ class List {
});
}
- destroy () {
+ destroy (persist = true) {
const index = gl.issueBoards.BoardsStore.state.lists.indexOf(this);
gl.issueBoards.BoardsStore.state.lists.splice(index, 1);
gl.issueBoards.BoardsStore.updateNewListDropdown(this.id);
- gl.boardService.destroyList(this.id);
+ this._interval.destroy();
+
+ if (persist) {
+ gl.boardService.destroyList(this.id);
+ }
}
update () {
@@ -102,7 +125,17 @@ class List {
createIssues (data) {
data.forEach((issueObj) => {
- this.addIssue(new ListIssue(issueObj));
+ const issue = this.findIssue(issueObj.iid);
+
+ if (issue) {
+ if (issueObj.assignee) {
+ issue.assignee = new ListUser(issueObj.assignee);
+ } else {
+ issue.assignee = undefined;
+ }
+ } else {
+ this.addIssue(new ListIssue(issueObj));
+ }
});
}
diff --git a/app/views/projects/boards/_show.html.haml b/app/views/projects/boards/_show.html.haml
index 356bd50f7f3..68a38f646cb 100644
--- a/app/views/projects/boards/_show.html.haml
+++ b/app/views/projects/boards/_show.html.haml
@@ -24,5 +24,5 @@
":list" => "list",
":disabled" => "disabled",
":issue-link-base" => "issueLinkBase",
- ":key" => "_uid" }
+ ":key" => "list._uid" }
= render "projects/boards/components/sidebar"
diff --git a/changelogs/unreleased/issue-boards-realtime.yml b/changelogs/unreleased/issue-boards-realtime.yml
new file mode 100644
index 00000000000..596848b6b7b
--- /dev/null
+++ b/changelogs/unreleased/issue-boards-realtime.yml
@@ -0,0 +1,4 @@
+---
+title: Realtime issue boards
+merge_request:
+author: