Improve subtask toggle status and timer
This commit is contained in:
parent
9c15658089
commit
4e07ad6555
|
|
@ -22,7 +22,7 @@ New features:
|
||||||
|
|
||||||
Improvements:
|
Improvements:
|
||||||
|
|
||||||
* Do not refresh the whole page when changing subtask status (work in progress)
|
* Do not refresh the whole page when changing subtask status
|
||||||
* Add dropdown menu with inline popup for all task actions
|
* Add dropdown menu with inline popup for all task actions
|
||||||
* Change sidebar style
|
* Change sidebar style
|
||||||
* Change task summary layout
|
* Change task summary layout
|
||||||
|
|
|
||||||
2
Makefile
2
Makefile
|
|
@ -4,7 +4,7 @@ CSS_APP = $(addprefix assets/css/src/, $(addsuffix .css, base links title table
|
||||||
CSS_PRINT = $(addprefix assets/css/src/, $(addsuffix .css, print links table board task comment subtask markdown))
|
CSS_PRINT = $(addprefix assets/css/src/, $(addsuffix .css, print links table board task comment subtask markdown))
|
||||||
CSS_VENDOR = $(addprefix assets/css/vendor/, $(addsuffix .css, jquery-ui.min jquery-ui-timepicker-addon.min chosen.min fullcalendar.min font-awesome.min c3.min))
|
CSS_VENDOR = $(addprefix assets/css/vendor/, $(addsuffix .css, jquery-ui.min jquery-ui-timepicker-addon.min chosen.min fullcalendar.min font-awesome.min c3.min))
|
||||||
|
|
||||||
JS_APP = $(addprefix assets/js/src/, $(addsuffix .js, Popover Dropdown Tooltip Markdown Search App Screenshot Calendar Board Swimlane Gantt Task Project TaskRepartitionChart UserRepartitionChart CumulativeFlowDiagram BurndownChart AvgTimeColumnChart TaskTimeColumnChart LeadCycleTimeChart CompareHoursColumnChart Router))
|
JS_APP = $(addprefix assets/js/src/, $(addsuffix .js, Popover Dropdown Tooltip Markdown Search App Screenshot Calendar Board Swimlane Gantt Task Project Subtask TaskRepartitionChart UserRepartitionChart CumulativeFlowDiagram BurndownChart AvgTimeColumnChart TaskTimeColumnChart LeadCycleTimeChart CompareHoursColumnChart Router))
|
||||||
JS_VENDOR = $(addprefix assets/js/vendor/, $(addsuffix .js, jquery-1.11.3.min jquery-ui.min jquery-ui-timepicker-addon.min jquery.ui.touch-punch.min chosen.jquery.min moment.min fullcalendar.min mousetrap.min mousetrap-global-bind.min jquery.textcomplete))
|
JS_VENDOR = $(addprefix assets/js/vendor/, $(addsuffix .js, jquery-1.11.3.min jquery-ui.min jquery-ui-timepicker-addon.min jquery.ui.touch-punch.min chosen.jquery.min moment.min fullcalendar.min mousetrap.min mousetrap-global-bind.min jquery.textcomplete))
|
||||||
JS_LANG = $(addprefix assets/js/vendor/lang/, $(addsuffix .js, cs da de es el fi fr hu id it ja nl nb pl pt pt-br ru sv sr th tr zh-cn))
|
JS_LANG = $(addprefix assets/js/vendor/lang/, $(addsuffix .js, cs da de es el fi fr hu id it ja nl nb pl pt pt-br ru sv sr th tr zh-cn))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,6 @@ class BoardPopover extends Base
|
||||||
|
|
||||||
$this->response->html($this->template->render('file/screenshot', array(
|
$this->response->html($this->template->render('file/screenshot', array(
|
||||||
'task' => $task,
|
'task' => $task,
|
||||||
'redirect' => 'board',
|
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@ class Subtask extends Base
|
||||||
'project' => $this->getProject(),
|
'project' => $this->getProject(),
|
||||||
'subtasks' => $this->subtask->getAll($task['id']),
|
'subtasks' => $this->subtask->getAll($task['id']),
|
||||||
'editable' => true,
|
'editable' => true,
|
||||||
'redirect' => 'subtask',
|
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,51 @@ class SubtaskStatus extends Base
|
||||||
$subtask = $this->getSubtask();
|
$subtask = $this->getSubtask();
|
||||||
|
|
||||||
$status = $this->subtask->toggleStatus($subtask['id']);
|
$status = $this->subtask->toggleStatus($subtask['id']);
|
||||||
$subtask['status'] = $status;
|
|
||||||
|
|
||||||
$this->response->html($this->helper->subtask->toggleStatus($subtask, $task['project_id']));
|
if ($this->request->getIntegerParam('refresh-table') === 0) {
|
||||||
|
$subtask['status'] = $status;
|
||||||
|
$html = $this->helper->subtask->toggleStatus($subtask, $task['project_id']);
|
||||||
|
} else {
|
||||||
|
$html = $this->renderTable($task);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->response->html($html);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start/stop timer for subtasks
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
public function timer()
|
||||||
|
{
|
||||||
|
$task = $this->getTask();
|
||||||
|
$subtask_id = $this->request->getIntegerParam('subtask_id');
|
||||||
|
$timer = $this->request->getStringParam('timer');
|
||||||
|
|
||||||
|
if ($timer === 'start') {
|
||||||
|
$this->subtaskTimeTracking->logStartTime($subtask_id, $this->userSession->getId());
|
||||||
|
} elseif ($timer === 'stop') {
|
||||||
|
$this->subtaskTimeTracking->logEndTime($subtask_id, $this->userSession->getId());
|
||||||
|
$this->subtaskTimeTracking->updateTaskTimeTracking($task['id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->response->html($this->renderTable($task));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render table
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
* @param array $task
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function renderTable(array $task)
|
||||||
|
{
|
||||||
|
return $this->template->render('subtask/table', array(
|
||||||
|
'task' => $task,
|
||||||
|
'subtasks' => $this->subtask->getAll($task['id']),
|
||||||
|
'editable' => true,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Kanboard\Controller;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Time Tracking controller
|
|
||||||
*
|
|
||||||
* @package controller
|
|
||||||
* @author Frederic Guillot
|
|
||||||
*/
|
|
||||||
class Timer extends Base
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Start/stop timer for subtasks
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
*/
|
|
||||||
public function subtask()
|
|
||||||
{
|
|
||||||
$project_id = $this->request->getIntegerParam('project_id');
|
|
||||||
$task_id = $this->request->getIntegerParam('task_id');
|
|
||||||
$subtask_id = $this->request->getIntegerParam('subtask_id');
|
|
||||||
$timer = $this->request->getStringParam('timer');
|
|
||||||
|
|
||||||
if ($timer === 'start') {
|
|
||||||
$this->subtaskTimeTracking->logStartTime($subtask_id, $this->userSession->getId());
|
|
||||||
} elseif ($timer === 'stop') {
|
|
||||||
$this->subtaskTimeTracking->logEndTime($subtask_id, $this->userSession->getId());
|
|
||||||
$this->subtaskTimeTracking->updateTaskTimeTracking($task_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->response->redirect($this->helper->url->to('task', 'show', array('project_id' => $project_id, 'task_id' => $task_id)).'#subtasks');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -29,21 +29,23 @@ class Subtask extends \Kanboard\Core\Base
|
||||||
* @access public
|
* @access public
|
||||||
* @param array $subtask
|
* @param array $subtask
|
||||||
* @param integer $project_id
|
* @param integer $project_id
|
||||||
|
* @param boolean $refresh_table
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function toggleStatus(array $subtask, $project_id)
|
public function toggleStatus(array $subtask, $project_id, $refresh_table = false)
|
||||||
{
|
{
|
||||||
if (! $this->helper->user->hasProjectAccess('subtask', 'edit', $project_id)) {
|
if (! $this->helper->user->hasProjectAccess('subtask', 'edit', $project_id)) {
|
||||||
return $this->getTitle($subtask);
|
return $this->getTitle($subtask);
|
||||||
}
|
}
|
||||||
|
|
||||||
$params = array('task_id' => $subtask['task_id'], 'subtask_id' => $subtask['id']);
|
$params = array('task_id' => $subtask['task_id'], 'subtask_id' => $subtask['id'], 'refresh-table' => (int) $refresh_table);
|
||||||
|
|
||||||
if ($subtask['status'] == 0 && isset($this->sessionStorage->hasSubtaskInProgress) && $this->sessionStorage->hasSubtaskInProgress) {
|
if ($subtask['status'] == 0 && isset($this->sessionStorage->hasSubtaskInProgress) && $this->sessionStorage->hasSubtaskInProgress) {
|
||||||
return $this->helper->url->link($this->getTitle($subtask), 'SubtaskRestriction', 'popover', $params, false, 'popover');
|
return $this->helper->url->link($this->getTitle($subtask), 'SubtaskRestriction', 'popover', $params, false, 'popover');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->helper->url->link($this->getTitle($subtask), 'SubtaskStatus', 'change', $params, false, 'ajax-replace');
|
$class = 'subtask-toggle-status '.($refresh_table ? 'subtask-refresh-table' : '');
|
||||||
|
return $this->helper->url->link($this->getTitle($subtask), 'SubtaskStatus', 'change', $params, false, $class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function selectTitle(array $values, array $errors = array(), array $attributes = array())
|
public function selectTitle(array $values, array $errors = array(), array $attributes = array())
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,6 @@ class AuthenticationProvider implements ServiceProviderInterface
|
||||||
$acl->add('TaskExternalLink', array('show'), Role::PROJECT_VIEWER);
|
$acl->add('TaskExternalLink', array('show'), Role::PROJECT_VIEWER);
|
||||||
$acl->add('Taskmodification', '*', Role::PROJECT_MEMBER);
|
$acl->add('Taskmodification', '*', Role::PROJECT_MEMBER);
|
||||||
$acl->add('Taskstatus', '*', Role::PROJECT_MEMBER);
|
$acl->add('Taskstatus', '*', Role::PROJECT_MEMBER);
|
||||||
$acl->add('Timer', '*', Role::PROJECT_MEMBER);
|
|
||||||
$acl->add('UserHelper', array('mention'), Role::PROJECT_MEMBER);
|
$acl->add('UserHelper', array('mention'), Role::PROJECT_MEMBER);
|
||||||
|
|
||||||
return $acl;
|
return $acl;
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<?php if ($editable): ?>
|
<?php if ($editable): ?>
|
||||||
<?= $this->subtask->toggleStatus($subtask, $task['project_id']) ?>
|
<?= $this->subtask->toggleStatus($subtask, $task['project_id'], true) ?>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<?= $this->subtask->getTitle($subtask) ?>
|
<?= $this->subtask->getTitle($subtask) ?>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
|
|
@ -41,11 +41,11 @@
|
||||||
<li>
|
<li>
|
||||||
<?php if ($subtask['is_timer_started']): ?>
|
<?php if ($subtask['is_timer_started']): ?>
|
||||||
<i class="fa fa-pause"></i>
|
<i class="fa fa-pause"></i>
|
||||||
<?= $this->url->link(t('Stop timer'), 'timer', 'subtask', array('timer' => 'stop', 'project_id' => $task['project_id'], 'task_id' => $subtask['task_id'], 'subtask_id' => $subtask['id'])) ?>
|
<?= $this->url->link(t('Stop timer'), 'SubtaskStatus', 'timer', array('timer' => 'stop', 'project_id' => $task['project_id'], 'task_id' => $subtask['task_id'], 'subtask_id' => $subtask['id']), false, 'subtask-toggle-timer') ?>
|
||||||
(<?= $this->dt->age($subtask['timer_start_date']) ?>)
|
(<?= $this->dt->age($subtask['timer_start_date']) ?>)
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<i class="fa fa-play-circle-o"></i>
|
<i class="fa fa-play-circle-o"></i>
|
||||||
<?= $this->url->link(t('Start timer'), 'timer', 'subtask', array('timer' => 'start', 'project_id' => $task['project_id'], 'task_id' => $subtask['task_id'], 'subtask_id' => $subtask['id'])) ?>
|
<?= $this->url->link(t('Start timer'), 'SubtaskStatus', 'timer', array('timer' => 'start', 'project_id' => $task['project_id'], 'task_id' => $subtask['task_id'], 'subtask_id' => $subtask['id']), false, 'subtask-toggle-timer') ?>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
</li>
|
</li>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -8,6 +8,7 @@ function App() {
|
||||||
this.popover = new Popover(this);
|
this.popover = new Popover(this);
|
||||||
this.task = new Task();
|
this.task = new Task();
|
||||||
this.project = new Project();
|
this.project = new Project();
|
||||||
|
this.subtask = new Subtask();
|
||||||
this.keyboardShortcuts();
|
this.keyboardShortcuts();
|
||||||
this.chosen();
|
this.chosen();
|
||||||
this.poll();
|
this.poll();
|
||||||
|
|
@ -37,23 +38,11 @@ App.prototype.listen = function() {
|
||||||
this.search.listen();
|
this.search.listen();
|
||||||
this.task.listen();
|
this.task.listen();
|
||||||
this.swimlane.listen();
|
this.swimlane.listen();
|
||||||
|
this.subtask.listen();
|
||||||
this.search.focus();
|
this.search.focus();
|
||||||
this.autoComplete();
|
this.autoComplete();
|
||||||
this.datePicker();
|
this.datePicker();
|
||||||
this.focus();
|
this.focus();
|
||||||
|
|
||||||
$(document).on("click", ".ajax-replace", function(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
var el = $(this);
|
|
||||||
|
|
||||||
$.ajax({
|
|
||||||
cache: false,
|
|
||||||
url: el.attr("href"),
|
|
||||||
success: function(data) {
|
|
||||||
el.replaceWith(data);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
App.prototype.refresh = function() {
|
App.prototype.refresh = function() {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
function Subtask() {
|
||||||
|
}
|
||||||
|
|
||||||
|
Subtask.prototype.listen = function() {
|
||||||
|
$(document).on("click", ".subtask-toggle-status", function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var el = $(this);
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
cache: false,
|
||||||
|
url: el.attr("href"),
|
||||||
|
success: function(data) {
|
||||||
|
if (el.hasClass("subtask-refresh-table")) {
|
||||||
|
$(".subtasks-table").replaceWith(data);
|
||||||
|
} else {
|
||||||
|
el.replaceWith(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$(document).on("click", ".subtask-toggle-timer", function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var el = $(this);
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
cache: false,
|
||||||
|
url: el.attr("href"),
|
||||||
|
success: function(data) {
|
||||||
|
$(".subtasks-table").replaceWith(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue