Skip to content

Commit

Permalink
Merge pull request #1048 from code-corps/np-task-card-add-assignee
Browse files Browse the repository at this point in the history
Add assignee to task card
  • Loading branch information
joshsmith committed Feb 17, 2017
2 parents 67e69b5 + 320cbd2 commit ffaa849
Show file tree
Hide file tree
Showing 43 changed files with 1,189 additions and 75 deletions.
1 change: 1 addition & 0 deletions app/abilities/task.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export default Ability.extend({
userIsAtLeastAdmin: or('membership.isAdmin', 'membership.isOwner'),
userIsAtLeastContributor: or('membership.isContributor', 'userIsAtLeastAdmin'),

canAssign: or('userIsAuthor', 'userIsAtLeastContributor'),
canEdit: or('userIsAuthor', 'userIsAtLeastAdmin'),
canReposition: or('userIsAuthor', 'userIsAtLeastContributor')
});
1 change: 1 addition & 0 deletions app/components/project-category-item.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const {
@extends Ember.Component
*/
export default Component.extend({
classNames: ['project-category-item'],
tagName: ['li'],

/**
Expand Down
File renamed without changes.
4 changes: 4 additions & 0 deletions app/components/task-card.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ export default Component.extend({
trueValue: true,

ability: EmberCan.computed.ability('task'),
canAssign: alias('ability.canAssign'),
canEdit: alias('ability.canEdit'),
canReposition: alias('ability.canReposition'),

'data-can-reposition': computed('canReposition', function() {
Expand All @@ -29,6 +31,8 @@ export default Component.extend({
'data-model-id': alias('task.id'),
'data-model-type': 'task',

assignedUser: alias('task.assignedUser'),

isLoading: alias('task.isLoading'),

taskType: alias('task.taskType'),
Expand Down
54 changes: 54 additions & 0 deletions app/components/task/user/user-select.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import Ember from 'ember';

const {
Component,
computed,
computed: { alias, or },
inject: { service },
get,
set
} = Ember;

export default Component.extend({
store: service(),

classNames: ['task__user__user-select'],
classNameBindings: ['canEdit:task__user__user-select--can-edit', 'isLoading:task__user__user-select--is-loading'],
tagName: 'p',

constraints: [{
to: 'scrollParent',
attachment: 'together',
pin: true
}],
showUsers: false,
isHovering: false,
limit: 10,

isLoading: or('userIsLoading', 'userTaskIsLoading'),
userIsLoading: alias('user.isLoading'),
userTaskIsLoading: alias('userTask.isLoading'),

target: computed('elementId', function() {
return `#${get(this, 'elementId')}`;
}),

click(/* event */) {
let canEdit = get(this, 'canEdit');
if (!canEdit) {
return true; // bubble event to be a click on the task card
}

let initiallyHidden = get(this, 'showUsers');
set(this, 'showUsers', true);
if (!initiallyHidden) {
return false;
}
},

actions: {
hide(/* event */) {
set(this, 'showUsers', false);
}
}
});
47 changes: 47 additions & 0 deletions app/components/task/user/users-list-item.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import Ember from 'ember';

const {
Component,
computed,
get
} = Ember;

export default Component.extend({
classNameBindings: ['assigned:task__user__users-list-item--assigned', 'selected:selected'],
classNames: ['task__user__users-list-item'],
tagName: ['li'],

assigned: computed('user', 'userTask', function() {
let user = get(this, 'user');
let existingUser = get(this, 'userTask.user');
return existingUser && get(existingUser, 'id') == get(user, 'id');
}),

mouseDown() {
let user = get(this, 'user');
this.sendAction('selectUser', user);
},

mouseEnter() {
let user = get(this, 'user');
this.sendAction('hover', user);
}

// selectedChanged: observer('selected', function() {
// once(this, '_scroll');
// }),
//
// target: computed('elementId', function() {
// return `#${get(this, 'elementId')}`;
// }),
//
// _scroll() {
// let item = this.$();
// let itemHeight = item.height();
// let itemTop = item.offset().top;
// let list = item.parent();
// let listHeight = list.height();
// let position = itemTop - itemHeight;
// list.scrollTop(position);
// }
});
185 changes: 185 additions & 0 deletions app/components/task/user/users-list.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
import Ember from 'ember';
import { getCode } from 'ember-keyboard';

const {
Component,
computed,
computed: { alias, not },
get,
getProperties,
inject: { service },
isEmpty,
observer,
run: { bind, once },
set
} = Ember;

export default Component.extend({
classNames: ['select-dropdown', 'task__user__users-list'],
tagName: 'div',
cursorAt: 0,
cursorWas: 0,
lastQuery: null,
limit: 5,
results: [],

store: service(),
taskAssignment: service(),

numberOfResults: alias('results.length'),
queryChanged: observer('query', function() {
once(this, '_search');
}),

_isNewQuery: not('_sameQuery'),
_sameQuery: computed('query', 'lastQuery', function() {
return get(this, 'query') === get(this, 'lastQuery');
}),

init() {
this._super(...arguments);
let limit = get(this, 'limit');
set(this, 'keyboardActivated', true);
set(this, 'boundKeyHandler', bind(this, this.keyHandler));
this._searchUsers('', limit);
},

didInsertElement() {
this.$(window).on('keydown', this.boundKeyHandler);
},

willDestroyElement() {
this.$(window).off('keydown', this.boundKeyHandler);
},

keyHandler(e) {
let key = getCode(e);
switch (key) {
case 'Escape':
this.send('getKeyDown', key);
break;
default:
break;
}
},

actions: {
getKeyDown(key) {
let cursorAt;
switch (key) {
case 'ArrowDown':
cursorAt = get(this, 'cursorAt');
this._setPosition(++cursorAt);
break;
case 'ArrowUp':
cursorAt = get(this, 'cursorAt');
this._setPosition(--cursorAt);
break;
case 'Enter':
this._selectUser();
break;
case 'Escape':
this._reset();
break;
default:
break;
}
},

hide() {
this.sendAction();
},

hoverUser(user) {
get(this, 'results').forEach((item, index) => {
if (item === user) {
set(this, 'cursorAt', index);
set(item, 'selected', true);
} else {
set(item, 'selected', false);
}
});
},

selectUser(user) {
this._selectUser(user);
this.sendAction();
}
},

_clearQuery() {
set(this, 'query', '');
set(this, 'lastQuery', '');
},

_reset() {
this._clearQuery();
set(this, 'results', []);
this.sendAction();
},

_search() {
let { limit, query } = getProperties(this, 'limit', 'query');

if (isEmpty(query)) {
this._clearQuery();
} else if (get(this, '_isNewQuery')) {
this._searchUsers(query, limit);
}
},

_searchUsers(query, limit) {
let store = get(this, 'store');
set(this, 'lastQuery', query);
store.query('user', { query, limit }).then((users) => {
set(this, 'results', users);
set(this, 'cursorAt', 0);
this._updateSelected();
});
},

async _selectUser(user) {
let { task, taskAssignment }
= getProperties(this, 'task', 'taskAssignment');

let taskIsAssignedToUser = await taskAssignment.isAssignedTo(task, user);

if (taskIsAssignedToUser) {
return taskAssignment.unassign(task);
} else {
return taskAssignment.assign(task, user);
}

},

_setPosition(position) {
let numberOfResults = get(this, 'numberOfResults');
let numberOfResultsIndexed = numberOfResults - 1;

set(this, 'cursorWas', get(this, 'cursorAt'));

if (numberOfResults > 0) {
if (position < 0) {
set(this, 'cursorAt', numberOfResultsIndexed);
} else if (position > numberOfResultsIndexed) {
set(this, 'cursorAt', 0);
} else {
set(this, 'cursorAt', position);
}
}

this._updateSelected();
},

_updateSelected() {
let cursorAt = get(this, 'cursorAt');

get(this, 'results').forEach((item, index) => {
if (index === cursorAt) {
set(item, 'selected', true);
} else {
set(item, 'selected', false);
}
});
}
});
10 changes: 9 additions & 1 deletion app/models/task.js
Original file line number Diff line number Diff line change
Expand Up @@ -134,5 +134,13 @@ export default Model.extend(ContainsCodeMixin, {
@attribute user
@type Ember.computed
*/
user: belongsTo('user', { async: true })
user: belongsTo('user', { async: true }),

/**
The user task relationshipp
@attribute userTask
@type Ember.computed
*/
userTask: belongsTo('user-task', { async: true })
});
7 changes: 7 additions & 0 deletions app/models/user-task.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import Model from 'ember-data/model';
import { belongsTo } from 'ember-data/relationships';

export default Model.extend({
task: belongsTo('task', { async: true }),
user: belongsTo('user', { async: true })
});
44 changes: 44 additions & 0 deletions app/services/task-assignment.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import Ember from 'ember';

const {
get,
inject: { service },
Service,
set
} = Ember;

export default Service.extend({
store: service(),

async isAssignedTo(task, user) {
return await get(task, 'userTask.user.id') === get(user, 'id');
},

async assign(task, user) {
let userTask = await get(task, 'userTask');
return userTask ? this._update(userTask, user) : this._create(user, task);
},

async unassign(task) {
let userTask = await get(task, 'userTask');

if (userTask) {
return this._destroy(userTask);
}
},

_create(user, task) {
let store = get(this, 'store');
return store.createRecord('user-task', { user, task })
.save();
},

_destroy(userTask) {
return userTask.destroyRecord();
},

_update(userTask, user) {
set(userTask, 'user', user);
return userTask.save();
}
});
2 changes: 1 addition & 1 deletion app/styles/_inputs.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
font-size: $body-font-size-normal;
margin: 0;
outline: none;
border: 1px solid $gray;
border: 1px solid $gray--light;
border-radius: 4px;
box-shadow: inset 0 1px 2px rgba(0,0,0,0.075);
background-color: #FAFAFA;
Expand Down
Loading

0 comments on commit ffaa849

Please sign in to comment.