Improve subtask toggle
@@ -48,14 +48,12 @@ class SubtaskRestrictionController extends BaseController
|
|||||||
$this->subtaskModel->update(array(
|
$this->subtaskModel->update(array(
|
||||||
'id' => $values['id'],
|
'id' => $values['id'],
|
||||||
'status' => $values['status'],
|
'status' => $values['status'],
|
||||||
'task_id' => $task['id'],
|
|
||||||
));
|
));
|
||||||
|
|
||||||
// Set the current subtask to "in progress"
|
// Set the current subtask to "in progress"
|
||||||
$this->subtaskModel->update(array(
|
$this->subtaskModel->update(array(
|
||||||
'id' => $subtask['id'],
|
'id' => $subtask['id'],
|
||||||
'status' => SubtaskModel::STATUS_INPROGRESS,
|
'status' => SubtaskModel::STATUS_INPROGRESS,
|
||||||
'task_id' => $task['id'],
|
|
||||||
));
|
));
|
||||||
|
|
||||||
$this->response->redirect($this->helper->url->to('TaskViewController', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id'])), true);
|
$this->response->redirect($this->helper->url->to('TaskViewController', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id'])), true);
|
||||||
|
|||||||
@@ -19,11 +19,20 @@ class SubtaskStatusController extends BaseController
|
|||||||
{
|
{
|
||||||
$task = $this->getTask();
|
$task = $this->getTask();
|
||||||
$subtask = $this->getSubtask();
|
$subtask = $this->getSubtask();
|
||||||
|
$fragment = $this->request->getStringParam('fragment');
|
||||||
|
|
||||||
$status = $this->subtaskStatusModel->toggleStatus($subtask['id']);
|
$status = $this->subtaskStatusModel->toggleStatus($subtask['id']);
|
||||||
$subtask['status'] = $status;
|
$subtask['status'] = $status;
|
||||||
|
|
||||||
$this->response->html($this->helper->subtask->renderToggleStatus($task, $subtask));
|
if ($fragment === 'table') {
|
||||||
|
$html = $this->renderTable($task);
|
||||||
|
} elseif ($fragment === 'rows') {
|
||||||
|
$html = $this->renderRows($task);
|
||||||
|
} else {
|
||||||
|
$html = $this->helper->subtask->renderToggleStatus($task, $subtask);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->response->html($html);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -49,4 +58,43 @@ class SubtaskStatusController extends BaseController
|
|||||||
'subtask' => $this->subtaskModel->getByIdWithDetails($subtaskId),
|
'subtask' => $this->subtaskModel->getByIdWithDetails($subtaskId),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render table
|
||||||
|
*
|
||||||
|
* @access protected
|
||||||
|
* @param array $task
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function renderTable(array $task)
|
||||||
|
{
|
||||||
|
return $this->template->render('subtask/table', array(
|
||||||
|
'task' => $task,
|
||||||
|
'subtasks' => $this->subtaskModel->getAll($task['id']),
|
||||||
|
'editable' => true,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render task list rows
|
||||||
|
*
|
||||||
|
* @access protected
|
||||||
|
* @param array $task
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function renderRows(array $task)
|
||||||
|
{
|
||||||
|
$userId = $this->request->getIntegerParam('user_id');
|
||||||
|
|
||||||
|
if ($userId > 0) {
|
||||||
|
$task['subtasks'] = $this->subtaskModel->getAllByTaskIdsAndAssignee(array($task['id']), $userId);
|
||||||
|
} else {
|
||||||
|
$task['subtasks'] = $this->subtaskModel->getAll($task['id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->template->render('task_list/task_subtasks', array(
|
||||||
|
'task' => $task,
|
||||||
|
'user_id' => $userId,
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,20 +45,24 @@ class SubtaskHelper extends Base
|
|||||||
* Get the link to toggle subtask status
|
* Get the link to toggle subtask status
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
* @param array $task
|
* @param array $task
|
||||||
* @param array $subtask
|
* @param array $subtask
|
||||||
|
* @param string $fragment
|
||||||
|
* @param int $userId
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function renderToggleStatus(array $task, array $subtask)
|
public function renderToggleStatus(array $task, array $subtask, $fragment = '', $userId = 0)
|
||||||
{
|
{
|
||||||
if (! $this->helper->user->hasProjectAccess('SubtaskController', 'edit', $task['project_id'])) {
|
if (! $this->helper->user->hasProjectAccess('SubtaskController', 'edit', $task['project_id'])) {
|
||||||
$html = $this->renderTitle($subtask);
|
$html = $this->renderTitle($subtask);
|
||||||
} else {
|
} else {
|
||||||
$title = $this->renderTitle($subtask);
|
$title = $this->renderTitle($subtask);
|
||||||
$params = array(
|
$params = array(
|
||||||
'project_id' => $task['project_id'],
|
'project_id' => $task['project_id'],
|
||||||
'task_id' => $subtask['task_id'],
|
'task_id' => $subtask['task_id'],
|
||||||
'subtask_id' => $subtask['id'],
|
'subtask_id' => $subtask['id'],
|
||||||
|
'user_id' => $userId,
|
||||||
|
'fragment' => $fragment,
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($subtask['status'] == 0 && $this->hasSubtaskInProgress()) {
|
if ($subtask['status'] == 0 && $this->hasSubtaskInProgress()) {
|
||||||
|
|||||||
@@ -218,10 +218,11 @@ class SubtaskModel extends Base
|
|||||||
$result = $this->db->table(self::TABLE)->eq('id', $values['id'])->save($values);
|
$result = $this->db->table(self::TABLE)->eq('id', $values['id'])->save($values);
|
||||||
|
|
||||||
if ($result) {
|
if ($result) {
|
||||||
$this->subtaskTimeTrackingModel->updateTaskTimeTracking($values['task_id']);
|
$subtask = $this->getById($values['id']);
|
||||||
|
$this->subtaskTimeTrackingModel->updateTaskTimeTracking($subtask['task_id']);
|
||||||
|
|
||||||
if ($fireEvent) {
|
if ($fireEvent) {
|
||||||
$this->queueManager->push($this->subtaskEventJob->withParams($values['id'], self::EVENT_UPDATE, $values));
|
$this->queueManager->push($this->subtaskEventJob->withParams($subtask['id'], self::EVENT_UPDATE, $values));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -69,7 +69,8 @@
|
|||||||
)) ?>
|
)) ?>
|
||||||
|
|
||||||
<?= $this->render('task_list/task_subtasks', array(
|
<?= $this->render('task_list/task_subtasks', array(
|
||||||
'task' => $task,
|
'task' => $task,
|
||||||
|
'user_id' => $user['id'],
|
||||||
)) ?>
|
)) ?>
|
||||||
</div>
|
</div>
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
'task' => $task,
|
'task' => $task,
|
||||||
'subtask' => $subtask,
|
'subtask' => $subtask,
|
||||||
)) ?>
|
)) ?>
|
||||||
<?= $this->subtask->renderToggleStatus($task, $subtask, true) ?>
|
<?= $this->subtask->renderToggleStatus($task, $subtask, 'table') ?>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<?= $this->subtask->renderTitle($subtask) ?>
|
<?= $this->subtask->renderTitle($subtask) ?>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<?php foreach ($task['subtasks'] as $subtask): ?>
|
<?php foreach ($task['subtasks'] as $subtask): ?>
|
||||||
<div class="task-list-subtask">
|
<div class="task-list-subtask">
|
||||||
<span class="subtask-cell column-50">
|
<span class="subtask-cell column-50">
|
||||||
<?= $this->subtask->renderToggleStatus($task, $subtask) ?>
|
<?= $this->subtask->renderToggleStatus($task, $subtask, 'rows', isset($user_id) ? $user_id : 0) ?>
|
||||||
</span>
|
</span>
|
||||||
<span class="subtask-cell column-20 subtask-assignee">
|
<span class="subtask-cell column-20 subtask-assignee">
|
||||||
<?php if (! empty($subtask['username'])): ?>
|
<?php if (! empty($subtask['username'])): ?>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 6.9 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 6.9 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 6.9 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 6.3 KiB |
6
assets/css/vendor.min.css
vendored
4
assets/js/app.min.js
vendored
44
assets/js/components/subtask-drag-and-drop.js
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
KB.on('dom.ready', function() {
|
||||||
|
|
||||||
|
function savePosition(subtaskId, position) {
|
||||||
|
var url = $(".subtasks-table").data("save-position-url");
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
cache: false,
|
||||||
|
url: url,
|
||||||
|
contentType: "application/json",
|
||||||
|
type: "POST",
|
||||||
|
processData: false,
|
||||||
|
data: JSON.stringify({
|
||||||
|
"subtask_id": subtaskId,
|
||||||
|
"position": position
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$(".draggable-row-handle").mouseenter(function() {
|
||||||
|
$(this).parent().parent().addClass("draggable-item-hover");
|
||||||
|
}).mouseleave(function() {
|
||||||
|
$(this).parent().parent().removeClass("draggable-item-hover");
|
||||||
|
});
|
||||||
|
|
||||||
|
$(".subtasks-table tbody").sortable({
|
||||||
|
forcePlaceholderSize: true,
|
||||||
|
handle: "td:first i",
|
||||||
|
helper: function(e, ui) {
|
||||||
|
ui.children().each(function() {
|
||||||
|
$(this).width($(this).width());
|
||||||
|
});
|
||||||
|
|
||||||
|
return ui;
|
||||||
|
},
|
||||||
|
stop: function(event, ui) {
|
||||||
|
var subtask = ui.item;
|
||||||
|
subtask.removeClass("draggable-item-selected");
|
||||||
|
savePosition(subtask.data("subtask-id"), subtask.index() + 1);
|
||||||
|
},
|
||||||
|
start: function(event, ui) {
|
||||||
|
ui.item.addClass("draggable-item-selected");
|
||||||
|
}
|
||||||
|
}).disableSelection();
|
||||||
|
});
|
||||||
35
assets/js/components/subtask-toggle-status.js
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
KB.on('dom.ready', function () {
|
||||||
|
$(document).on('click', '.js-subtask-toggle-status', function(e) {
|
||||||
|
var el = $(this);
|
||||||
|
var url = el.attr('href');
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
cache: false,
|
||||||
|
url: url,
|
||||||
|
success: function(data) {
|
||||||
|
if (url.indexOf('fragment=table') != -1) {
|
||||||
|
$('.subtasks-table').replaceWith(data);
|
||||||
|
} else if (url.indexOf('fragment=rows') != -1) {
|
||||||
|
$(el).closest('.task-list-subtasks').replaceWith(data);
|
||||||
|
} else {
|
||||||
|
$(el).closest('.subtask-title').replaceWith(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$(document).on('click', '.js-subtask-toggle-timer', function(e) {
|
||||||
|
var el = $(this);
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
cache: false,
|
||||||
|
url: el.attr('href'),
|
||||||
|
success: function(data) {
|
||||||
|
$(el).closest('.subtask-time-tracking').replaceWith(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
Kanboard.Subtask = function(app) {
|
|
||||||
this.app = app;
|
|
||||||
};
|
|
||||||
|
|
||||||
Kanboard.Subtask.prototype.listen = function() {
|
|
||||||
var self = this;
|
|
||||||
this.dragAndDrop();
|
|
||||||
|
|
||||||
$(document).on("click", ".js-subtask-toggle-status", function(e) {
|
|
||||||
var el = $(this);
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
$.ajax({
|
|
||||||
cache: false,
|
|
||||||
url: el.attr("href"),
|
|
||||||
success: function(data) {
|
|
||||||
$(el).closest('.subtask-title').replaceWith(data);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
$(document).on("click", ".js-subtask-toggle-timer", function(e) {
|
|
||||||
var el = $(this);
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
$.ajax({
|
|
||||||
cache: false,
|
|
||||||
url: el.attr("href"),
|
|
||||||
success: function(data) {
|
|
||||||
$(el).closest('.subtask-time-tracking').replaceWith(data);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Kanboard.Subtask.prototype.dragAndDrop = function() {
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
$(".draggable-row-handle").mouseenter(function() {
|
|
||||||
$(this).parent().parent().addClass("draggable-item-hover");
|
|
||||||
}).mouseleave(function() {
|
|
||||||
$(this).parent().parent().removeClass("draggable-item-hover");
|
|
||||||
});
|
|
||||||
|
|
||||||
$(".subtasks-table tbody").sortable({
|
|
||||||
forcePlaceholderSize: true,
|
|
||||||
handle: "td:first i",
|
|
||||||
helper: function(e, ui) {
|
|
||||||
ui.children().each(function() {
|
|
||||||
$(this).width($(this).width());
|
|
||||||
});
|
|
||||||
|
|
||||||
return ui;
|
|
||||||
},
|
|
||||||
stop: function(event, ui) {
|
|
||||||
var subtask = ui.item;
|
|
||||||
subtask.removeClass("draggable-item-selected");
|
|
||||||
self.savePosition(subtask.data("subtask-id"), subtask.index() + 1);
|
|
||||||
},
|
|
||||||
start: function(event, ui) {
|
|
||||||
ui.item.addClass("draggable-item-selected");
|
|
||||||
}
|
|
||||||
}).disableSelection();
|
|
||||||
};
|
|
||||||
|
|
||||||
Kanboard.Subtask.prototype.savePosition = function(subtaskId, position) {
|
|
||||||
var url = $(".subtasks-table").data("save-position-url");
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
this.app.showLoadingIcon();
|
|
||||||
|
|
||||||
$.ajax({
|
|
||||||
cache: false,
|
|
||||||
url: url,
|
|
||||||
contentType: "application/json",
|
|
||||||
type: "POST",
|
|
||||||
processData: false,
|
|
||||||
data: JSON.stringify({
|
|
||||||
"subtask_id": subtaskId,
|
|
||||||
"position": position
|
|
||||||
}),
|
|
||||||
complete: function() {
|
|
||||||
self.app.hideLoadingIcon();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||