From 7a265e5ec29f38a69e12213ab95dd1475aff95e7 Mon Sep 17 00:00:00 2001 From: wenincode Date: Sun, 11 Dec 2016 21:36:31 -0700 Subject: [PATCH] add task-list model, update project & task models --- app/models/project.js | 1 + app/models/task-list.js | 55 +++++++++++++ app/models/task.js | 116 ++++++++++++++++++++++++++++ mirage/config.js | 13 +++- mirage/factories/task-list.js | 10 +++ mirage/factories/task.js | 6 ++ mirage/models/project.js | 1 + mirage/models/task-list.js | 6 ++ mirage/models/task.js | 1 + mirage/scenarios/default.js | 42 +++++++++- tests/unit/models/project-test.js | 2 + tests/unit/models/task-list-test.js | 20 +++++ tests/unit/models/task-test.js | 4 +- tests/unit/serializers/task-test.js | 1 + 14 files changed, 273 insertions(+), 5 deletions(-) create mode 100644 app/models/task-list.js create mode 100644 mirage/factories/task-list.js create mode 100644 mirage/models/task-list.js create mode 100644 tests/unit/models/task-list-test.js diff --git a/app/models/project.js b/app/models/project.js index de7c12898..06fdc4ea9 100644 --- a/app/models/project.js +++ b/app/models/project.js @@ -21,6 +21,7 @@ export default Model.extend({ donationGoals: hasMany('donation-goal', { async: true }), organization: belongsTo('organization', { async: true }), + taskLists: hasMany('task-list', { async: true }), tasks: hasMany('tasks', { async: true }), projectCategories: hasMany('project-category', { async: true }), projectSkills: hasMany('project-skill', { async: true }), diff --git a/app/models/task-list.js b/app/models/task-list.js new file mode 100644 index 000000000..8f2a3ee4f --- /dev/null +++ b/app/models/task-list.js @@ -0,0 +1,55 @@ +import Model from 'ember-data/model'; +import attr from 'ember-data/attr'; +import { belongsTo, hasMany } from 'ember-data/relationships'; + +/** + Task-list is a collection of categorized tasks that belong to a project. + + @class task-list + @module Model + @extends Ember.Model + */ +export default Model.extend({ + + /** + Task-lists name + + @attribute name + @type string + */ + name: attr(), + + /** + Order is a read-only attribute computed from the `position` attribute + + @attribute order + @readonly + @type number + */ + order: attr(), + + /** + Position is a virtual (write-only) attribute used to compute the `order` of the task-list + + @attribute position + @virtual + @type number + */ + position: attr(), + + /** + The project that the task-list belongs to. + + @attribute project + @type Ember.computed + */ + project: belongsTo('project', { async: true }), + + /** + The tasks that belong to the task-list. + + @attribute tasks + @type Ember.computed + */ + tasks: hasMany('task', { async: true }) +}); diff --git a/app/models/task.js b/app/models/task.js index ff5aad10d..3d1acb7c7 100644 --- a/app/models/task.js +++ b/app/models/task.js @@ -3,18 +3,134 @@ import attr from 'ember-data/attr'; import { belongsTo, hasMany } from 'ember-data/relationships'; import ContainsCodeMixin from '../mixins/contains-code'; +/** + Task is a (issue/idea/task) created by a user for a project. + + @class task + @module Model + @extends Ember.Model + */ export default Model.extend(ContainsCodeMixin, { + + /** + The tasks body content. + + @attribute body + @type string + */ body: attr(), + + /** + The date that the task was inserted. + + @attribute insertedAt + @type date + */ insertedAt: attr('date'), + + /** + The tasks markdown content. + + @attribute markdown + @type string + */ markdown: attr(), + + /** + The tasks client facing number. + + @attribute number + @type number + */ number: attr('number'), + + /** + Order is a read-only attribute computed from the `position` attribute + + @attribute order + @readonly + @type number + */ + order: attr(), + + /** + The task's type (issue/task/idea/etc.) + + @attribute taskType + @type string + */ taskType: attr(), + + /** + The task's status (open/closed) + + @attribute status + @type string + */ status: attr(), + + /** + The task's title + + @attribute title + @type string + */ title: attr(), + /** + Position is a virtual (write-only) attribute used to compute the `order` of the task + + @attribute position + @virtual + @type number + */ + position: attr(), + + /** + The comments that belong to the task + + @attribute comments + @type Ember.computed + */ comments: hasMany('comment', { async: true }), + + /** + The comment user mentions that belong to the task + + @attribute commentUserMentions + @type Ember.computed + */ commentUserMentions: hasMany('comment-user-mention', { asnyc: true }), + + /** + The task-list that the task belongs to + + @attribute task-list + @type Ember.computed + */ + taskList: belongsTo('task-list', { async: true }), + + /** + The task user mentions that belong to the task. + + @attribute taskUserMentions + @type Ember.computed + */ taskUserMentions: hasMany('task-user-mention', { asnyc: true }), + + /** + The project that the task belongs to + + @attribute project + @type Ember.computed + */ project: belongsTo('project', { async: true }), + + /** + The user that the task belongs to + + @attribute user + @type Ember.computed + */ user: belongsTo('user', { async: true }) }); diff --git a/mirage/config.js b/mirage/config.js index 567b4b134..05f1976d5 100644 --- a/mirage/config.js +++ b/mirage/config.js @@ -63,7 +63,7 @@ function generatePreviewMentions(schema, preview) { // The set of routes we have defined; needs updated when adding new routes const routes = [ - 'categories', 'comment-user-mentions', 'comments', 'donation-goals', 'organizations', + 'categories', 'comment-user-mentions', 'comments', 'donation-goals', 'organizations', 'task-lists', 'task-user-mentions', 'tasks', 'previews', 'projects', 'project-categories', 'slugged-routes', 'stripe-connect-accounts', 'stripe-connect-subscriptions', 'stripe-connect-plans', 'stripe-platform-cards', 'stripe-platform-customers', @@ -427,6 +427,16 @@ export default function() { this.post('/stripe-connect-subscriptions'); this.get('/stripe-connect-subscriptions/:id'); + /** + * Task lists + */ + + // GET /task-lists + this.get('/task-lists', { coalesce: true }); + + // GET /task-lists/:id + this.get('/task-lists/:id'); + /** * Task user mentions */ @@ -476,6 +486,7 @@ export default function() { task.attrs = attrs; task.taskUserMentions.models.forEach((mention) => mention.destroy()); + task.order = (task.position || 0) * 100; task.save(); return task; diff --git a/mirage/factories/task-list.js b/mirage/factories/task-list.js new file mode 100644 index 000000000..a0aec4bd5 --- /dev/null +++ b/mirage/factories/task-list.js @@ -0,0 +1,10 @@ +import { Factory } from 'ember-cli-mirage'; + +export default Factory.extend({ + order() { + return (this.position || 0) * 100; + }, + position(i) { + return i + 1; + } +}); diff --git a/mirage/factories/task.js b/mirage/factories/task.js index 550d25171..b3f7bfd53 100644 --- a/mirage/factories/task.js +++ b/mirage/factories/task.js @@ -11,6 +11,12 @@ export default Factory.extend({ number(i) { return i + 1; }, + order() { + return (this.position || 0) * 100; + }, + position(i) { + return i + 1; + }, status: 'open', taskType: faker.list.cycle('task', 'idea', 'issue'), title() { diff --git a/mirage/models/project.js b/mirage/models/project.js index 153f3e426..333fad709 100644 --- a/mirage/models/project.js +++ b/mirage/models/project.js @@ -3,6 +3,7 @@ import { Model, belongsTo, hasMany } from 'ember-cli-mirage'; export default Model.extend({ donationGoals: hasMany(), organization: belongsTo(), + taskLists: hasMany(), tasks: hasMany(), projectCategories: hasMany(), projectSkills: hasMany(), diff --git a/mirage/models/task-list.js b/mirage/models/task-list.js new file mode 100644 index 000000000..2caed2f6f --- /dev/null +++ b/mirage/models/task-list.js @@ -0,0 +1,6 @@ +import { Model, belongsTo, hasMany } from 'ember-cli-mirage'; + +export default Model.extend({ + project: belongsTo(), + tasks: hasMany() +}); diff --git a/mirage/models/task.js b/mirage/models/task.js index e0c7bc672..d4eb85b0e 100644 --- a/mirage/models/task.js +++ b/mirage/models/task.js @@ -3,6 +3,7 @@ import { Model, belongsTo, hasMany } from 'ember-cli-mirage'; export default Model.extend({ comments: hasMany(), commentUserMentions: hasMany(), + taskList: belongsTo(), taskUserMentions: hasMany(), project: belongsTo(), user: belongsTo() diff --git a/mirage/scenarios/default.js b/mirage/scenarios/default.js index c3a120028..1a426f74b 100644 --- a/mirage/scenarios/default.js +++ b/mirage/scenarios/default.js @@ -236,9 +236,45 @@ export default function(server) { username: 'random' }); - server.createList('task', 10, { project, taskType: 'idea', user: owner }); - server.createList('task', 10, { project, taskType: 'issue', user: owner }); - server.createList('task', 10, { project, taskType: 'task', user: owner }); + let inboxTaskList = server.create('taskList', { + name: 'Inbox', + position: 0, + project + }); + + let backlogTaskList = server.create('taskList', { + name: 'Backlog', + position: 1, + project + }); + + let inProgressTaskList = server.create('taskList', { + name: 'In Progress', + position: 2, + project + }); + + let doneTaskList = server.create('taskList', { + name: 'Done', + position: 3, + project + }); + + server.createList('task', 2, { project, taskList: inboxTaskList, taskType: 'idea', user: owner }); + server.createList('task', 1, { project, taskList: inboxTaskList, taskType: 'issue', user: owner }); + server.createList('task', 1, { project, taskList: inboxTaskList, taskType: 'task', user: owner }); + + server.createList('task', 1, { project, taskList: backlogTaskList, taskType: 'idea', user: owner }); + server.createList('task', 1, { project, taskList: backlogTaskList, taskType: 'issue', user: owner }); + server.createList('task', 2, { project, taskList: backlogTaskList, taskType: 'task', user: owner }); + + server.createList('task', 1, { project, taskList: inProgressTaskList, taskType: 'idea', user: owner }); + server.createList('task', 3, { project, taskList: inProgressTaskList, taskType: 'issue', user: owner }); + server.createList('task', 2, { project, taskList: inProgressTaskList, taskType: 'task', user: owner }); + + server.createList('task', 1, { project, taskList: doneTaskList, taskType: 'idea', user: owner }); + server.createList('task', 1, { project, taskList: doneTaskList, taskType: 'issue', user: owner }); + server.createList('task', 1, { project, taskList: doneTaskList, taskType: 'task', user: owner }); let skillTitles = ['CSS', 'Ember.js', 'HTML']; diff --git a/tests/unit/models/project-test.js b/tests/unit/models/project-test.js index a29e9941d..e6b231448 100644 --- a/tests/unit/models/project-test.js +++ b/tests/unit/models/project-test.js @@ -18,6 +18,7 @@ moduleForModel('project', 'Unit | Model | project', { 'model:stripe-connect-account', 'model:stripe-connect-plan', 'model:task', + 'model:task-list', 'model:user' ] }); @@ -40,6 +41,7 @@ testForBelongsTo('project', 'stripeConnectPlan'); testForHasMany('project', 'donationGoals'); testForHasMany('project', 'projectCategories'); testForHasMany('project', 'projectSkills'); +testForHasMany('project', 'taskLists'); testForHasMany('project', 'tasks'); test('it should have open tasks', function(assert) { diff --git a/tests/unit/models/task-list-test.js b/tests/unit/models/task-list-test.js new file mode 100644 index 000000000..9b5c204d4 --- /dev/null +++ b/tests/unit/models/task-list-test.js @@ -0,0 +1,20 @@ +import { moduleForModel, test } from 'ember-qunit'; +import { testForAttributes } from 'code-corps-ember/tests/helpers/attributes'; +import { testForBelongsTo, testForHasMany } from '../../helpers/relationship'; + +moduleForModel('task-list', 'Unit | Model | task list', { + // Specify the other units that are required for this test. + needs: [ + 'model:project', + 'model:task' + ] +}); + +test('it exists', function(assert) { + let model = this.subject(); + assert.ok(!!model); +}); + +testForAttributes('task-list', ['name', 'order', 'position']); +testForBelongsTo('task-list', 'project'); +testForHasMany('task-list', 'tasks'); diff --git a/tests/unit/models/task-test.js b/tests/unit/models/task-test.js index 214244ecd..50942b1b9 100644 --- a/tests/unit/models/task-test.js +++ b/tests/unit/models/task-test.js @@ -8,6 +8,7 @@ moduleForModel('task', 'Unit | Model | task', { 'model:comment', 'model:comment-user-mention', 'model:project', + 'model:task-list', 'model:task-user-mention', 'model:user' ] @@ -18,8 +19,9 @@ test('it exists', function(assert) { assert.ok(!!model); }); -testForAttributes('task', ['body', 'insertedAt', 'markdown', 'number', 'status', 'taskType', 'title']); +testForAttributes('task', ['body', 'insertedAt', 'markdown', 'number', 'order', 'position', 'status', 'taskType', 'title']); testForBelongsTo('task', 'project'); +testForBelongsTo('task', 'taskList'); testForBelongsTo('task', 'user'); testForHasMany('task', 'comments'); testForHasMany('task', 'commentUserMentions'); diff --git a/tests/unit/serializers/task-test.js b/tests/unit/serializers/task-test.js index 51128ed42..5a49f1a93 100644 --- a/tests/unit/serializers/task-test.js +++ b/tests/unit/serializers/task-test.js @@ -8,6 +8,7 @@ moduleForModel('task', 'Unit | Serializer | task', { 'model:user', 'model:comment', 'model:comment-user-mention', + 'model:task-list', 'model:task-user-mention' ] });