diff --git a/README.markdown b/README.markdown
index c003b110d..7f9ff1dd8 100644
--- a/README.markdown
+++ b/README.markdown
@@ -99,7 +99,9 @@ Documentation
- [Keyboard shortcuts](docs/keyboard-shortcuts.markdown)
- [Application settings](docs/application-configuration.markdown)
+- [Project settings](docs/project-configuration.markdown)
- [Board settings](docs/board-configuration.markdown)
+- [Calendar settings](docs/calendar-configuration.markdown)
- [Link settings](docs/link-labels.markdown)
- [Currency rate](docs/currency-rate.markdown)
- [Config file](docs/config.markdown)
diff --git a/app/Controller/Calendar.php b/app/Controller/Calendar.php
index 49c7f56e5..41642a59b 100644
--- a/app/Controller/Calendar.php
+++ b/app/Controller/Calendar.php
@@ -47,7 +47,8 @@ class Calendar extends Base
$start = $this->request->getStringParam('start');
$end = $this->request->getStringParam('end');
- $due_tasks = $this->taskFilter
+ // Common filter
+ $filter = $this->taskFilter
->create()
->filterByProject($project_id)
->filterByCategory($this->request->getIntegerParam('category_id', -1))
@@ -55,11 +56,20 @@ class Calendar extends Base
->filterByColumn($this->request->getIntegerParam('column_id', -1))
->filterBySwimlane($this->request->getIntegerParam('swimlane_id', -1))
->filterByColor($this->request->getStringParam('color_id'))
- ->filterByStatus($this->request->getIntegerParam('is_active', -1))
- ->filterByDueDateRange($start, $end)
- ->toCalendarEvents();
+ ->filterByStatus($this->request->getIntegerParam('is_active', -1));
- $this->response->json($due_tasks);
+ // Tasks
+ if ($this->config->get('calendar_project_tasks', 'date_started') === 'date_creation') {
+ $events = $filter->copy()->filterByCreationDateRange($start, $end)->toDateTimeCalendarEvents('date_creation', 'date_completed');
+ }
+ else {
+ $events = $filter->copy()->filterByStartDateRange($start, $end)->toDateTimeCalendarEvents('date_started', 'date_completed');
+ }
+
+ // Tasks with due date
+ $events = array_merge($events, $filter->copy()->filterByDueDateRange($start, $end)->toAllDayCalendarEvents());
+
+ $this->response->json($events);
}
/**
@@ -72,19 +82,30 @@ class Calendar extends Base
$user_id = $this->request->getIntegerParam('user_id');
$start = $this->request->getStringParam('start');
$end = $this->request->getStringParam('end');
+ $filter = $this->taskFilter->create()->filterByOwner($user_id)->filterByStatus(TaskModel::STATUS_OPEN);
- $due_tasks = $this->taskFilter
- ->create()
- ->filterByOwner($user_id)
- ->filterByStatus(TaskModel::STATUS_OPEN)
- ->filterByDueDateRange($start, $end)
- ->toCalendarEvents();
+ // Task with due date
+ $events = $filter->copy()->filterByDueDateRange($start, $end)->toAllDayCalendarEvents();
- $subtask_timeslots = $this->subtaskTimeTracking->getUserCalendarEvents($user_id, $start, $end);
+ // Tasks
+ if ($this->config->get('calendar_user_tasks', 'date_started') === 'date_creation') {
+ $events = array_merge($events, $filter->copy()->filterByCreationDateRange($start, $end)->toDateTimeCalendarEvents('date_creation', 'date_completed'));
+ }
+ else {
+ $events = array_merge($events, $filter->copy()->filterByStartDateRange($start, $end)->toDateTimeCalendarEvents('date_started', 'date_completed'));
+ }
- $subtask_forcast = $this->config->get('subtask_forecast') == 1 ? $this->subtaskForecast->getCalendarEvents($user_id, $end) : array();
+ // Subtasks time tracking
+ if ($this->config->get('calendar_user_subtasks_time_tracking') == 1) {
+ $events = array_merge($events, $this->subtaskTimeTracking->getUserCalendarEvents($user_id, $start, $end));
+ }
- $this->response->json(array_merge($due_tasks, $subtask_timeslots, $subtask_forcast));
+ // Subtask estimates
+ if ($this->config->get('calendar_user_subtasks_forecast') == 1) {
+ $events = array_merge($events, $this->subtaskForecast->getCalendarEvents($user_id, $end));
+ }
+
+ $this->response->json($events);
}
/**
diff --git a/app/Controller/Config.php b/app/Controller/Config.php
index c17b9f64a..fbd374ab9 100644
--- a/app/Controller/Config.php
+++ b/app/Controller/Config.php
@@ -40,11 +40,16 @@ class Config extends Base
$values = $this->request->getValues();
- if ($redirect === 'board') {
- $values += array('subtask_restriction' => 0, 'subtask_time_tracking' => 0, 'subtask_forecast' => 0);
- }
- else if ($redirect === 'integrations') {
- $values += array('integration_slack_webhook' => 0, 'integration_hipchat' => 0, 'integration_gravatar' => 0, 'integration_jabber' => 0);
+ switch ($redirect) {
+ case 'project':
+ $values += array('subtask_restriction' => 0, 'subtask_time_tracking' => 0);
+ break;
+ case 'integrations':
+ $values += array('integration_slack_webhook' => 0, 'integration_hipchat' => 0, 'integration_gravatar' => 0, 'integration_jabber' => 0);
+ break;
+ case 'calendar':
+ $values += array('calendar_user_subtasks_forecast' => 0, 'calendar_user_subtasks_time_tracking' => 0);
+ break;
}
if ($this->config->save($values)) {
@@ -89,6 +94,21 @@ class Config extends Base
)));
}
+ /**
+ * Display the project settings page
+ *
+ * @access public
+ */
+ public function project()
+ {
+ $this->common('project');
+
+ $this->response->html($this->layout('config/project', array(
+ 'default_columns' => implode(', ', $this->board->getDefaultColumns()),
+ 'title' => t('Settings').' > '.t('Project settings'),
+ )));
+ }
+
/**
* Display the board settings page
*
@@ -99,11 +119,24 @@ class Config extends Base
$this->common('board');
$this->response->html($this->layout('config/board', array(
- 'default_columns' => implode(', ', $this->board->getDefaultColumns()),
'title' => t('Settings').' > '.t('Board settings'),
)));
}
+ /**
+ * Display the calendar settings page
+ *
+ * @access public
+ */
+ public function calendar()
+ {
+ $this->common('calendar');
+
+ $this->response->html($this->layout('config/calendar', array(
+ 'title' => t('Settings').' > '.t('Calendar settings'),
+ )));
+ }
+
/**
* Display the integration settings page
*
diff --git a/app/Core/Helper.php b/app/Core/Helper.php
index 0650c2938..12557e451 100644
--- a/app/Core/Helper.php
+++ b/app/Core/Helper.php
@@ -274,7 +274,7 @@ class Helper
*/
public function formRadio($name, $label, $value, $selected = false, $class = '')
{
- return '';
+ return '';
}
/**
diff --git a/app/Locale/da_DK/translations.php b/app/Locale/da_DK/translations.php
index 36d6eb9fc..0815440f9 100644
--- a/app/Locale/da_DK/translations.php
+++ b/app/Locale/da_DK/translations.php
@@ -808,7 +808,7 @@ return array(
// 'Move the task to another column when assigned to a user' => '',
// 'Move the task to another column when assignee is cleared' => '',
// 'Source column' => '',
- // 'Show subtask estimates in the user calendar' => '',
+ // 'Show subtask estimates (forecast of future work)' => '',
// 'Transitions' => '',
// 'Executer' => '',
// 'Time spent in the column' => '',
@@ -908,4 +908,12 @@ return array(
// 'Multi-user chat room' => '',
// 'Help on Jabber integration' => '',
// 'The server address must use this format: "tcp://hostname:5222"' => '',
+ // 'Calendar settings' => '',
+ // 'Project calendar view' => '',
+ // 'Project settings' => '',
+ // 'Show subtasks based on the time tracking' => '',
+ // 'Show tasks based on the creation date' => '',
+ // 'Show tasks based on the start date' => '',
+ // 'Subtasks time tracking' => '',
+ // 'User calendar view' => '',
);
diff --git a/app/Locale/de_DE/translations.php b/app/Locale/de_DE/translations.php
index ee91a3d27..c859d4334 100644
--- a/app/Locale/de_DE/translations.php
+++ b/app/Locale/de_DE/translations.php
@@ -808,7 +808,7 @@ return array(
'Move the task to another column when assigned to a user' => 'Aufgabe in eine andere Spalte verschieben, wenn ein User zugeordnet wurde.',
'Move the task to another column when assignee is cleared' => 'Aufgabe in eine andere Spalte verschieben, wenn die Zuordnung gelöscht wurde.',
'Source column' => 'Quellspalte',
- 'Show subtask estimates in the user calendar' => 'Teilaufgabenschätzung in Benutzerkalender anzeigen.',
+ // 'Show subtask estimates (forecast of future work)' => '',
'Transitions' => 'Übergänge',
'Executer' => 'Ausführender',
'Time spent in the column' => 'Zeit in Spalte verbracht',
@@ -908,4 +908,12 @@ return array(
// 'Multi-user chat room' => '',
// 'Help on Jabber integration' => '',
// 'The server address must use this format: "tcp://hostname:5222"' => '',
+ // 'Calendar settings' => '',
+ // 'Project calendar view' => '',
+ // 'Project settings' => '',
+ // 'Show subtasks based on the time tracking' => '',
+ // 'Show tasks based on the creation date' => '',
+ // 'Show tasks based on the start date' => '',
+ // 'Subtasks time tracking' => '',
+ // 'User calendar view' => '',
);
diff --git a/app/Locale/es_ES/translations.php b/app/Locale/es_ES/translations.php
index a9d8dde7b..6f30046c3 100644
--- a/app/Locale/es_ES/translations.php
+++ b/app/Locale/es_ES/translations.php
@@ -808,7 +808,7 @@ return array(
'Move the task to another column when assigned to a user' => 'Mover la tarea a otra columna al asignarse al usuario',
'Move the task to another column when assignee is cleared' => 'Mover la tarea a otra columna al quitar el asignado',
'Source column' => 'Columna fuente',
- 'Show subtask estimates in the user calendar' => 'Mostrar estimaciones de subtarea en calendario de usuario',
+ // 'Show subtask estimates (forecast of future work)' => '',
'Transitions' => 'Transiciones',
'Executer' => 'Ejecutor',
'Time spent in the column' => 'Tiempo transcurrido en la columna',
@@ -908,4 +908,12 @@ return array(
// 'Multi-user chat room' => '',
// 'Help on Jabber integration' => '',
// 'The server address must use this format: "tcp://hostname:5222"' => '',
+ // 'Calendar settings' => '',
+ // 'Project calendar view' => '',
+ // 'Project settings' => '',
+ // 'Show subtasks based on the time tracking' => '',
+ // 'Show tasks based on the creation date' => '',
+ // 'Show tasks based on the start date' => '',
+ // 'Subtasks time tracking' => '',
+ // 'User calendar view' => '',
);
diff --git a/app/Locale/fi_FI/translations.php b/app/Locale/fi_FI/translations.php
index b975d6643..efd7eb6d6 100644
--- a/app/Locale/fi_FI/translations.php
+++ b/app/Locale/fi_FI/translations.php
@@ -808,7 +808,7 @@ return array(
// 'Move the task to another column when assigned to a user' => '',
// 'Move the task to another column when assignee is cleared' => '',
// 'Source column' => '',
- // 'Show subtask estimates in the user calendar' => '',
+ // 'Show subtask estimates (forecast of future work)' => '',
// 'Transitions' => '',
// 'Executer' => '',
// 'Time spent in the column' => '',
@@ -908,4 +908,12 @@ return array(
// 'Multi-user chat room' => '',
// 'Help on Jabber integration' => '',
// 'The server address must use this format: "tcp://hostname:5222"' => '',
+ // 'Calendar settings' => '',
+ // 'Project calendar view' => '',
+ // 'Project settings' => '',
+ // 'Show subtasks based on the time tracking' => '',
+ // 'Show tasks based on the creation date' => '',
+ // 'Show tasks based on the start date' => '',
+ // 'Subtasks time tracking' => '',
+ // 'User calendar view' => '',
);
diff --git a/app/Locale/fr_FR/translations.php b/app/Locale/fr_FR/translations.php
index 03bb59f58..e50bf1b34 100644
--- a/app/Locale/fr_FR/translations.php
+++ b/app/Locale/fr_FR/translations.php
@@ -810,7 +810,7 @@ return array(
'Move the task to another column when assigned to a user' => 'Déplacer la tâche dans une autre colonne lorsque celle-ci est assignée à quelqu\'un',
'Move the task to another column when assignee is cleared' => 'Déplacer la tâche dans une autre colonne lorsque celle-ci n\'est plus assignée',
'Source column' => 'Colonne d\'origine',
- 'Show subtask estimates in the user calendar' => 'Afficher le temps estimé des sous-tâches dans le calendrier utilisateur',
+ 'Show subtask estimates (forecast of future work)' => 'Afficher l\'estimation des sous-tâches (prévision du travail à venir)',
'Transitions' => 'Transitions',
'Executer' => 'Exécutant',
'Time spent in the column' => 'Temps passé dans la colonne',
@@ -910,4 +910,12 @@ return array(
'Multi-user chat room' => 'Salon de discussion multi-utilisateurs',
'Help on Jabber integration' => 'Aide sur l\'intégration avec Jabber',
'The server address must use this format: "tcp://hostname:5222"' => 'L\'adresse du serveur doit utiliser le format suivant : « tcp://hostname:5222 »',
+ 'Calendar settings' => 'Paramètres du calendrier',
+ 'Project calendar view' => 'Vue en mode projet du calendrier',
+ 'Project settings' => 'Paramètres des projets',
+ 'Show subtasks based on the time tracking' => 'Afficher les sous-tâches basé sur le suivi du temps',
+ 'Show tasks based on the creation date' => 'Afficher les tâches en fonction de la date de création',
+ 'Show tasks based on the start date' => 'Afficher les tâches en fonction de la date de début',
+ 'Subtasks time tracking' => 'Suivi du temps par rapport aux sous-tâches',
+ 'User calendar view' => 'Vue en mode utilisateur du calendrier',
);
diff --git a/app/Locale/hu_HU/translations.php b/app/Locale/hu_HU/translations.php
index ceae14bd4..7f0280a81 100644
--- a/app/Locale/hu_HU/translations.php
+++ b/app/Locale/hu_HU/translations.php
@@ -808,7 +808,7 @@ return array(
'Move the task to another column when assigned to a user' => 'Feladat másik oszlopba helyezése felhasználóhoz rendélés után',
'Move the task to another column when assignee is cleared' => 'Feladat másik oszlopba helyezése felhasználóhoz rendélés törlésekor',
'Source column' => 'Forrás oszlop',
- // 'Show subtask estimates in the user calendar' => '',
+ // 'Show subtask estimates (forecast of future work)' => '',
// 'Transitions' => '',
// 'Executer' => '',
// 'Time spent in the column' => '',
@@ -908,4 +908,12 @@ return array(
// 'Multi-user chat room' => '',
// 'Help on Jabber integration' => '',
// 'The server address must use this format: "tcp://hostname:5222"' => '',
+ // 'Calendar settings' => '',
+ // 'Project calendar view' => '',
+ // 'Project settings' => '',
+ // 'Show subtasks based on the time tracking' => '',
+ // 'Show tasks based on the creation date' => '',
+ // 'Show tasks based on the start date' => '',
+ // 'Subtasks time tracking' => '',
+ // 'User calendar view' => '',
);
diff --git a/app/Locale/it_IT/translations.php b/app/Locale/it_IT/translations.php
index a3b5d3a1a..3f2f5f76c 100644
--- a/app/Locale/it_IT/translations.php
+++ b/app/Locale/it_IT/translations.php
@@ -808,7 +808,7 @@ return array(
'Move the task to another column when assigned to a user' => 'Sposta il compito in un\'altra colonna quando viene assegnato ad un utente',
'Move the task to another column when assignee is cleared' => 'Sposta il compito in un\'altra colonna quando l\'assegnatario cancellato',
'Source column' => 'Colonna sorgente',
- 'Show subtask estimates in the user calendar' => 'Mostra le stime dei sotto-compiti nel calendario utente',
+ // 'Show subtask estimates (forecast of future work)' => '',
'Transitions' => 'Transizioni',
'Executer' => 'Esecutore',
'Time spent in the column' => 'Tempo trascorso nella colonna',
@@ -908,4 +908,12 @@ return array(
// 'Multi-user chat room' => '',
// 'Help on Jabber integration' => '',
// 'The server address must use this format: "tcp://hostname:5222"' => '',
+ // 'Calendar settings' => '',
+ // 'Project calendar view' => '',
+ // 'Project settings' => '',
+ // 'Show subtasks based on the time tracking' => '',
+ // 'Show tasks based on the creation date' => '',
+ // 'Show tasks based on the start date' => '',
+ // 'Subtasks time tracking' => '',
+ // 'User calendar view' => '',
);
diff --git a/app/Locale/ja_JP/translations.php b/app/Locale/ja_JP/translations.php
index 0be0c91f8..57ba3abb1 100644
--- a/app/Locale/ja_JP/translations.php
+++ b/app/Locale/ja_JP/translations.php
@@ -808,7 +808,7 @@ return array(
'Move the task to another column when assigned to a user' => 'ユーザの割り当てをしたらタスクを他のカラムに移動',
'Move the task to another column when assignee is cleared' => 'ユーザの割り当てがなくなったらタスクを他のカラムに移動',
'Source column' => '移動元のカラム',
- 'Show subtask estimates in the user calendar' => 'カレンダーでサブタスクの見積もりを表示',
+ // 'Show subtask estimates (forecast of future work)' => '',
'Transitions' => '履歴',
'Executer' => '実行者',
'Time spent in the column' => 'カラムでの時間消費',
@@ -908,4 +908,12 @@ return array(
// 'Multi-user chat room' => '',
// 'Help on Jabber integration' => '',
// 'The server address must use this format: "tcp://hostname:5222"' => '',
+ // 'Calendar settings' => '',
+ // 'Project calendar view' => '',
+ // 'Project settings' => '',
+ // 'Show subtasks based on the time tracking' => '',
+ // 'Show tasks based on the creation date' => '',
+ // 'Show tasks based on the start date' => '',
+ // 'Subtasks time tracking' => '',
+ // 'User calendar view' => '',
);
diff --git a/app/Locale/nl_NL/translations.php b/app/Locale/nl_NL/translations.php
index c971f95c0..f3f2e72bf 100644
--- a/app/Locale/nl_NL/translations.php
+++ b/app/Locale/nl_NL/translations.php
@@ -808,7 +808,7 @@ return array(
// 'Move the task to another column when assigned to a user' => '',
// 'Move the task to another column when assignee is cleared' => '',
// 'Source column' => '',
- // 'Show subtask estimates in the user calendar' => '',
+ // 'Show subtask estimates (forecast of future work)' => '',
// 'Transitions' => '',
// 'Executer' => '',
// 'Time spent in the column' => '',
@@ -908,4 +908,12 @@ return array(
// 'Multi-user chat room' => '',
// 'Help on Jabber integration' => '',
// 'The server address must use this format: "tcp://hostname:5222"' => '',
+ // 'Calendar settings' => '',
+ // 'Project calendar view' => '',
+ // 'Project settings' => '',
+ // 'Show subtasks based on the time tracking' => '',
+ // 'Show tasks based on the creation date' => '',
+ // 'Show tasks based on the start date' => '',
+ // 'Subtasks time tracking' => '',
+ // 'User calendar view' => '',
);
diff --git a/app/Locale/pl_PL/translations.php b/app/Locale/pl_PL/translations.php
index 5f035b5d1..cb24b60b7 100644
--- a/app/Locale/pl_PL/translations.php
+++ b/app/Locale/pl_PL/translations.php
@@ -808,7 +808,7 @@ return array(
// 'Move the task to another column when assigned to a user' => '',
// 'Move the task to another column when assignee is cleared' => '',
// 'Source column' => '',
- // 'Show subtask estimates in the user calendar' => '',
+ // 'Show subtask estimates (forecast of future work)' => '',
// 'Transitions' => '',
// 'Executer' => '',
// 'Time spent in the column' => '',
@@ -908,4 +908,12 @@ return array(
// 'Multi-user chat room' => '',
// 'Help on Jabber integration' => '',
// 'The server address must use this format: "tcp://hostname:5222"' => '',
+ // 'Calendar settings' => '',
+ // 'Project calendar view' => '',
+ // 'Project settings' => '',
+ // 'Show subtasks based on the time tracking' => '',
+ // 'Show tasks based on the creation date' => '',
+ // 'Show tasks based on the start date' => '',
+ // 'Subtasks time tracking' => '',
+ // 'User calendar view' => '',
);
diff --git a/app/Locale/pt_BR/translations.php b/app/Locale/pt_BR/translations.php
index acf5a6beb..652dc80ea 100644
--- a/app/Locale/pt_BR/translations.php
+++ b/app/Locale/pt_BR/translations.php
@@ -808,7 +808,7 @@ return array(
'Move the task to another column when assigned to a user' => 'Mover a tarefa para uma outra coluna quando esta está atribuída a um usuário',
'Move the task to another column when assignee is cleared' => 'Mover a tarefa para uma outra coluna quando esta não está atribuída',
'Source column' => 'Coluna de origem',
- 'Show subtask estimates in the user calendar' => 'Mostrar o tempo estimado das subtarefas no calendário do usuário',
+ // 'Show subtask estimates (forecast of future work)' => '',
'Transitions' => 'Transições',
'Executer' => 'Executor(a)',
'Time spent in the column' => 'Tempo gasto na coluna',
@@ -908,4 +908,12 @@ return array(
// 'Multi-user chat room' => '',
// 'Help on Jabber integration' => '',
// 'The server address must use this format: "tcp://hostname:5222"' => '',
+ // 'Calendar settings' => '',
+ // 'Project calendar view' => '',
+ // 'Project settings' => '',
+ // 'Show subtasks based on the time tracking' => '',
+ // 'Show tasks based on the creation date' => '',
+ // 'Show tasks based on the start date' => '',
+ // 'Subtasks time tracking' => '',
+ // 'User calendar view' => '',
);
diff --git a/app/Locale/ru_RU/translations.php b/app/Locale/ru_RU/translations.php
index 37d5c50f4..354c6a5bb 100644
--- a/app/Locale/ru_RU/translations.php
+++ b/app/Locale/ru_RU/translations.php
@@ -808,7 +808,7 @@ return array(
// 'Move the task to another column when assigned to a user' => '',
// 'Move the task to another column when assignee is cleared' => '',
// 'Source column' => '',
- // 'Show subtask estimates in the user calendar' => '',
+ // 'Show subtask estimates (forecast of future work)' => '',
'Transitions' => 'Перемещения',
'Executer' => 'Исполнитель',
'Time spent in the column' => 'Время проведенное в колонке',
@@ -908,4 +908,12 @@ return array(
// 'Multi-user chat room' => '',
// 'Help on Jabber integration' => '',
// 'The server address must use this format: "tcp://hostname:5222"' => '',
+ // 'Calendar settings' => '',
+ // 'Project calendar view' => '',
+ // 'Project settings' => '',
+ // 'Show subtasks based on the time tracking' => '',
+ // 'Show tasks based on the creation date' => '',
+ // 'Show tasks based on the start date' => '',
+ // 'Subtasks time tracking' => '',
+ // 'User calendar view' => '',
);
diff --git a/app/Locale/sr_Latn_RS/translations.php b/app/Locale/sr_Latn_RS/translations.php
index eec574549..a43fe57be 100644
--- a/app/Locale/sr_Latn_RS/translations.php
+++ b/app/Locale/sr_Latn_RS/translations.php
@@ -808,7 +808,7 @@ return array(
// 'Move the task to another column when assigned to a user' => '',
// 'Move the task to another column when assignee is cleared' => '',
// 'Source column' => '',
- // 'Show subtask estimates in the user calendar' => '',
+ // 'Show subtask estimates (forecast of future work)' => '',
// 'Transitions' => '',
// 'Executer' => '',
// 'Time spent in the column' => '',
@@ -908,4 +908,12 @@ return array(
// 'Multi-user chat room' => '',
// 'Help on Jabber integration' => '',
// 'The server address must use this format: "tcp://hostname:5222"' => '',
+ // 'Calendar settings' => '',
+ // 'Project calendar view' => '',
+ // 'Project settings' => '',
+ // 'Show subtasks based on the time tracking' => '',
+ // 'Show tasks based on the creation date' => '',
+ // 'Show tasks based on the start date' => '',
+ // 'Subtasks time tracking' => '',
+ // 'User calendar view' => '',
);
diff --git a/app/Locale/sv_SE/translations.php b/app/Locale/sv_SE/translations.php
index 28addb8c7..8c7229f48 100644
--- a/app/Locale/sv_SE/translations.php
+++ b/app/Locale/sv_SE/translations.php
@@ -808,7 +808,7 @@ return array(
'Move the task to another column when assigned to a user' => 'Flytta uppgiften till en annan kolumn när den tilldelats en användare',
'Move the task to another column when assignee is cleared' => 'Flytta uppgiften till en annan kolumn när tilldelningen tas bort.',
'Source column' => 'Källkolumn',
- 'Show subtask estimates in the user calendar' => 'Visa deluppgiftsuppskattning i användarens kalender',
+ // 'Show subtask estimates (forecast of future work)' => '',
'Transitions' => 'Övergångar',
'Executer' => 'Verkställare',
'Time spent in the column' => 'Tid i kolumnen.',
@@ -908,4 +908,12 @@ return array(
// 'Multi-user chat room' => '',
// 'Help on Jabber integration' => '',
// 'The server address must use this format: "tcp://hostname:5222"' => '',
+ // 'Calendar settings' => '',
+ // 'Project calendar view' => '',
+ // 'Project settings' => '',
+ // 'Show subtasks based on the time tracking' => '',
+ // 'Show tasks based on the creation date' => '',
+ // 'Show tasks based on the start date' => '',
+ // 'Subtasks time tracking' => '',
+ // 'User calendar view' => '',
);
diff --git a/app/Locale/th_TH/translations.php b/app/Locale/th_TH/translations.php
index 6ce864332..3066e7980 100644
--- a/app/Locale/th_TH/translations.php
+++ b/app/Locale/th_TH/translations.php
@@ -808,7 +808,7 @@ return array(
// 'Move the task to another column when assigned to a user' => '',
// 'Move the task to another column when assignee is cleared' => '',
// 'Source column' => '',
- // 'Show subtask estimates in the user calendar' => '',
+ // 'Show subtask estimates (forecast of future work)' => '',
// 'Transitions' => '',
// 'Executer' => '',
// 'Time spent in the column' => '',
@@ -908,4 +908,12 @@ return array(
// 'Multi-user chat room' => '',
// 'Help on Jabber integration' => '',
// 'The server address must use this format: "tcp://hostname:5222"' => '',
+ // 'Calendar settings' => '',
+ // 'Project calendar view' => '',
+ // 'Project settings' => '',
+ // 'Show subtasks based on the time tracking' => '',
+ // 'Show tasks based on the creation date' => '',
+ // 'Show tasks based on the start date' => '',
+ // 'Subtasks time tracking' => '',
+ // 'User calendar view' => '',
);
diff --git a/app/Locale/tr_TR/translations.php b/app/Locale/tr_TR/translations.php
index 1daeb36a3..e5011905b 100644
--- a/app/Locale/tr_TR/translations.php
+++ b/app/Locale/tr_TR/translations.php
@@ -808,7 +808,7 @@ return array(
// 'Move the task to another column when assigned to a user' => '',
// 'Move the task to another column when assignee is cleared' => '',
// 'Source column' => '',
- // 'Show subtask estimates in the user calendar' => '',
+ // 'Show subtask estimates (forecast of future work)' => '',
// 'Transitions' => '',
// 'Executer' => '',
// 'Time spent in the column' => '',
@@ -908,4 +908,12 @@ return array(
// 'Multi-user chat room' => '',
// 'Help on Jabber integration' => '',
// 'The server address must use this format: "tcp://hostname:5222"' => '',
+ // 'Calendar settings' => '',
+ // 'Project calendar view' => '',
+ // 'Project settings' => '',
+ // 'Show subtasks based on the time tracking' => '',
+ // 'Show tasks based on the creation date' => '',
+ // 'Show tasks based on the start date' => '',
+ // 'Subtasks time tracking' => '',
+ // 'User calendar view' => '',
);
diff --git a/app/Locale/zh_CN/translations.php b/app/Locale/zh_CN/translations.php
index f5353b2e3..c61861456 100644
--- a/app/Locale/zh_CN/translations.php
+++ b/app/Locale/zh_CN/translations.php
@@ -808,7 +808,7 @@ return array(
'Move the task to another column when assigned to a user' => '指定负责人时移动到其它栏目',
'Move the task to another column when assignee is cleared' => '移除负责人时移动到其它栏目',
'Source column' => '原栏目',
- 'Show subtask estimates in the user calendar' => '在用户日历中显示子任务预估',
+ // 'Show subtask estimates (forecast of future work)' => '',
'Transitions' => '变更',
'Executer' => '执行者',
'Time spent in the column' => '栏目中的时间消耗',
@@ -908,4 +908,12 @@ return array(
// 'Multi-user chat room' => '',
// 'Help on Jabber integration' => '',
// 'The server address must use this format: "tcp://hostname:5222"' => '',
+ // 'Calendar settings' => '',
+ // 'Project calendar view' => '',
+ // 'Project settings' => '',
+ // 'Show subtasks based on the time tracking' => '',
+ // 'Show tasks based on the creation date' => '',
+ // 'Show tasks based on the start date' => '',
+ // 'Subtasks time tracking' => '',
+ // 'User calendar view' => '',
);
diff --git a/app/Model/Base.php b/app/Model/Base.php
index b4f9a9e26..dd902bb34 100644
--- a/app/Model/Base.php
+++ b/app/Model/Base.php
@@ -162,4 +162,48 @@ abstract class Base
}
}
}
+
+ /**
+ * Build SQL condition for a given time range
+ *
+ * @access protected
+ * @param string $start_time Start timestamp
+ * @param string $end_time End timestamp
+ * @param string $start_column Start column name
+ * @param string $end_column End column name
+ * @return string
+ */
+ protected function getCalendarCondition($start_time, $end_time, $start_column, $end_column)
+ {
+ $start_column = $this->db->escapeIdentifier($start_column);
+ $end_column = $this->db->escapeIdentifier($end_column);
+
+ $conditions = array(
+ "($start_column >= '$start_time' AND $start_column <= '$end_time')",
+ "($start_column <= '$start_time' AND $end_column >= '$start_time')",
+ "($start_column <= '$start_time' AND ($end_column = '0' OR $end_column IS NULL))",
+ );
+
+ return '('.implode(' OR ', $conditions).')';
+ }
+
+ /**
+ * Get common properties for task calendar events
+ *
+ * @access protected
+ * @param array $task
+ * @return array
+ */
+ protected function getTaskCalendarProperties(array &$task)
+ {
+ return array(
+ 'timezoneParam' => $this->config->getCurrentTimezone(),
+ 'id' => $task['id'],
+ 'title' => t('#%d', $task['id']).' '.$task['title'],
+ 'backgroundColor' => $this->color->getBackgroundColor($task['color_id']),
+ 'borderColor' => $this->color->getBorderColor($task['color_id']),
+ 'textColor' => 'black',
+ 'url' => $this->helper->url('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])),
+ );
+ }
}
diff --git a/app/Model/SubtaskTimeTracking.php b/app/Model/SubtaskTimeTracking.php
index a984533f6..6d4a3467c 100644
--- a/app/Model/SubtaskTimeTracking.php
+++ b/app/Model/SubtaskTimeTracking.php
@@ -135,8 +135,13 @@ class SubtaskTimeTracking extends Base
public function getUserCalendarEvents($user_id, $start, $end)
{
$result = $this->getUserQuery($user_id)
- ->addCondition($this->getCalendarCondition($start, $end))
- ->findAll();
+ ->addCondition($this->getCalendarCondition(
+ $this->dateParser->getTimestampFromIsoFormat($start),
+ $this->dateParser->getTimestampFromIsoFormat($end),
+ 'start',
+ 'end'
+ ))
+ ->findAll();
$result = $this->timetable->calculateEventsIntersect($user_id, $result, $start, $end);
@@ -154,37 +159,19 @@ class SubtaskTimeTracking extends Base
*/
public function getProjectCalendarEvents($project_id, $start, $end)
{
- $result = $this->getProjectQuery($project_id)
- ->addCondition($this->getCalendarCondition($start, $end))
- ->findAll();
+ $result = $this
+ ->getProjectQuery($project_id)
+ ->addCondition($this->getCalendarCondition(
+ $this->dateParser->getTimestampFromIsoFormat($start),
+ $this->dateParser->getTimestampFromIsoFormat($end),
+ 'start',
+ 'end'
+ ))
+ ->findAll();
return $this->toCalendarEvents($result);
}
- /**
- * Get time slots that should be displayed in the calendar time range
- *
- * @access private
- * @param string $start ISO8601 start date
- * @param string $end ISO8601 end date
- * @return string
- */
- private function getCalendarCondition($start, $end)
- {
- $start_time = $this->dateParser->getTimestampFromIsoFormat($start);
- $end_time = $this->dateParser->getTimestampFromIsoFormat($end);
- $start_column = $this->db->escapeIdentifier('start');
- $end_column = $this->db->escapeIdentifier('end');
-
- $conditions = array(
- "($start_column >= '$start_time' AND $start_column <= '$end_time')",
- "($start_column <= '$start_time' AND $end_column >= '$start_time')",
- "($start_column <= '$start_time' AND $end_column = '0')",
- );
-
- return '('.implode(' OR ', $conditions).')';
- }
-
/**
* Convert a record set to calendar events
*
diff --git a/app/Model/TaskFilter.php b/app/Model/TaskFilter.php
index 94f6bab0a..21e77e63e 100644
--- a/app/Model/TaskFilter.php
+++ b/app/Model/TaskFilter.php
@@ -10,20 +10,59 @@ namespace Model;
*/
class TaskFilter extends Base
{
- private $query;
+ /**
+ * Query
+ *
+ * @access public
+ * @var \PicoDb\Table
+ */
+ public $query;
+ /**
+ * Create a new query
+ *
+ * @access public
+ * @return TaskFilter
+ */
public function create()
{
$this->query = $this->db->table(Task::TABLE);
return $this;
}
+ /**
+ * Clone the filter
+ *
+ * @access public
+ * @return TaskFilter
+ */
+ public function copy()
+ {
+ $filter = clone($this);
+ $filter->query = clone($this->query);
+ return $filter;
+ }
+
+ /**
+ * Exclude a list of task_id
+ *
+ * @access public
+ * @param array $task_ids
+ * @return TaskFilter
+ */
public function excludeTasks(array $task_ids)
{
$this->query->notin('id', $task_ids);
return $this;
}
+ /**
+ * Filter by id
+ *
+ * @access public
+ * @param integer $task_id
+ * @return TaskFilter
+ */
public function filterById($task_id)
{
if ($task_id > 0) {
@@ -33,18 +72,39 @@ class TaskFilter extends Base
return $this;
}
+ /**
+ * Filter by title
+ *
+ * @access public
+ * @param string $title
+ * @return TaskFilter
+ */
public function filterByTitle($title)
{
$this->query->ilike('title', '%'.$title.'%');
return $this;
}
+ /**
+ * Filter by a list of project id
+ *
+ * @access public
+ * @param array $project_ids
+ * @return TaskFilter
+ */
public function filterByProjects(array $project_ids)
{
$this->query->in('project_id', $project_ids);
return $this;
}
+ /**
+ * Filter by project id
+ *
+ * @access public
+ * @param integer $project_id
+ * @return TaskFilter
+ */
public function filterByProject($project_id)
{
if ($project_id > 0) {
@@ -54,6 +114,13 @@ class TaskFilter extends Base
return $this;
}
+ /**
+ * Filter by category id
+ *
+ * @access public
+ * @param integer $category_id
+ * @return TaskFilter
+ */
public function filterByCategory($category_id)
{
if ($category_id >= 0) {
@@ -63,6 +130,13 @@ class TaskFilter extends Base
return $this;
}
+ /**
+ * Filter by assignee
+ *
+ * @access public
+ * @param integer $owner_id
+ * @return TaskFilter
+ */
public function filterByOwner($owner_id)
{
if ($owner_id >= 0) {
@@ -72,6 +146,13 @@ class TaskFilter extends Base
return $this;
}
+ /**
+ * Filter by color
+ *
+ * @access public
+ * @param string $color_id
+ * @return TaskFilter
+ */
public function filterByColor($color_id)
{
if ($color_id !== '') {
@@ -81,6 +162,13 @@ class TaskFilter extends Base
return $this;
}
+ /**
+ * Filter by column
+ *
+ * @access public
+ * @param integer $column_id
+ * @return TaskFilter
+ */
public function filterByColumn($column_id)
{
if ($column_id >= 0) {
@@ -90,6 +178,13 @@ class TaskFilter extends Base
return $this;
}
+ /**
+ * Filter by swimlane
+ *
+ * @access public
+ * @param integer $swimlane_id
+ * @return TaskFilter
+ */
public function filterBySwimlane($swimlane_id)
{
if ($swimlane_id >= 0) {
@@ -99,6 +194,13 @@ class TaskFilter extends Base
return $this;
}
+ /**
+ * Filter by status
+ *
+ * @access public
+ * @param integer $is_active
+ * @return TaskFilter
+ */
public function filterByStatus($is_active)
{
if ($is_active >= 0) {
@@ -108,6 +210,14 @@ class TaskFilter extends Base
return $this;
}
+ /**
+ * Filter by due date (range)
+ *
+ * @access public
+ * @param integer $start
+ * @param integer $end
+ * @return TaskFilter
+ */
public function filterByDueDateRange($start, $end)
{
$this->query->gte('date_due', $this->dateParser->getTimestampFromIsoFormat($start));
@@ -116,11 +226,63 @@ class TaskFilter extends Base
return $this;
}
+ /**
+ * Filter by start date (range)
+ *
+ * @access public
+ * @param integer $start
+ * @param integer $end
+ * @return TaskFilter
+ */
+ public function filterByStartDateRange($start, $end)
+ {
+ $this->query->addCondition($this->getCalendarCondition(
+ $this->dateParser->getTimestampFromIsoFormat($start),
+ $this->dateParser->getTimestampFromIsoFormat($end),
+ 'date_started',
+ 'date_completed'
+ ));
+
+ return $this;
+ }
+
+ /**
+ * Filter by creation date
+ *
+ * @access public
+ * @param integer $start
+ * @param integer $end
+ * @return TaskFilter
+ */
+ public function filterByCreationDateRange($start, $end)
+ {
+ $this->query->addCondition($this->getCalendarCondition(
+ $this->dateParser->getTimestampFromIsoFormat($start),
+ $this->dateParser->getTimestampFromIsoFormat($end),
+ 'date_creation',
+ 'date_completed'
+ ));
+
+ return $this;
+ }
+
+ /**
+ * Get all results of the filter
+ *
+ * @access public
+ * @return array
+ */
public function findAll()
{
return $this->query->findAll();
}
+ /**
+ * Format the results to the ajax autocompletion
+ *
+ * @access public
+ * @return array
+ */
public function toAutoCompletion()
{
return $this->query->columns('id', 'title')->filter(function(array $results) {
@@ -135,22 +297,53 @@ class TaskFilter extends Base
})->findAll();
}
- public function toCalendarEvents()
+ /**
+ * Transform results to calendar events
+ *
+ * @access public
+ * @param string $start_column Column name for the start date
+ * @param string $end_column Column name for the end date
+ * @return array
+ */
+ public function toDateTimeCalendarEvents($start_column, $end_column)
{
$events = array();
foreach ($this->query->findAll() as $task) {
- $events[] = array(
- 'timezoneParam' => $this->config->getCurrentTimezone(),
- 'id' => $task['id'],
- 'title' => t('#%d', $task['id']).' '.$task['title'],
- 'start' => date('Y-m-d', $task['date_due']),
- 'end' => date('Y-m-d', $task['date_due']),
- 'allday' => true,
- 'backgroundColor' => $this->color->getBackgroundColor($task['color_id']),
- 'borderColor' => $this->color->getBorderColor($task['color_id']),
- 'textColor' => 'black',
- 'url' => $this->helper->url('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])),
+
+ $events[] = array_merge(
+ $this->getTaskCalendarProperties($task),
+ array(
+ 'start' => date('Y-m-d\TH:i:s', $task[$start_column]),
+ 'end' => date('Y-m-d\TH:i:s', $task[$end_column] ?: time()),
+ 'editable' => false,
+ )
+ );
+ }
+
+ return $events;
+ }
+
+ /**
+ * Transform results to all day calendar events
+ *
+ * @access public
+ * @param string $column Column name for the date
+ * @return array
+ */
+ public function toAllDayCalendarEvents($column = 'date_due')
+ {
+ $events = array();
+
+ foreach ($this->query->findAll() as $task) {
+
+ $events[] = array_merge(
+ $this->getTaskCalendarProperties($task),
+ array(
+ 'start' => date('Y-m-d', $task[$column]),
+ 'end' => date('Y-m-d', $task[$column]),
+ 'allday' => true,
+ )
);
}
diff --git a/app/Schema/Mysql.php b/app/Schema/Mysql.php
index 369d48266..7195c7feb 100644
--- a/app/Schema/Mysql.php
+++ b/app/Schema/Mysql.php
@@ -6,7 +6,22 @@ use PDO;
use Core\Security;
use Model\Link;
-const VERSION = 68;
+const VERSION = 69;
+
+function version_69($pdo)
+{
+ $rq = $pdo->prepare("SELECT `value` FROM `settings` WHERE `option`='subtask_forecast'");
+ $rq->execute();
+ $result = $rq->fetch(PDO::FETCH_ASSOC);
+
+ $rq = $pdo->prepare('INSERT INTO settings VALUES (?, ?)');
+ $rq->execute(array('calendar_user_subtasks_forecast', isset($result['subtask_forecast']) && $result['subtask_forecast'] == 1 ? 1 : 0));
+ $rq->execute(array('calendar_user_subtasks_time_tracking', 0));
+ $rq->execute(array('calendar_user_tasks', 'date_started'));
+ $rq->execute(array('calendar_project_tasks', 'date_started'));
+
+ $pdo->exec("DELETE FROM `settings` WHERE `option`='subtask_forecast'");
+}
function version_68($pdo)
{
@@ -20,12 +35,12 @@ function version_68($pdo)
$rq->execute(array('integration_jabber_room', ''));
$pdo->exec("ALTER TABLE project_integrations ADD COLUMN jabber INTEGER DEFAULT '0'");
- $pdo->exec("ALTER TABLE project_integrations ADD COLUMN jabber_server TEXT DEFAULT ''");
- $pdo->exec("ALTER TABLE project_integrations ADD COLUMN jabber_domain TEXT DEFAULT ''");
- $pdo->exec("ALTER TABLE project_integrations ADD COLUMN jabber_username TEXT DEFAULT ''");
- $pdo->exec("ALTER TABLE project_integrations ADD COLUMN jabber_password TEXT DEFAULT ''");
- $pdo->exec("ALTER TABLE project_integrations ADD COLUMN jabber_nickname TEXT DEFAULT 'kanboard'");
- $pdo->exec("ALTER TABLE project_integrations ADD COLUMN jabber_room TEXT DEFAULT ''");
+ $pdo->exec("ALTER TABLE project_integrations ADD COLUMN jabber_server VARCHAR(255) DEFAULT ''");
+ $pdo->exec("ALTER TABLE project_integrations ADD COLUMN jabber_domain VARCHAR(255) DEFAULT ''");
+ $pdo->exec("ALTER TABLE project_integrations ADD COLUMN jabber_username VARCHAR(255) DEFAULT ''");
+ $pdo->exec("ALTER TABLE project_integrations ADD COLUMN jabber_password VARCHAR(255) DEFAULT ''");
+ $pdo->exec("ALTER TABLE project_integrations ADD COLUMN jabber_nickname VARCHAR(255) DEFAULT 'kanboard'");
+ $pdo->exec("ALTER TABLE project_integrations ADD COLUMN jabber_room VARCHAR(255) DEFAULT ''");
}
function version_67($pdo)
diff --git a/app/Schema/Postgres.php b/app/Schema/Postgres.php
index 1cd0ab8fe..27efe8c41 100644
--- a/app/Schema/Postgres.php
+++ b/app/Schema/Postgres.php
@@ -6,7 +6,22 @@ use PDO;
use Core\Security;
use Model\Link;
-const VERSION = 49;
+const VERSION = 50;
+
+function version_50($pdo)
+{
+ $rq = $pdo->prepare("SELECT value FROM settings WHERE option='subtask_forecast'");
+ $rq->execute();
+ $result = $rq->fetch(PDO::FETCH_ASSOC);
+
+ $rq = $pdo->prepare('INSERT INTO settings VALUES (?, ?)');
+ $rq->execute(array('calendar_user_subtasks_forecast', isset($result['subtask_forecast']) && $result['subtask_forecast'] == 1 ? 1 : 0));
+ $rq->execute(array('calendar_user_subtasks_time_tracking', 0));
+ $rq->execute(array('calendar_user_tasks', 'date_started'));
+ $rq->execute(array('calendar_project_tasks', 'date_started'));
+
+ $pdo->exec("DELETE FROM settings WHERE option='subtask_forecast'");
+}
function version_49($pdo)
{
@@ -20,12 +35,12 @@ function version_49($pdo)
$rq->execute(array('integration_jabber_room', ''));
$pdo->exec("ALTER TABLE project_integrations ADD COLUMN jabber INTEGER DEFAULT '0'");
- $pdo->exec("ALTER TABLE project_integrations ADD COLUMN jabber_server TEXT DEFAULT ''");
- $pdo->exec("ALTER TABLE project_integrations ADD COLUMN jabber_domain TEXT DEFAULT ''");
- $pdo->exec("ALTER TABLE project_integrations ADD COLUMN jabber_username TEXT DEFAULT ''");
- $pdo->exec("ALTER TABLE project_integrations ADD COLUMN jabber_password TEXT DEFAULT ''");
- $pdo->exec("ALTER TABLE project_integrations ADD COLUMN jabber_nickname TEXT DEFAULT 'kanboard'");
- $pdo->exec("ALTER TABLE project_integrations ADD COLUMN jabber_room TEXT DEFAULT ''");
+ $pdo->exec("ALTER TABLE project_integrations ADD COLUMN jabber_server VARCHAR(255) DEFAULT ''");
+ $pdo->exec("ALTER TABLE project_integrations ADD COLUMN jabber_domain VARCHAR(255) DEFAULT ''");
+ $pdo->exec("ALTER TABLE project_integrations ADD COLUMN jabber_username VARCHAR(255) DEFAULT ''");
+ $pdo->exec("ALTER TABLE project_integrations ADD COLUMN jabber_password VARCHAR(255) DEFAULT ''");
+ $pdo->exec("ALTER TABLE project_integrations ADD COLUMN jabber_nickname VARCHAR(255) DEFAULT 'kanboard'");
+ $pdo->exec("ALTER TABLE project_integrations ADD COLUMN jabber_room VARCHAR(255) DEFAULT ''");
}
function version_48($pdo)
diff --git a/app/Schema/Sqlite.php b/app/Schema/Sqlite.php
index 830fd916a..7af7bbe8e 100644
--- a/app/Schema/Sqlite.php
+++ b/app/Schema/Sqlite.php
@@ -6,7 +6,22 @@ use Core\Security;
use PDO;
use Model\Link;
-const VERSION = 67;
+const VERSION = 68;
+
+function version_68($pdo)
+{
+ $rq = $pdo->prepare("SELECT value FROM settings WHERE option='subtask_forecast'");
+ $rq->execute();
+ $result = $rq->fetch(PDO::FETCH_ASSOC);
+
+ $rq = $pdo->prepare('INSERT INTO settings VALUES (?, ?)');
+ $rq->execute(array('calendar_user_subtasks_forecast', isset($result['subtask_forecast']) && $result['subtask_forecast'] == 1 ? 1 : 0));
+ $rq->execute(array('calendar_user_subtasks_time_tracking', 0));
+ $rq->execute(array('calendar_user_tasks', 'date_started'));
+ $rq->execute(array('calendar_project_tasks', 'date_started'));
+
+ $pdo->exec("DELETE FROM settings WHERE option='subtask_forecast'");
+}
function version_67($pdo)
{
diff --git a/app/Template/config/board.php b/app/Template/config/board.php
index 15e2b4226..c55003de2 100644
--- a/app/Template/config/board.php
+++ b/app/Template/config/board.php
@@ -18,18 +18,6 @@
= $this->formNumber('board_private_refresh_interval', $values, $errors) ?>
= t('Frequency in second (0 to disable this feature, 10 seconds by default)') ?>
- = $this->formLabel(t('Default columns for new projects (Comma-separated)'), 'board_columns') ?> - = $this->formText('board_columns', $values, $errors) ?>= t('Default values are "%s"', $default_columns) ?>
- - = $this->formLabel(t('Default categories for new projects (Comma-separated)'), 'project_categories') ?> - = $this->formText('project_categories', $values, $errors) ?>= t('Example: "Bug, Feature Request, Improvement"') ?>
- - = $this->formCheckbox('subtask_restriction', t('Allow only one subtask in progress at the same time for a user'), 1, $values['subtask_restriction'] == 1) ?> - = $this->formCheckbox('subtask_time_tracking', t('Enable time tracking for subtasks'), 1, $values['subtask_time_tracking'] == 1) ?> - = $this->formCheckbox('subtask_forecast', t('Show subtask estimates in the user calendar'), 1, $values['subtask_forecast'] == 1) ?> -