Skip to content

Commit

Permalink
Drag challenge tasks (#12204)
Browse files Browse the repository at this point in the history
* Allow challenge tasks to be draggable by leaders and admins

* Drag challenge tasks, ensure they're ordered

* Ensure group tasks are ordered properly, make draggable

* Add tests, fix broken tests

* Resolve merge conflict

* Remove console.log()

* Address code review comments

* Code review fixes

* Fix lint

* Fix importing

* taskManager

* Lint

* Fix collapseChecklist test

Co-authored-by: Sabe Jones <[email protected]>
  • Loading branch information
alecbrick and SabreCat authored Apr 30, 2021
1 parent a533558 commit f33720e
Show file tree
Hide file tree
Showing 17 changed files with 340 additions and 256 deletions.
4 changes: 3 additions & 1 deletion test/api/unit/libs/taskManager.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import {
createTasks,
getTasks,
} from '../../../../website/server/libs/tasks';
import {
syncableAttrs,
moveTask,
} from '../../../../website/server/libs/taskManager';
} from '../../../../website/server/libs/tasks/utils';
import i18n from '../../../../website/common/script/i18n';
import shared from '../../../../website/common/script';
import {
Expand Down
1 change: 0 additions & 1 deletion test/api/v3/integration/tasks/DELETE-tasks_id.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ describe('DELETE /tasks/:id', () => {

it('deletes a user\'s task', async () => {
await user.del(`/tasks/${task._id}`);

await expect(user.get(`/tasks/${task._id}`)).to.eventually.be.rejected.and.eql({
code: 404,
error: 'NotFound',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ describe('POST /tasks/unlink-all/:challengeId', () => {
await user.del(`/challenges/${challenge._id}`);
await user.post(`/tasks/unlink-all/${challenge._id}?keep=keep-all`);
// Get the task for the second user
const [, anotherUserTask] = await anotherUser.get('/tasks/user');
const [anotherUserTask] = await anotherUser.get('/tasks/user');
// Expect the second user to still have the task, but unlinked
expect(anotherUserTask.challenge).to.eql({
taskId: daily._id,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,16 +92,16 @@ describe('POST /tasks/unlink-one/:taskId', () => {

it('unlinks a task from a challenge and saves it on keep=keep', async () => {
await user.post(`/tasks/challenge/${challenge._id}`, tasksToTest.daily);
let [, daily] = await user.get('/tasks/user');
let [daily] = await user.get('/tasks/user');
await user.del(`/challenges/${challenge._id}`);
await user.post(`/tasks/unlink-one/${daily._id}?keep=keep`);
[, daily] = await user.get('/tasks/user');
[daily] = await user.get('/tasks/user');
expect(daily.challenge).to.eql({});
});

it('unlinks a task from a challenge and deletes it on keep=remove', async () => {
await user.post(`/tasks/challenge/${challenge._id}`, tasksToTest.daily);
const [, daily] = await user.get('/tasks/user');
const [daily] = await user.get('/tasks/user');
await user.del(`/challenges/${challenge._id}`);
await user.post(`/tasks/unlink-one/${daily._id}?keep=remove`);
const tasks = await user.get('/tasks/user');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,17 @@ describe('GET /tasks/challenge/:challengeId', () => {
up: false,
down: true,
},
todo: {
text: 'test todo',
type: 'todo',
},
daily: {
text: 'test daily',
type: 'daily',
frequency: 'daily',
everyX: 5,
startDate: new Date(),
},
todo: {
text: 'test todo',
type: 'todo',
},
reward: {
text: 'test reward',
type: 'reward',
Expand Down Expand Up @@ -84,4 +84,35 @@ describe('GET /tasks/challenge/:challengeId', () => {
});
});
});

it('maintains challenge task order', async () => {
const orderedTasks = {};
Object.entries(tasksToTest).forEach(async (taskType, taskValue) => {
const results = [];
for (let i = 0; i < 5; i += 1) {
results.push(user.post(`/tasks/challenge/${challenge._id}`, taskValue));
}
const taskList = await Promise.all(results);
await user.post(`/tasks/${taskList[0]._id}/move/to/3`);

const firstTask = taskList.unshift();
taskList.splice(3, 0, firstTask);

orderedTasks[taskType] = taskList;
});

const results = await user.get(`/tasks/challenge/${challenge._id}`);
const resultTasks = {};

results.forEach(result => {
if (!resultTasks[result.type]) {
resultTasks[result.type] = [];
}
resultTasks[result.type].push(result);
});

Object.entries(orderedTasks).forEach((taskType, taskList) => {
expect(resultTasks[taskType]).to.eql(taskList);
});
});
});
39 changes: 35 additions & 4 deletions test/api/v3/integration/tasks/groups/GET-tasks_group_id.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,17 @@ describe('GET /tasks/group/:groupId', () => {
up: false,
down: true,
},
todo: {
text: 'test todo',
type: 'todo',
},
daily: {
text: 'test daily',
type: 'daily',
frequency: 'daily',
everyX: 5,
startDate: new Date(),
},
todo: {
text: 'test todo',
type: 'todo',
},
reward: {
text: 'test reward',
type: 'reward',
Expand Down Expand Up @@ -78,4 +78,35 @@ describe('GET /tasks/group/:groupId', () => {
});
});
});

it('maintains group task order', async () => {
const orderedTasks = {};
Object.entries(tasksToTest).forEach(async (taskType, taskValue) => {
const results = [];
for (let i = 0; i < 5; i += 1) {
results.push(user.post(`/tasks/group/${group._id}`, taskValue));
}
const taskList = await Promise.all(results);
await user.post(`/tasks/${taskList[0]._id}/move/to/3`);

const firstTask = taskList.unshift();
taskList.splice(3, 0, firstTask);

orderedTasks[taskType] = taskList;
});

const results = await user.get(`/tasks/group/${group._id}`);
const resultTasks = {};

results.forEach(result => {
if (!resultTasks[result.type]) {
resultTasks[result.type] = [];
}
resultTasks[result.type].push(result);
});

Object.entries(orderedTasks).forEach((taskType, taskList) => {
expect(resultTasks[taskType]).to.eql(taskList);
});
});
});
3 changes: 2 additions & 1 deletion website/client/src/components/challenges/challengeDetail.vue
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@
:type="column"
:task-list-override="tasksByType[column]"
:challenge="challenge"
:draggable-override="isLeader || isAdmin"
@editTask="editTask"
@taskDestroyed="taskDestroyed"
/>
Expand Down Expand Up @@ -512,7 +513,7 @@ export default {
this.creatingTask = null;
},
taskCreated (task) {
this.tasksByType[task.type].push(task);
this.tasksByType[task.type].unshift(task);
},
taskEdited (task) {
const index = findIndex(this.tasksByType[task.type], taskItem => taskItem._id === task._id);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
:task-list-override="tasksByType[column]"
:group="group"
:search-text="searchText"
:draggable-override="canCreateTasks"
@editTask="editTask"
@loadGroupCompletedTodos="loadGroupCompletedTodos"
@taskDestroyed="taskDestroyed"
Expand Down Expand Up @@ -295,7 +296,7 @@ export default {
},
taskCreated (task) {
task.group.id = this.group._id;
this.tasksByType[task.type].push(task);
this.tasksByType[task.type].unshift(task);
},
taskEdited (task) {
const index = findIndex(this.tasksByType[task.type], taskItem => taskItem._id === task._id);
Expand Down
11 changes: 10 additions & 1 deletion website/client/src/components/tasks/column.vue
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@
v-if="taskList.length > 0"
ref="tasksList"
class="sortable-tasks"
:options="{disabled: activeFilter.label === 'scheduled' || !isUser, scrollSensitivity: 64}"
:options="{disabled: activeFilter.label === 'scheduled' || !canBeDragged(),
scrollSensitivity: 64}"
:delay-on-touch-only="true"
:delay="100"
@update="taskSorted"
Expand Down Expand Up @@ -391,6 +392,10 @@ export default {
type: Boolean,
default: false,
},
draggableOverride: {
type: Boolean,
default: false,
},
searchText: {},
selectedTags: {},
taskListOverride: {},
Expand Down Expand Up @@ -767,6 +772,10 @@ export default {
taskDestroyed (task) {
this.$emit('taskDestroyed', task);
},
canBeDragged () {
return this.isUser
|| this.draggableOverride;
},
},
};
</script>
2 changes: 1 addition & 1 deletion website/server/controllers/api-v3/challenges.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import * as Tasks from '../../models/task';
import csvStringify from '../../libs/csvStringify';
import {
createTasks,
} from '../../libs/taskManager';
} from '../../libs/tasks';

import {
addUserJoinChallengeNotification,
Expand Down
Loading

0 comments on commit f33720e

Please sign in to comment.