Add timer for subtasks and remove settings for subtask time tracking
This commit is contained in:
parent
58c96b8c4e
commit
6efac784fc
|
|
@ -42,7 +42,7 @@ class Config extends Base
|
|||
|
||||
switch ($redirect) {
|
||||
case 'project':
|
||||
$values += array('subtask_restriction' => 0, 'subtask_time_tracking' => 0);
|
||||
$values += array('subtask_restriction' => 0);
|
||||
break;
|
||||
case 'integrations':
|
||||
$values += array('integration_slack_webhook' => 0, 'integration_hipchat' => 0, 'integration_gravatar' => 0, 'integration_jabber' => 0);
|
||||
|
|
|
|||
|
|
@ -256,7 +256,7 @@ class Subtask extends Base
|
|||
case 'dashboard':
|
||||
$this->response->redirect($this->helper->url->to('app', 'index'));
|
||||
default:
|
||||
$this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])));
|
||||
$this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])).'#subtasks');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
namespace 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());
|
||||
}
|
||||
else if ($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');
|
||||
}
|
||||
}
|
||||
|
|
@ -10,6 +10,39 @@ namespace Helper;
|
|||
*/
|
||||
class Datetime extends \Core\Base
|
||||
{
|
||||
/**
|
||||
* Get the age of an item in quasi human readable format.
|
||||
* It's in this format: <1h , NNh, NNd
|
||||
*
|
||||
* @access public
|
||||
* @param integer $timestamp Unix timestamp of the artifact for which age will be calculated
|
||||
* @param integer $now Compare with this timestamp (Default value is the current unix timestamp)
|
||||
* @return string
|
||||
*/
|
||||
public function age($timestamp, $now = null)
|
||||
{
|
||||
if ($now === null) {
|
||||
$now = time();
|
||||
}
|
||||
|
||||
$diff = $now - $timestamp;
|
||||
|
||||
if ($diff < 900) {
|
||||
return t('<15m');
|
||||
}
|
||||
if ($diff < 1200) {
|
||||
return t('<30m');
|
||||
}
|
||||
else if ($diff < 3600) {
|
||||
return t('<1h');
|
||||
}
|
||||
else if ($diff < 86400) {
|
||||
return '~'.t('%dh', $diff / 3600);
|
||||
}
|
||||
|
||||
return t('%dd', ($now - $timestamp) / 86400);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all hours for day
|
||||
*
|
||||
|
|
|
|||
|
|
@ -10,33 +10,6 @@ namespace Helper;
|
|||
*/
|
||||
class Task extends \Core\Base
|
||||
{
|
||||
/**
|
||||
* Get the age of an item in quasi human readable format.
|
||||
* It's in this format: <1h , NNh, NNd
|
||||
*
|
||||
* @access public
|
||||
* @param integer $timestamp Unix timestamp of the artifact for which age will be calculated
|
||||
* @param integer $now Compare with this timestamp (Default value is the current unix timestamp)
|
||||
* @return string
|
||||
*/
|
||||
public function age($timestamp, $now = null)
|
||||
{
|
||||
if ($now === null) {
|
||||
$now = time();
|
||||
}
|
||||
|
||||
$diff = $now - $timestamp;
|
||||
|
||||
if ($diff < 3600) {
|
||||
return t('<1h');
|
||||
}
|
||||
else if ($diff < 86400) {
|
||||
return t('%dh', $diff / 3600);
|
||||
}
|
||||
|
||||
return t('%dd', ($now - $timestamp) / 86400);
|
||||
}
|
||||
|
||||
public function getColors()
|
||||
{
|
||||
return $this->color->getList();
|
||||
|
|
|
|||
|
|
@ -614,7 +614,6 @@ return array(
|
|||
// 'User dashboard' => '',
|
||||
// 'Allow only one subtask in progress at the same time for a user' => '',
|
||||
// 'Edit column "%s"' => '',
|
||||
// 'Enable time tracking for subtasks' => '',
|
||||
// 'Select the new status of the subtask: "%s"' => '',
|
||||
// 'Subtask timesheet' => '',
|
||||
// 'There is nothing to show.' => '',
|
||||
|
|
@ -946,4 +945,8 @@ return array(
|
|||
// '%%Y-%%m-%%d' => '',
|
||||
// 'Total for all columns' => '',
|
||||
// 'You need at least 2 days of data to show the chart.' => '',
|
||||
// '<15m' => '',
|
||||
// '<30m' => '',
|
||||
// 'Stop timer' => '',
|
||||
// 'Start timer' => '',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -614,7 +614,6 @@ return array(
|
|||
'User dashboard' => 'Benutzer Dashboard',
|
||||
'Allow only one subtask in progress at the same time for a user' => 'Erlaube nur eine Teilaufgabe pro Benutzer zu bearbeiten',
|
||||
'Edit column "%s"' => 'Spalte "%s" bearbeiten',
|
||||
'Enable time tracking for subtasks' => 'Aktiviere Zeiterfassung für Teilaufgaben',
|
||||
'Select the new status of the subtask: "%s"' => 'Wähle einen neuen Status für Teilaufgabe: "%s"',
|
||||
'Subtask timesheet' => 'Teilaufgaben Zeiterfassung',
|
||||
'There is nothing to show.' => 'Es ist nichts zum Anzeigen vorhanden.',
|
||||
|
|
@ -946,4 +945,8 @@ return array(
|
|||
// '%%Y-%%m-%%d' => '',
|
||||
// 'Total for all columns' => '',
|
||||
// 'You need at least 2 days of data to show the chart.' => '',
|
||||
// '<15m' => '',
|
||||
// '<30m' => '',
|
||||
// 'Stop timer' => '',
|
||||
// 'Start timer' => '',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -614,7 +614,6 @@ return array(
|
|||
'User dashboard' => 'Tablero de usuario',
|
||||
'Allow only one subtask in progress at the same time for a user' => 'Permitir sólo una subtarea en progreso a la vez para cada usuario',
|
||||
'Edit column "%s"' => 'Editar columna %s',
|
||||
'Enable time tracking for subtasks' => 'Activar seguimiento temporal para subtareas',
|
||||
'Select the new status of the subtask: "%s"' => 'Seleccionar el nuevo estado de la subtarea: "%s"',
|
||||
'Subtask timesheet' => 'Hoja temporal de subtarea',
|
||||
'There is nothing to show.' => 'Nada que mostrar',
|
||||
|
|
@ -946,4 +945,8 @@ return array(
|
|||
// '%%Y-%%m-%%d' => '',
|
||||
// 'Total for all columns' => '',
|
||||
// 'You need at least 2 days of data to show the chart.' => '',
|
||||
// '<15m' => '',
|
||||
// '<30m' => '',
|
||||
// 'Stop timer' => '',
|
||||
// 'Start timer' => '',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -614,7 +614,6 @@ return array(
|
|||
// 'User dashboard' => '',
|
||||
// 'Allow only one subtask in progress at the same time for a user' => '',
|
||||
// 'Edit column "%s"' => '',
|
||||
// 'Enable time tracking for subtasks' => '',
|
||||
// 'Select the new status of the subtask: "%s"' => '',
|
||||
// 'Subtask timesheet' => '',
|
||||
// 'There is nothing to show.' => '',
|
||||
|
|
@ -946,4 +945,8 @@ return array(
|
|||
// '%%Y-%%m-%%d' => '',
|
||||
// 'Total for all columns' => '',
|
||||
// 'You need at least 2 days of data to show the chart.' => '',
|
||||
// '<15m' => '',
|
||||
// '<30m' => '',
|
||||
// 'Stop timer' => '',
|
||||
// 'Start timer' => '',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -616,7 +616,6 @@ return array(
|
|||
'User dashboard' => 'Tableau de bord de l\'utilisateur',
|
||||
'Allow only one subtask in progress at the same time for a user' => 'Autoriser une seule sous-tâche en progrès en même temps pour un utilisateur',
|
||||
'Edit column "%s"' => 'Modifier la colonne « %s »',
|
||||
'Enable time tracking for subtasks' => 'Activer la feuille de temps pour les sous-tâches',
|
||||
'Select the new status of the subtask: "%s"' => 'Selectionnez le nouveau statut de la sous-tâche : « %s »',
|
||||
'Subtask timesheet' => 'Feuille de temps des sous-tâches',
|
||||
'There is nothing to show.' => 'Il n\'y a rien à montrer.',
|
||||
|
|
@ -948,4 +947,8 @@ return array(
|
|||
'%%Y-%%m-%%d' => '%%d/%%m/%%Y',
|
||||
'Total for all columns' => 'Total pour toutes les colonnes',
|
||||
'You need at least 2 days of data to show the chart.' => 'Vous avez besoin d\'au minimum 2 jours de données pour afficher le graphique.',
|
||||
'<15m' => '<15m',
|
||||
'<30m' => '<30m',
|
||||
'Stop timer' => 'Stopper le chrono',
|
||||
'Start timer' => 'Démarrer le chrono',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -614,7 +614,6 @@ return array(
|
|||
'User dashboard' => 'Felhasználói vezérlőpult',
|
||||
'Allow only one subtask in progress at the same time for a user' => 'Egyszerre csak egy folyamatban levő részfeladat engedélyezése a felhasználóknak',
|
||||
'Edit column "%s"' => 'Oszlop szerkesztés: %s',
|
||||
'Enable time tracking for subtasks' => 'Idő követés engedélyezése a részfeladatokhoz',
|
||||
'Select the new status of the subtask: "%s"' => 'Részfeladat állapot változtatás: %s',
|
||||
'Subtask timesheet' => 'Részfeladat idővonal',
|
||||
'There is nothing to show.' => 'Nincs megjelenítendő adat.',
|
||||
|
|
@ -946,4 +945,8 @@ return array(
|
|||
// '%%Y-%%m-%%d' => '',
|
||||
// 'Total for all columns' => '',
|
||||
// 'You need at least 2 days of data to show the chart.' => '',
|
||||
// '<15m' => '',
|
||||
// '<30m' => '',
|
||||
// 'Stop timer' => '',
|
||||
// 'Start timer' => '',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -614,7 +614,6 @@ return array(
|
|||
'User dashboard' => 'Bacheca utente',
|
||||
'Allow only one subtask in progress at the same time for a user' => 'Permetti un solo sotto-compito in progresso per utente nello stesso tempo',
|
||||
'Edit column "%s"' => 'Modifica la colonna "%s"',
|
||||
'Enable time tracking for subtasks' => 'Abilita la gestione del tempo per i sotto-compiti',
|
||||
'Select the new status of the subtask: "%s"' => 'Selziona il nuovo status per il sotto-compito: "%s"',
|
||||
'Subtask timesheet' => 'Timesheet del sotto-compito',
|
||||
'There is nothing to show.' => 'Nulla da mostrare.',
|
||||
|
|
@ -946,4 +945,8 @@ return array(
|
|||
// '%%Y-%%m-%%d' => '',
|
||||
// 'Total for all columns' => '',
|
||||
// 'You need at least 2 days of data to show the chart.' => '',
|
||||
// '<15m' => '',
|
||||
// '<30m' => '',
|
||||
// 'Stop timer' => '',
|
||||
// 'Start timer' => '',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -614,7 +614,6 @@ return array(
|
|||
'User dashboard' => 'ユーザダッシュボード',
|
||||
'Allow only one subtask in progress at the same time for a user' => '一人のユーザにつき一つのタスクのみ進行中にできます',
|
||||
'Edit column "%s"' => 'カラム「%s」の編集',
|
||||
'Enable time tracking for subtasks' => 'サブタスクのタイムトラッキングを有効',
|
||||
'Select the new status of the subtask: "%s"' => 'サブタスク「%s」のステータスを選択',
|
||||
'Subtask timesheet' => 'サブタスクタイムシート',
|
||||
'There is nothing to show.' => '何も表示するものがありません。',
|
||||
|
|
@ -946,4 +945,8 @@ return array(
|
|||
// '%%Y-%%m-%%d' => '',
|
||||
// 'Total for all columns' => '',
|
||||
// 'You need at least 2 days of data to show the chart.' => '',
|
||||
// '<15m' => '',
|
||||
// '<30m' => '',
|
||||
// 'Stop timer' => '',
|
||||
// 'Start timer' => '',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -614,7 +614,6 @@ return array(
|
|||
'User dashboard' => 'Gebruiker dashboard',
|
||||
'Allow only one subtask in progress at the same time for a user' => 'Sta maximaal één subtaak in behandeling toe per gebruiker',
|
||||
'Edit column "%s"' => 'Kolom « %s » aanpassen',
|
||||
'Enable time tracking for subtasks' => 'Activeer tijdschrijven voor subtaken',
|
||||
'Select the new status of the subtask: "%s"' => 'Selecteer nieuwe status voor subtaak : « %s »',
|
||||
'Subtask timesheet' => 'Subtaak timesheet',
|
||||
'There is nothing to show.' => 'Er is niets om te laten zijn.',
|
||||
|
|
@ -946,4 +945,8 @@ return array(
|
|||
// '%%Y-%%m-%%d' => '',
|
||||
// 'Total for all columns' => '',
|
||||
// 'You need at least 2 days of data to show the chart.' => '',
|
||||
// '<15m' => '',
|
||||
// '<30m' => '',
|
||||
// 'Stop timer' => '',
|
||||
// 'Start timer' => '',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -614,7 +614,6 @@ return array(
|
|||
'User dashboard' => 'Panel użytkownika',
|
||||
'Allow only one subtask in progress at the same time for a user' => 'Zezwalaj na tylko jedno pod-zadanie o statusie "w trakcie" jednocześnie',
|
||||
'Edit column "%s"' => 'Zmień kolumnę "%s"',
|
||||
'Enable time tracking for subtasks' => 'Włącz śledzenie czasu dla pod-zadań',
|
||||
'Select the new status of the subtask: "%s"' => 'Wybierz nowy status dla pod-zadania: "%s"',
|
||||
'Subtask timesheet' => 'Oś czasu pod-zadania',
|
||||
'There is nothing to show.' => 'Nie nic do wyświetlenia',
|
||||
|
|
@ -946,4 +945,8 @@ return array(
|
|||
// '%%Y-%%m-%%d' => '',
|
||||
// 'Total for all columns' => '',
|
||||
// 'You need at least 2 days of data to show the chart.' => '',
|
||||
// '<15m' => '',
|
||||
// '<30m' => '',
|
||||
// 'Stop timer' => '',
|
||||
// 'Start timer' => '',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -614,7 +614,6 @@ return array(
|
|||
'User dashboard' => 'Painel de Controle do usuário',
|
||||
'Allow only one subtask in progress at the same time for a user' => 'Permitir apenas uma subtarefa em andamento ao mesmo tempo para um usuário',
|
||||
'Edit column "%s"' => 'Editar a coluna "%s"',
|
||||
'Enable time tracking for subtasks' => 'Ativar a gestão de tempo par a subtarefa',
|
||||
'Select the new status of the subtask: "%s"' => 'Selecionar um novo status para a subtarefa: "%s"',
|
||||
'Subtask timesheet' => 'Gestão de tempo das subtarefas',
|
||||
'There is nothing to show.' => 'Não há nada para mostrar',
|
||||
|
|
@ -946,4 +945,8 @@ return array(
|
|||
// '%%Y-%%m-%%d' => '',
|
||||
// 'Total for all columns' => '',
|
||||
// 'You need at least 2 days of data to show the chart.' => '',
|
||||
// '<15m' => '',
|
||||
// '<30m' => '',
|
||||
// 'Stop timer' => '',
|
||||
// 'Start timer' => '',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -614,7 +614,6 @@ return array(
|
|||
'User dashboard' => 'Пользователь панели мониторинга',
|
||||
'Allow only one subtask in progress at the same time for a user' => 'Разрешена только одна подзадача в разработке одновременно для одного пользователя',
|
||||
'Edit column "%s"' => 'Редактировать колонку "%s"',
|
||||
'Enable time tracking for subtasks' => 'Включить учет времени для подзадач',
|
||||
'Select the new status of the subtask: "%s"' => 'Выбрать новый статус для подзадачи: "%s"',
|
||||
'Subtask timesheet' => 'Табель времени подзадач',
|
||||
'There is nothing to show.' => 'Здесь ничего нет.',
|
||||
|
|
@ -946,4 +945,8 @@ return array(
|
|||
// '%%Y-%%m-%%d' => '',
|
||||
// 'Total for all columns' => '',
|
||||
// 'You need at least 2 days of data to show the chart.' => '',
|
||||
// '<15m' => '',
|
||||
// '<30m' => '',
|
||||
// 'Stop timer' => '',
|
||||
// 'Start timer' => '',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -614,7 +614,6 @@ return array(
|
|||
'User dashboard' => 'Korisnički panel',
|
||||
// 'Allow only one subtask in progress at the same time for a user' => '',
|
||||
// 'Edit column "%s"' => '',
|
||||
// 'Enable time tracking for subtasks' => '',
|
||||
// 'Select the new status of the subtask: "%s"' => '',
|
||||
// 'Subtask timesheet' => '',
|
||||
'There is nothing to show.' => 'Nema podataka',
|
||||
|
|
@ -946,4 +945,8 @@ return array(
|
|||
// '%%Y-%%m-%%d' => '',
|
||||
// 'Total for all columns' => '',
|
||||
// 'You need at least 2 days of data to show the chart.' => '',
|
||||
// '<15m' => '',
|
||||
// '<30m' => '',
|
||||
// 'Stop timer' => '',
|
||||
// 'Start timer' => '',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -614,7 +614,6 @@ return array(
|
|||
'User dashboard' => 'Användardashboard',
|
||||
'Allow only one subtask in progress at the same time for a user' => 'Tillåt endast en deluppgift igång samtidigt för en användare',
|
||||
'Edit column "%s"' => 'Ändra kolumn "%s"',
|
||||
'Enable time tracking for subtasks' => 'Aktivera tidsbevakning för deluppgifter',
|
||||
'Select the new status of the subtask: "%s"' => 'Välj ny status för deluppgiften: "%s"',
|
||||
'Subtask timesheet' => 'Tidrapport för deluppgiften',
|
||||
'There is nothing to show.' => 'Det finns inget att visa',
|
||||
|
|
@ -946,4 +945,8 @@ return array(
|
|||
// '%%Y-%%m-%%d' => '',
|
||||
// 'Total for all columns' => '',
|
||||
// 'You need at least 2 days of data to show the chart.' => '',
|
||||
// '<15m' => '',
|
||||
// '<30m' => '',
|
||||
// 'Stop timer' => '',
|
||||
// 'Start timer' => '',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -614,7 +614,6 @@ return array(
|
|||
'User dashboard' => 'ผู้ใช้แดชบอร์ด',
|
||||
'Allow only one subtask in progress at the same time for a user' => 'อนุญาตให้ทำงานย่อยได้เพียงงานเดียวต่อหนึ่งคนในเวลาเดียวกัน',
|
||||
'Edit column "%s"' => 'แก้ไขคอลัมน์ "%s"',
|
||||
'Enable time tracking for subtasks' => 'สามารถติดตามเวลาของงานย่อย',
|
||||
'Select the new status of the subtask: "%s"' => 'เลือกสถานะใหม่ของงานย่อย: "%s"',
|
||||
'Subtask timesheet' => 'เวลางานย่อย',
|
||||
'There is nothing to show.' => 'ไม่มีที่ต้องแสดง',
|
||||
|
|
@ -946,4 +945,8 @@ return array(
|
|||
// '%%Y-%%m-%%d' => '',
|
||||
// 'Total for all columns' => '',
|
||||
// 'You need at least 2 days of data to show the chart.' => '',
|
||||
// '<15m' => '',
|
||||
// '<30m' => '',
|
||||
// 'Stop timer' => '',
|
||||
// 'Start timer' => '',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -614,7 +614,6 @@ return array(
|
|||
'User dashboard' => 'Kullanıcı Anasayfası',
|
||||
'Allow only one subtask in progress at the same time for a user' => 'Bir kullanıcı için aynı anda yalnızca bir alt göreve izin ver',
|
||||
'Edit column "%s"' => '"%s" sütununu değiştir',
|
||||
'Enable time tracking for subtasks' => 'Alt görevler için zaman takibini etkinleştir',
|
||||
'Select the new status of the subtask: "%s"' => '"%s" alt görevi için yeni durum seçin.',
|
||||
'Subtask timesheet' => 'Alt görev için zaman takip tablosu',
|
||||
'There is nothing to show.' => 'Gösterilecek hiçbir şey yok.',
|
||||
|
|
@ -946,4 +945,8 @@ return array(
|
|||
// '%%Y-%%m-%%d' => '',
|
||||
// 'Total for all columns' => '',
|
||||
// 'You need at least 2 days of data to show the chart.' => '',
|
||||
// '<15m' => '',
|
||||
// '<30m' => '',
|
||||
// 'Stop timer' => '',
|
||||
// 'Start timer' => '',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -614,7 +614,6 @@ return array(
|
|||
'User dashboard' => '用户仪表板',
|
||||
'Allow only one subtask in progress at the same time for a user' => '每用户同时仅有一个活动子任务',
|
||||
'Edit column "%s"' => '编辑栏目"%s"',
|
||||
'Enable time tracking for subtasks' => '启用子任务的时间记录',
|
||||
'Select the new status of the subtask: "%s"' => '选择子任务的新状态:"%s"',
|
||||
'Subtask timesheet' => '子任务时间',
|
||||
'There is nothing to show.' => '无内容。',
|
||||
|
|
@ -946,4 +945,8 @@ return array(
|
|||
// '%%Y-%%m-%%d' => '',
|
||||
// 'Total for all columns' => '',
|
||||
// 'You need at least 2 days of data to show the chart.' => '',
|
||||
// '<15m' => '',
|
||||
// '<30m' => '',
|
||||
// 'Stop timer' => '',
|
||||
// 'Start timer' => '',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ class Acl extends Base
|
|||
'subtask' => '*',
|
||||
'task' => '*',
|
||||
'tasklink' => '*',
|
||||
'timer' => '*',
|
||||
'calendar' => array('show', 'project'),
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ class Budget extends Base
|
|||
->join(Task::TABLE, 'id', 'task_id', Subtask::TABLE)
|
||||
->join(User::TABLE, 'id', 'user_id')
|
||||
->eq(Task::TABLE.'.project_id', $project_id)
|
||||
->filter(array($this, 'applyUserRate'));
|
||||
->callback(array($this, 'applyUserRate'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -276,7 +276,7 @@ class Project extends Base
|
|||
return $this->db
|
||||
->table(Project::TABLE)
|
||||
->in('id', $project_ids)
|
||||
->filter(array($this, 'applyColumnStats'));
|
||||
->callback(array($this, 'applyColumnStats'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -78,6 +78,8 @@ class Subtask extends Base
|
|||
|
||||
foreach ($subtasks as &$subtask) {
|
||||
$subtask['status_name'] = $status[$subtask['status']];
|
||||
$subtask['timer_start_date'] = isset($subtask['timer_start_date']) ? $subtask['timer_start_date'] : 0;
|
||||
$subtask['is_timer_started'] = ! empty($subtask['timer_start_date']);
|
||||
}
|
||||
|
||||
return $subtasks;
|
||||
|
|
@ -101,12 +103,13 @@ class Subtask extends Base
|
|||
Task::TABLE.'.title AS task_name',
|
||||
Project::TABLE.'.name AS project_name'
|
||||
)
|
||||
->subquery($this->subtaskTimeTracking->getTimerQuery($user_id), 'timer_start_date')
|
||||
->eq('user_id', $user_id)
|
||||
->eq(Project::TABLE.'.is_active', Project::ACTIVE)
|
||||
->in(Subtask::TABLE.'.status', $status)
|
||||
->join(Task::TABLE, 'id', 'task_id')
|
||||
->join(Project::TABLE, 'id', 'project_id', Task::TABLE)
|
||||
->filter(array($this, 'addStatusName'));
|
||||
->callback(array($this, 'addStatusName'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -121,10 +124,15 @@ class Subtask extends Base
|
|||
return $this->db
|
||||
->table(self::TABLE)
|
||||
->eq('task_id', $task_id)
|
||||
->columns(self::TABLE.'.*', User::TABLE.'.username', User::TABLE.'.name')
|
||||
->columns(
|
||||
self::TABLE.'.*',
|
||||
User::TABLE.'.username',
|
||||
User::TABLE.'.name'
|
||||
)
|
||||
->subquery($this->subtaskTimeTracking->getTimerQuery($this->userSession->getId()), 'timer_start_date')
|
||||
->join(User::TABLE, 'id', 'user_id')
|
||||
->asc(self::TABLE.'.position')
|
||||
->filter(array($this, 'addStatusName'))
|
||||
->callback(array($this, 'addStatusName'))
|
||||
->findAll();
|
||||
}
|
||||
|
||||
|
|
@ -144,8 +152,9 @@ class Subtask extends Base
|
|||
->table(self::TABLE)
|
||||
->eq(self::TABLE.'.id', $subtask_id)
|
||||
->columns(self::TABLE.'.*', User::TABLE.'.username', User::TABLE.'.name')
|
||||
->subquery($this->subtaskTimeTracking->getTimerQuery($this->userSession->getId()), 'timer_start_date')
|
||||
->join(User::TABLE, 'id', 'user_id')
|
||||
->filter(array($this, 'addStatusName'))
|
||||
->callback(array($this, 'addStatusName'))
|
||||
->findOne();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,27 @@ class SubtaskTimeTracking extends Base
|
|||
*/
|
||||
const TABLE = 'subtask_time_tracking';
|
||||
|
||||
/**
|
||||
* Get query to check if a timer is started for the given user and subtask
|
||||
*
|
||||
* @access public
|
||||
* @param integer $user_id User id
|
||||
* @return string
|
||||
*/
|
||||
public function getTimerQuery($user_id)
|
||||
{
|
||||
return sprintf(
|
||||
"SELECT %s FROM %s WHERE %s='%d' AND %s='0' AND %s=%s",
|
||||
$this->db->escapeIdentifier('start'),
|
||||
$this->db->escapeIdentifier(self::TABLE),
|
||||
$this->db->escapeIdentifier('user_id'),
|
||||
$user_id,
|
||||
$this->db->escapeIdentifier('end'),
|
||||
$this->db->escapeIdentifier('subtask_id'),
|
||||
Subtask::TABLE.'.id'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get query for user timesheet (pagination)
|
||||
*
|
||||
|
|
@ -217,7 +238,7 @@ class SubtaskTimeTracking extends Base
|
|||
{
|
||||
return $this->db
|
||||
->table(self::TABLE)
|
||||
->insert(array('subtask_id' => $subtask_id, 'user_id' => $user_id, 'start' => time()));
|
||||
->insert(array('subtask_id' => $subtask_id, 'user_id' => $user_id, 'start' => time(), 'end' => 0));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -301,7 +301,7 @@ class TaskFilter extends Base
|
|||
*/
|
||||
public function toAutoCompletion()
|
||||
{
|
||||
return $this->query->columns('id', 'title')->filter(function(array $results) {
|
||||
return $this->query->columns('id', 'title')->callback(function(array $results) {
|
||||
|
||||
foreach ($results as &$result) {
|
||||
$result['value'] = $result['title'];
|
||||
|
|
|
|||
|
|
@ -316,7 +316,7 @@ class TaskFinder extends Base
|
|||
->table(Task::TABLE)
|
||||
->eq('project_id', $project_id)
|
||||
->eq('column_id', $column_id)
|
||||
->in('is_active', 1)
|
||||
->eq('is_active', 1)
|
||||
->count();
|
||||
}
|
||||
|
||||
|
|
@ -336,7 +336,7 @@ class TaskFinder extends Base
|
|||
->eq('project_id', $project_id)
|
||||
->eq('column_id', $column_id)
|
||||
->eq('swimlane_id', $swimlane_id)
|
||||
->in('is_active', 1)
|
||||
->eq('is_active', 1)
|
||||
->count();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,12 @@ use PDO;
|
|||
use Core\Security;
|
||||
use Model\Link;
|
||||
|
||||
const VERSION = 75;
|
||||
const VERSION = 76;
|
||||
|
||||
function version_76($pdo)
|
||||
{
|
||||
$pdo->exec("DELETE FROM `settings` WHERE `option`='subtask_time_tracking'");
|
||||
}
|
||||
|
||||
function version_75($pdo)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -6,7 +6,12 @@ use PDO;
|
|||
use Core\Security;
|
||||
use Model\Link;
|
||||
|
||||
const VERSION = 55;
|
||||
const VERSION = 56;
|
||||
|
||||
function version_56($pdo)
|
||||
{
|
||||
$pdo->exec('DELETE FROM "settings" WHERE "option"=\'subtask_time_tracking\'');
|
||||
}
|
||||
|
||||
function version_55($pdo)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -6,7 +6,12 @@ use Core\Security;
|
|||
use PDO;
|
||||
use Model\Link;
|
||||
|
||||
const VERSION = 72;
|
||||
const VERSION = 73;
|
||||
|
||||
function version_73($pdo)
|
||||
{
|
||||
$pdo->exec("DELETE FROM settings WHERE option='subtask_time_tracking'");
|
||||
}
|
||||
|
||||
function version_72($pdo)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use Subscriber\ProjectActivitySubscriber;
|
|||
use Subscriber\ProjectDailySummarySubscriber;
|
||||
use Subscriber\ProjectModificationDateSubscriber;
|
||||
use Subscriber\WebhookSubscriber;
|
||||
use Subscriber\SubtaskTimesheetSubscriber;
|
||||
use Subscriber\SubtaskTimeTrackingSubscriber;
|
||||
use Subscriber\TaskMovedDateSubscriber;
|
||||
use Subscriber\TransitionSubscriber;
|
||||
use Subscriber\RecurringTaskSubscriber;
|
||||
|
|
@ -29,7 +29,7 @@ class EventDispatcherProvider implements ServiceProviderInterface
|
|||
$container['dispatcher']->addSubscriber(new ProjectModificationDateSubscriber($container));
|
||||
$container['dispatcher']->addSubscriber(new WebhookSubscriber($container));
|
||||
$container['dispatcher']->addSubscriber(new NotificationSubscriber($container));
|
||||
$container['dispatcher']->addSubscriber(new SubtaskTimesheetSubscriber($container));
|
||||
$container['dispatcher']->addSubscriber(new SubtaskTimeTrackingSubscriber($container));
|
||||
$container['dispatcher']->addSubscriber(new TaskMovedDateSubscriber($container));
|
||||
$container['dispatcher']->addSubscriber(new TransitionSubscriber($container));
|
||||
$container['dispatcher']->addSubscriber(new RecurringTaskSubscriber($container));
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
|||
use Model\Subtask;
|
||||
use Event\SubtaskEvent;
|
||||
|
||||
class SubtaskTimesheetSubscriber extends \Core\Base implements EventSubscriberInterface
|
||||
class SubtaskTimeTrackingSubscriber extends \Core\Base implements EventSubscriberInterface
|
||||
{
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
|
|
@ -28,7 +28,7 @@ class SubtaskTimesheetSubscriber extends \Core\Base implements EventSubscriberIn
|
|||
|
||||
public function logStartEnd(SubtaskEvent $event)
|
||||
{
|
||||
if ($this->config->get('subtask_time_tracking') == 1 && isset($event['status'])) {
|
||||
if (isset($event['status'])) {
|
||||
|
||||
$subtask = $this->subtask->getById($event['id']);
|
||||
|
||||
|
|
@ -32,8 +32,8 @@
|
|||
</span>
|
||||
|
||||
<div class="task-board-days">
|
||||
<span title="<?= t('Task age in days')?>" class="task-days-age"><?= $this->task->age($task['date_creation']) ?></span>
|
||||
<span title="<?= t('Days in this column')?>" class="task-days-incolumn"><?= $this->task->age($task['date_moved']) ?></span>
|
||||
<span title="<?= t('Task age in days')?>" class="task-days-age"><?= $this->datetime->age($task['date_creation']) ?></span>
|
||||
<span title="<?= t('Days in this column')?>" class="task-days-incolumn"><?= $this->datetime->age($task['date_moved']) ?></span>
|
||||
</div>
|
||||
|
||||
<div class="task-board-title">
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@
|
|||
<p class="form-help"><?= t('Example: "Bug, Feature Request, Improvement"') ?></p>
|
||||
|
||||
<?= $this->form->checkbox('subtask_restriction', t('Allow only one subtask in progress at the same time for a user'), 1, $values['subtask_restriction'] == 1) ?>
|
||||
<?= $this->form->checkbox('subtask_time_tracking', t('Enable time tracking for subtasks'), 1, $values['subtask_time_tracking'] == 1) ?>
|
||||
|
||||
<div class="form-actions">
|
||||
<input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/>
|
||||
|
|
|
|||
|
|
@ -33,13 +33,29 @@
|
|||
<?php endif ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php if (! empty($subtask['time_spent'])): ?>
|
||||
<strong><?= $this->e($subtask['time_spent']).'h' ?></strong> <?= t('spent') ?>
|
||||
<?php endif ?>
|
||||
<ul class="no-bullet">
|
||||
<li>
|
||||
<?php if (! empty($subtask['time_spent'])): ?>
|
||||
<strong><?= $this->e($subtask['time_spent']).'h' ?></strong> <?= t('spent') ?>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if (! empty($subtask['time_estimated'])): ?>
|
||||
<strong><?= $this->e($subtask['time_estimated']).'h' ?></strong> <?= t('estimated') ?>
|
||||
<?php endif ?>
|
||||
<?php if (! empty($subtask['time_estimated'])): ?>
|
||||
<strong><?= $this->e($subtask['time_estimated']).'h' ?></strong> <?= t('estimated') ?>
|
||||
<?php endif ?>
|
||||
</li>
|
||||
<?php if (! isset($not_editable) && $subtask['user_id'] == $this->user->getId()): ?>
|
||||
<li>
|
||||
<?php if ($subtask['is_timer_started']): ?>
|
||||
<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->datetime->age($subtask['timer_start_date']) ?>)
|
||||
<?php else: ?>
|
||||
<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'])) ?>
|
||||
<?php endif ?>
|
||||
</li>
|
||||
<?php endif ?>
|
||||
</ul>
|
||||
</td>
|
||||
<?php if (! isset($not_editable)): ?>
|
||||
<td>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
"erusev/parsedown" : "1.5.1",
|
||||
"fabiang/xmpp" : "0.6.1",
|
||||
"fguillot/json-rpc" : "0.0.3",
|
||||
"fguillot/picodb" : "0.0.3",
|
||||
"fguillot/picodb" : "dev-master",
|
||||
"fguillot/simpleLogger" : "0.0.2",
|
||||
"fguillot/simple-validator" : "0.0.3",
|
||||
"lusitanian/oauth" : "0.3.5",
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"hash": "4aed9321378ab6e96c0fd0170b379c38",
|
||||
"hash": "c5913f9f57295aae111f3a29b385dafb",
|
||||
"packages": [
|
||||
{
|
||||
"name": "christian-riesen/base32",
|
||||
|
|
@ -297,16 +297,16 @@
|
|||
},
|
||||
{
|
||||
"name": "fguillot/picodb",
|
||||
"version": "v0.0.3",
|
||||
"version": "dev-master",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/fguillot/picoDb.git",
|
||||
"reference": "f65d11cb52de34e0fd236a34184ca1a310da244a"
|
||||
"reference": "dd08649713c9d8330b3c5fa23220a11cb5da3e79"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/fguillot/picoDb/zipball/f65d11cb52de34e0fd236a34184ca1a310da244a",
|
||||
"reference": "f65d11cb52de34e0fd236a34184ca1a310da244a",
|
||||
"url": "https://api.github.com/repos/fguillot/picoDb/zipball/dd08649713c9d8330b3c5fa23220a11cb5da3e79",
|
||||
"reference": "dd08649713c9d8330b3c5fa23220a11cb5da3e79",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -330,7 +330,7 @@
|
|||
],
|
||||
"description": "Minimalist database query builder",
|
||||
"homepage": "https://github.com/fguillot/picoDb",
|
||||
"time": "2015-05-17 23:57:05"
|
||||
"time": "2015-06-24 21:58:15"
|
||||
},
|
||||
{
|
||||
"name": "fguillot/simple-validator",
|
||||
|
|
@ -820,6 +820,7 @@
|
|||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": {
|
||||
"fguillot/picodb": 20,
|
||||
"swiftmailer/swiftmailer": 0,
|
||||
"symfony/console": 0
|
||||
},
|
||||
|
|
|
|||
|
|
@ -6,6 +6,18 @@ use Helper\Datetime;
|
|||
|
||||
class DatetimeHelperTest extends Base
|
||||
{
|
||||
public function testAge()
|
||||
{
|
||||
$h = new Datetime($this->container);
|
||||
|
||||
$this->assertEquals('<15m', $h->age(0, 30));
|
||||
$this->assertEquals('<30m', $h->age(0, 1000));
|
||||
$this->assertEquals('<1h', $h->age(0, 3000));
|
||||
$this->assertEquals('~2h', $h->age(0, 2*3600));
|
||||
$this->assertEquals('1d', $h->age(0, 30*3600));
|
||||
$this->assertEquals('2d', $h->age(0, 65*3600));
|
||||
}
|
||||
|
||||
public function testGetDayHours()
|
||||
{
|
||||
$h = new Datetime($this->container);
|
||||
|
|
|
|||
|
|
@ -9,9 +9,61 @@ use Model\SubtaskTimeTracking;
|
|||
use Model\Project;
|
||||
use Model\Category;
|
||||
use Model\User;
|
||||
use Core\Session;
|
||||
|
||||
class SubtaskTimeTrackingTest extends Base
|
||||
{
|
||||
public function testGetTimerStatus()
|
||||
{
|
||||
$tc = new TaskCreation($this->container);
|
||||
$s = new Subtask($this->container);
|
||||
$st = new SubtaskTimeTracking($this->container);
|
||||
$p = new Project($this->container);
|
||||
$ss = new Session;
|
||||
|
||||
$ss['user'] = array('id' => 1);
|
||||
|
||||
$this->assertEquals(1, $p->create(array('name' => 'test1')));
|
||||
$this->assertEquals(1, $tc->create(array('title' => 'test 1', 'project_id' => 1, 'column_id' => 1, 'owner_id' => 1)));
|
||||
$this->assertEquals(1, $s->create(array('title' => 'subtask #1', 'task_id' => 1, 'user_id' => 1)));
|
||||
|
||||
// Nothing started
|
||||
$subtasks = $s->getAll(1);
|
||||
$this->assertNotEmpty($subtasks);
|
||||
$this->assertEquals(0, $subtasks[0]['timer_start_date']);
|
||||
$this->assertFalse($subtasks[0]['is_timer_started']);
|
||||
|
||||
$subtask = $s->getbyId(1, true);
|
||||
$this->assertNotEmpty($subtask);
|
||||
$this->assertEquals(0, $subtask['timer_start_date']);
|
||||
$this->assertFalse($subtask['is_timer_started']);
|
||||
|
||||
// Start the clock
|
||||
$this->assertTrue($st->logStartTime(1, 1));
|
||||
|
||||
$subtasks = $s->getAll(1);
|
||||
$this->assertNotEmpty($subtasks);
|
||||
$this->assertEquals(time(), $subtasks[0]['timer_start_date'], '', 3);
|
||||
$this->assertTrue($subtasks[0]['is_timer_started']);
|
||||
|
||||
$subtask = $s->getbyId(1, true);
|
||||
$this->assertNotEmpty($subtask);
|
||||
$this->assertEquals(time(), $subtask['timer_start_date'], '', 3);
|
||||
$this->assertTrue($subtask['is_timer_started']);
|
||||
|
||||
// Stop the clock
|
||||
$this->assertTrue($st->logEndTime(1, 1));
|
||||
$subtasks = $s->getAll(1);
|
||||
$this->assertNotEmpty($subtasks);
|
||||
$this->assertEquals(0, $subtasks[0]['timer_start_date']);
|
||||
$this->assertFalse($subtasks[0]['is_timer_started']);
|
||||
|
||||
$subtask = $s->getbyId(1, true);
|
||||
$this->assertNotEmpty($subtask);
|
||||
$this->assertEquals(0, $subtask['timer_start_date']);
|
||||
$this->assertFalse($subtask['is_timer_started']);
|
||||
}
|
||||
|
||||
public function testLogStartTime()
|
||||
{
|
||||
$tc = new TaskCreation($this->container);
|
||||
|
|
|
|||
Loading…
Reference in New Issue