summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog3
-rw-r--r--app/Controller/Timetable.php39
-rw-r--r--app/Controller/Timetableday.php88
-rw-r--r--app/Controller/Timetableextra.php16
-rw-r--r--app/Controller/Timetableoff.php107
-rw-r--r--app/Controller/Timetableweek.php99
-rw-r--r--app/Core/Base.php5
-rw-r--r--app/Core/Plugin/Hook.php29
-rw-r--r--app/Core/Plugin/Loader.php2
-rw-r--r--app/Locale/cs_CZ/translations.php23
-rw-r--r--app/Locale/da_DK/translations.php23
-rw-r--r--app/Locale/de_DE/translations.php23
-rw-r--r--app/Locale/es_ES/translations.php23
-rw-r--r--app/Locale/fi_FI/translations.php23
-rw-r--r--app/Locale/fr_FR/translations.php23
-rw-r--r--app/Locale/hu_HU/translations.php23
-rw-r--r--app/Locale/id_ID/translations.php63
-rw-r--r--app/Locale/it_IT/translations.php23
-rw-r--r--app/Locale/ja_JP/translations.php23
-rwxr-xr-xapp/Locale/nb_NO/translations.php103
-rw-r--r--app/Locale/nl_NL/translations.php23
-rw-r--r--app/Locale/pl_PL/translations.php23
-rw-r--r--app/Locale/pt_BR/translations.php23
-rw-r--r--app/Locale/pt_PT/translations.php23
-rw-r--r--app/Locale/ru_RU/translations.php26
-rw-r--r--app/Locale/sr_Latn_RS/translations.php23
-rw-r--r--app/Locale/sv_SE/translations.php23
-rw-r--r--app/Locale/th_TH/translations.php23
-rw-r--r--app/Locale/tr_TR/translations.php23
-rw-r--r--app/Locale/zh_CN/translations.php23
-rw-r--r--app/Model/SubtaskTimeTracking.php38
-rw-r--r--app/Model/Timetable.php356
-rw-r--r--app/Model/TimetableDay.php87
-rw-r--r--app/Model/TimetableExtra.php22
-rw-r--r--app/Model/TimetableOff.php125
-rw-r--r--app/Model/TimetableWeek.php91
-rw-r--r--app/Schema/Mysql.php46
-rw-r--r--app/Schema/Postgres.php42
-rw-r--r--app/Schema/Sqlite.php42
-rw-r--r--app/ServiceProvider/ClassProvider.php5
-rw-r--r--app/Template/config/calendar.php8
-rw-r--r--app/Template/timetable/index.php44
-rw-r--r--app/Template/timetable_day/index.php45
-rw-r--r--app/Template/timetable_day/remove.php13
-rw-r--r--app/Template/timetable_extra/index.php56
-rw-r--r--app/Template/timetable_extra/remove.php13
-rw-r--r--app/Template/timetable_off/index.php56
-rw-r--r--app/Template/timetable_off/remove.php13
-rw-r--r--app/Template/timetable_week/index.php46
-rw-r--r--app/Template/timetable_week/remove.php13
-rw-r--r--app/Template/user/sidebar.php3
-rw-r--r--doc/budget.markdown34
-rw-r--r--doc/fr/budget.markdown34
-rw-r--r--doc/hourly-rate.markdown11
-rw-r--r--doc/index.markdown3
-rw-r--r--doc/plugins.markdown27
-rw-r--r--doc/timetable.markdown46
-rw-r--r--tests/units/Core/Plugin/HookTest.php34
-rw-r--r--tests/units/Model/TimetableTest.php256
59 files changed, 136 insertions, 2467 deletions
diff --git a/ChangeLog b/ChangeLog
index abb90de0..566f501a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -14,6 +14,7 @@ Core functionalities moved to plugins:
* Budget planning: https://github.com/kanboard/plugin-budget
* SubtaskForecast: https://github.com/kanboard/plugin-subtask-forecast
+* Timetable: https://github.com/kanboard/plugin-timetable
Improvements:
@@ -30,7 +31,7 @@ Improvements:
Bug fixes:
-* Fix typo in template that prevent the Gitlab oauth link to be displayed
+* Fix typo in template that prevent the Gitlab OAuth link to be displayed
* Fix Markdown preview links focus
* Avoid dropdown menu to be truncated inside a column with scrolling
* Deleting subtask doesn't update task time tracking
diff --git a/app/Controller/Timetable.php b/app/Controller/Timetable.php
deleted file mode 100644
index 65edb44c..00000000
--- a/app/Controller/Timetable.php
+++ /dev/null
@@ -1,39 +0,0 @@
-<?php
-
-namespace Controller;
-
-use DateTime;
-
-/**
- * Timetable controller
- *
- * @package controller
- * @author Frederic Guillot
- */
-class Timetable extends User
-{
- /**
- * Display timetable for the user
- *
- * @access public
- */
- public function index()
- {
- $user = $this->getUser();
- $from = $this->request->getStringParam('from', date('Y-m-d'));
- $to = $this->request->getStringParam('to', date('Y-m-d', strtotime('next week')));
- $timetable = $this->timetable->calculate($user['id'], new DateTime($from), new DateTime($to));
-
- $this->response->html($this->layout('timetable/index', array(
- 'user' => $user,
- 'timetable' => $timetable,
- 'values' => array(
- 'from' => $from,
- 'to' => $to,
- 'controller' => 'timetable',
- 'action' => 'index',
- 'user_id' => $user['id'],
- ),
- )));
- }
-}
diff --git a/app/Controller/Timetableday.php b/app/Controller/Timetableday.php
deleted file mode 100644
index c8f7ac8a..00000000
--- a/app/Controller/Timetableday.php
+++ /dev/null
@@ -1,88 +0,0 @@
-<?php
-
-namespace Controller;
-
-/**
- * Day Timetable controller
- *
- * @package controller
- * @author Frederic Guillot
- */
-class Timetableday extends User
-{
- /**
- * Display timetable for the user
- *
- * @access public
- */
- public function index(array $values = array(), array $errors = array())
- {
- $user = $this->getUser();
-
- $this->response->html($this->layout('timetable_day/index', array(
- 'timetable' => $this->timetableDay->getByUser($user['id']),
- 'values' => $values + array('user_id' => $user['id']),
- 'errors' => $errors,
- 'user' => $user,
- )));
- }
-
- /**
- * Validate and save
- *
- * @access public
- */
- public function save()
- {
- $values = $this->request->getValues();
- list($valid, $errors) = $this->timetableDay->validateCreation($values);
-
- if ($valid) {
-
- if ($this->timetableDay->create($values['user_id'], $values['start'], $values['end'])) {
- $this->session->flash(t('Time slot created successfully.'));
- $this->response->redirect($this->helper->url->to('timetableday', 'index', array('user_id' => $values['user_id'])));
- }
- else {
- $this->session->flashError(t('Unable to save this time slot.'));
- }
- }
-
- $this->index($values, $errors);
- }
-
- /**
- * Confirmation dialag box to remove a row
- *
- * @access public
- */
- public function confirm()
- {
- $user = $this->getUser();
-
- $this->response->html($this->layout('timetable_day/remove', array(
- 'slot_id' => $this->request->getIntegerParam('slot_id'),
- 'user' => $user,
- )));
- }
-
- /**
- * Remove a row
- *
- * @access public
- */
- public function remove()
- {
- $this->checkCSRFParam();
- $user = $this->getUser();
-
- if ($this->timetableDay->remove($this->request->getIntegerParam('slot_id'))) {
- $this->session->flash(t('Time slot removed successfully.'));
- }
- else {
- $this->session->flash(t('Unable to remove this time slot.'));
- }
-
- $this->response->redirect($this->helper->url->to('timetableday', 'index', array('user_id' => $user['id'])));
- }
-}
diff --git a/app/Controller/Timetableextra.php b/app/Controller/Timetableextra.php
deleted file mode 100644
index 7c6fe265..00000000
--- a/app/Controller/Timetableextra.php
+++ /dev/null
@@ -1,16 +0,0 @@
-<?php
-
-namespace Controller;
-
-/**
- * Over-time Timetable controller
- *
- * @package controller
- * @author Frederic Guillot
- */
-class Timetableextra extends Timetableoff
-{
- protected $model = 'timetableExtra';
- protected $controller_url = 'timetableextra';
- protected $template_dir = 'timetable_extra';
-}
diff --git a/app/Controller/Timetableoff.php b/app/Controller/Timetableoff.php
deleted file mode 100644
index 585014a3..00000000
--- a/app/Controller/Timetableoff.php
+++ /dev/null
@@ -1,107 +0,0 @@
-<?php
-
-namespace Controller;
-
-/**
- * Time-off Timetable controller
- *
- * @package controller
- * @author Frederic Guillot
- */
-class Timetableoff extends User
-{
- protected $model = 'timetableOff';
- protected $controller_url = 'timetableoff';
- protected $template_dir = 'timetable_off';
-
- /**
- * Display timetable for the user
- *
- * @access public
- */
- public function index(array $values = array(), array $errors = array())
- {
- $user = $this->getUser();
-
- $paginator = $this->paginator
- ->setUrl($this->controller_url, 'index', array('user_id' => $user['id']))
- ->setMax(10)
- ->setOrder('date')
- ->setDirection('desc')
- ->setQuery($this->{$this->model}->getUserQuery($user['id']))
- ->calculate();
-
- $this->response->html($this->layout($this->template_dir.'/index', array(
- 'values' => $values + array('user_id' => $user['id']),
- 'errors' => $errors,
- 'paginator' => $paginator,
- 'user' => $user,
- )));
- }
-
- /**
- * Validate and save
- *
- * @access public
- */
- public function save()
- {
- $values = $this->request->getValues();
- list($valid, $errors) = $this->{$this->model}->validateCreation($values);
-
- if ($valid) {
-
- if ($this->{$this->model}->create(
- $values['user_id'],
- $values['date'],
- isset($values['all_day']) && $values['all_day'] == 1,
- $values['start'],
- $values['end'],
- $values['comment'])) {
-
- $this->session->flash(t('Time slot created successfully.'));
- $this->response->redirect($this->helper->url->to($this->controller_url, 'index', array('user_id' => $values['user_id'])));
- }
- else {
- $this->session->flashError(t('Unable to save this time slot.'));
- }
- }
-
- $this->index($values, $errors);
- }
-
- /**
- * Confirmation dialag box to remove a row
- *
- * @access public
- */
- public function confirm()
- {
- $user = $this->getUser();
-
- $this->response->html($this->layout($this->template_dir.'/remove', array(
- 'slot_id' => $this->request->getIntegerParam('slot_id'),
- 'user' => $user,
- )));
- }
-
- /**
- * Remove a row
- *
- * @access public
- */
- public function remove()
- {
- $this->checkCSRFParam();
- $user = $this->getUser();
-
- if ($this->{$this->model}->remove($this->request->getIntegerParam('slot_id'))) {
- $this->session->flash(t('Time slot removed successfully.'));
- }
- else {
- $this->session->flash(t('Unable to remove this time slot.'));
- }
-
- $this->response->redirect($this->helper->url->to($this->controller_url, 'index', array('user_id' => $user['id'])));
- }
-}
diff --git a/app/Controller/Timetableweek.php b/app/Controller/Timetableweek.php
deleted file mode 100644
index b8ce00e7..00000000
--- a/app/Controller/Timetableweek.php
+++ /dev/null
@@ -1,99 +0,0 @@
-<?php
-
-namespace Controller;
-
-/**
- * Week Timetable controller
- *
- * @package controller
- * @author Frederic Guillot
- */
-class Timetableweek extends User
-{
- /**
- * Display timetable for the user
- *
- * @access public
- */
- public function index(array $values = array(), array $errors = array())
- {
- $user = $this->getUser();
-
- if (empty($values)) {
-
- $day = $this->timetableDay->getByUser($user['id']);
-
- $values = array(
- 'user_id' => $user['id'],
- 'start' => isset($day[0]['start']) ? $day[0]['start'] : null,
- 'end' => isset($day[0]['end']) ? $day[0]['end'] : null,
- );
- }
-
- $this->response->html($this->layout('timetable_week/index', array(
- 'timetable' => $this->timetableWeek->getByUser($user['id']),
- 'values' => $values,
- 'errors' => $errors,
- 'user' => $user,
- )));
- }
-
- /**
- * Validate and save
- *
- * @access public
- */
- public function save()
- {
- $values = $this->request->getValues();
- list($valid, $errors) = $this->timetableWeek->validateCreation($values);
-
- if ($valid) {
-
- if ($this->timetableWeek->create($values['user_id'], $values['day'], $values['start'], $values['end'])) {
- $this->session->flash(t('Time slot created successfully.'));
- $this->response->redirect($this->helper->url->to('timetableweek', 'index', array('user_id' => $values['user_id'])));
- }
- else {
- $this->session->flashError(t('Unable to save this time slot.'));
- }
- }
-
- $this->index($values, $errors);
- }
-
- /**
- * Confirmation dialag box to remove a row
- *
- * @access public
- */
- public function confirm()
- {
- $user = $this->getUser();
-
- $this->response->html($this->layout('timetable_week/remove', array(
- 'slot_id' => $this->request->getIntegerParam('slot_id'),
- 'user' => $user,
- )));
- }
-
- /**
- * Remove a row
- *
- * @access public
- */
- public function remove()
- {
- $this->checkCSRFParam();
- $user = $this->getUser();
-
- if ($this->timetableWeek->remove($this->request->getIntegerParam('slot_id'))) {
- $this->session->flash(t('Time slot removed successfully.'));
- }
- else {
- $this->session->flash(t('Unable to remove this time slot.'));
- }
-
- $this->response->redirect($this->helper->url->to('timetableweek', 'index', array('user_id' => $user['id'])));
- }
-}
diff --git a/app/Core/Base.php b/app/Core/Base.php
index 2dec4b29..ba925ebe 100644
--- a/app/Core/Base.php
+++ b/app/Core/Base.php
@@ -70,11 +70,6 @@ use Pimple\Container;
* @property \Model\TaskPosition $taskPosition
* @property \Model\TaskStatus $taskStatus
* @property \Model\TaskValidator $taskValidator
- * @property \Model\Timetable $timetable
- * @property \Model\TimetableDay $timetableDay
- * @property \Model\TimetableExtra $timetableExtra
- * @property \Model\TimetableOff $timetableOff
- * @property \Model\TimetableWeek $timetableWeek
* @property \Model\Transition $transition
* @property \Model\User $user
* @property \Model\UserSession $userSession
diff --git a/app/Core/Plugin/Hook.php b/app/Core/Plugin/Hook.php
index 4fb55569..fa14af13 100644
--- a/app/Core/Plugin/Hook.php
+++ b/app/Core/Plugin/Hook.php
@@ -47,6 +47,18 @@ class Hook
}
/**
+ * Return true if the hook is used
+ *
+ * @access public
+ * @param string $hook
+ * @return boolean
+ */
+ public function exists($hook)
+ {
+ return isset($this->hooks[$hook]);
+ }
+
+ /**
* Merge listener results with input array
*
* @access public
@@ -67,4 +79,21 @@ class Hook
return $values;
}
+
+ /**
+ * Execute only first listener
+ *
+ * @access public
+ * @param string $hook
+ * @param array $params
+ * @return mixed
+ */
+ public function first($hook, array $params = array())
+ {
+ foreach ($this->getListeners($hook) as $listener) {
+ return call_user_func_array($listener, $params);
+ }
+
+ return null;
+ }
}
diff --git a/app/Core/Plugin/Loader.php b/app/Core/Plugin/Loader.php
index ffead9f6..45da135b 100644
--- a/app/Core/Plugin/Loader.php
+++ b/app/Core/Plugin/Loader.php
@@ -67,7 +67,7 @@ class Loader extends \Core\Base
$filename = __DIR__.'/../../../plugins/'.$plugin.'/Schema/'.ucfirst(DB_DRIVER).'.php';
if (file_exists($filename)) {
- require($filename);
+ require_once($filename);
$this->migrateSchema($plugin);
}
}
diff --git a/app/Locale/cs_CZ/translations.php b/app/Locale/cs_CZ/translations.php
index 8cea7367..6c5cf0fb 100644
--- a/app/Locale/cs_CZ/translations.php
+++ b/app/Locale/cs_CZ/translations.php
@@ -666,28 +666,6 @@ return array(
'Compact/wide view' => 'Kompaktní/plné zobrazení',
'No results match:' => 'Žádná shoda:',
'Currency' => 'Měna',
- 'Start time' => 'Počáteční datum',
- 'End time' => 'Konečné datum',
- 'Comment' => 'Komentář',
- 'All day' => 'Všechny dny',
- 'Day' => 'Den',
- 'Manage timetable' => 'Spravovat pracovní dobu',
- 'Overtime timetable' => 'Přesčasy',
- 'Time off timetable' => 'Pracovní volno',
- 'Timetable' => 'Pracovní doba',
- 'Work timetable' => 'Pracovní doba',
- 'Week timetable' => 'Týdenní pracovní doba',
- 'Day timetable' => 'Denní pracovní doba',
- 'From' => 'Od',
- 'To' => 'Do',
- 'Time slot created successfully.' => 'Časový úsek byl úspěšně vytvořen.',
- 'Unable to save this time slot.' => 'Nelze uložit tento časový úsek.',
- 'Time slot removed successfully.' => 'Časový úsek byl odstraněn.',
- 'Unable to remove this time slot.' => 'Nelze odstranit tento časový úsek',
- 'Do you really want to remove this time slot?' => 'Opravdu chcete odstranit tento časový úsek?',
- 'Remove time slot' => 'Odstranit časový úsek',
- 'Add new time slot' => 'Přidat nový časový úsek',
- 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => 'Tato pracovní doba se použije když je zaškrtnuto políčko "Celý den" pro plánovanou pracovní dobu i přesčas .',
'Files' => 'Soubory',
'Images' => 'Obrázky',
'Private project' => 'Soukromý projekt',
@@ -707,7 +685,6 @@ return array(
'Move the task to another column when assigned to a user' => 'Přesunout úkol do jiného sloupce, když je úkol přiřazen uživateli.',
'Move the task to another column when assignee is cleared' => 'Přesunout úkol do jiného sloupce, když je pověření uživatele vymazáno.',
'Source column' => 'Zdrojový sloupec',
- // 'Show subtask estimates (forecast of future work)' => '',
'Transitions' => 'Změny etap',
'Executer' => 'Vykonavatel',
'Time spent in the column' => 'Trvání jednotlivých etap',
diff --git a/app/Locale/da_DK/translations.php b/app/Locale/da_DK/translations.php
index 027b22c5..d0fa1a18 100644
--- a/app/Locale/da_DK/translations.php
+++ b/app/Locale/da_DK/translations.php
@@ -666,28 +666,6 @@ return array(
// 'Compact/wide view' => '',
// 'No results match:' => '',
// 'Currency' => '',
- // 'Start time' => '',
- // 'End time' => '',
- // 'Comment' => '',
- // 'All day' => '',
- // 'Day' => '',
- // 'Manage timetable' => '',
- // 'Overtime timetable' => '',
- // 'Time off timetable' => '',
- // 'Timetable' => '',
- // 'Work timetable' => '',
- // 'Week timetable' => '',
- // 'Day timetable' => '',
- // 'From' => '',
- // 'To' => '',
- // 'Time slot created successfully.' => '',
- // 'Unable to save this time slot.' => '',
- // 'Time slot removed successfully.' => '',
- // 'Unable to remove this time slot.' => '',
- // 'Do you really want to remove this time slot?' => '',
- // 'Remove time slot' => '',
- // 'Add new time slot' => '',
- // 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => '',
// 'Files' => '',
// 'Images' => '',
// 'Private project' => '',
@@ -707,7 +685,6 @@ 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 (forecast of future work)' => '',
// 'Transitions' => '',
// 'Executer' => '',
// 'Time spent in the column' => '',
diff --git a/app/Locale/de_DE/translations.php b/app/Locale/de_DE/translations.php
index 0b1df2e7..71a1d7eb 100644
--- a/app/Locale/de_DE/translations.php
+++ b/app/Locale/de_DE/translations.php
@@ -666,28 +666,6 @@ return array(
'Compact/wide view' => 'Kompakt/Breite-Ansicht',
'No results match:' => 'Keine Ergebnisse:',
'Currency' => 'Währung',
- 'Start time' => 'Startzeit',
- 'End time' => 'Endzeit',
- 'Comment' => 'Kommentar',
- 'All day' => 'ganztägig',
- 'Day' => 'Tag',
- 'Manage timetable' => 'Zeitplan verwalten',
- 'Overtime timetable' => 'Überstunden Zeitplan',
- 'Time off timetable' => 'Freizeit Zeitplan',
- 'Timetable' => 'Zeitplan',
- 'Work timetable' => 'Arbeitszeitplan',
- 'Week timetable' => 'Wochenzeitplan',
- 'Day timetable' => 'Tageszeitplan',
- 'From' => 'von',
- 'To' => 'bis',
- 'Time slot created successfully.' => 'Zeitfenster erfolgreich erstellt.',
- 'Unable to save this time slot.' => 'Nicht in der Lage, dieses Zeitfenster zu speichern.',
- 'Time slot removed successfully.' => 'Zeitfenster erfolgreich entfernt.',
- 'Unable to remove this time slot.' => 'Nicht in der Lage, dieses Zeitfenster zu entfernen',
- 'Do you really want to remove this time slot?' => 'Soll diese Zeitfenster wirklich gelöscht werden?',
- 'Remove time slot' => 'Zeitfenster entfernen',
- 'Add new time slot' => 'Neues Zeitfenster hinzufügen',
- 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => 'Dieses Zeitfenster wird verwendet, wenn die Checkbox "ganztägig" für Freizeit und Überstunden angeklickt ist.',
'Files' => 'Dateien',
'Images' => 'Bilder',
'Private project' => 'privates Projekt',
@@ -707,7 +685,6 @@ 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 (forecast of future work)' => 'Teilaufgaben-Schätzungen anzeigen (Prognose)',
'Transitions' => 'Übergänge',
'Executer' => 'Ausführender',
'Time spent in the column' => 'Zeit in Spalte verbracht',
diff --git a/app/Locale/es_ES/translations.php b/app/Locale/es_ES/translations.php
index 1e15d8c0..3a80d2fb 100644
--- a/app/Locale/es_ES/translations.php
+++ b/app/Locale/es_ES/translations.php
@@ -666,28 +666,6 @@ return array(
'Compact/wide view' => 'Vista compacta/amplia',
'No results match:' => 'No hay resultados coincidentes:',
'Currency' => 'Moneda',
- 'Start time' => 'Tiempo de inicio',
- 'End time' => 'Tiempo de fin',
- 'Comment' => 'Comentario',
- 'All day' => 'Todos los días',
- 'Day' => 'Día',
- 'Manage timetable' => 'Gestionar horario',
- 'Overtime timetable' => 'Horario de tiempo extra',
- 'Time off timetable' => 'Horario de tiempo libre',
- 'Timetable' => 'Horario',
- 'Work timetable' => 'Horario de trabajo',
- 'Week timetable' => 'Horario semanal',
- 'Day timetable' => 'Horario diario',
- 'From' => 'De',
- 'To' => 'Para',
- 'Time slot created successfully.' => 'Intervalo de tiempo creado correctamente.',
- 'Unable to save this time slot.' => 'No pude grabar este intervalo de tiempo.',
- 'Time slot removed successfully.' => 'Intervalo de tiempo quitado correctamente.',
- 'Unable to remove this time slot.' => 'No pude quitar este intervalo de tiempo.',
- 'Do you really want to remove this time slot?' => '¿Realmente quiere quitar este intervalo de tiempo?',
- 'Remove time slot' => 'Quitar intervalo de tiempo',
- 'Add new time slot' => 'Añadir nuevo intervalo de tiempo',
- 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => 'Este horario se usa cuando se marca la casilla "todos los días" para calendario de tiempo libre y horas extras.',
'Files' => 'Ficheros',
'Images' => 'Imágenes',
'Private project' => 'Proyecto privado',
@@ -707,7 +685,6 @@ 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 concesionario',
'Source column' => 'Columna fuente',
- 'Show subtask estimates (forecast of future work)' => 'Mostrar estimaciones para la subtarea (pronóstico de trabajo futuro)',
'Transitions' => 'Transiciones',
'Executer' => 'Ejecutor',
'Time spent in the column' => 'Tiempo transcurrido en la columna',
diff --git a/app/Locale/fi_FI/translations.php b/app/Locale/fi_FI/translations.php
index da462831..e8940ba9 100644
--- a/app/Locale/fi_FI/translations.php
+++ b/app/Locale/fi_FI/translations.php
@@ -666,28 +666,6 @@ return array(
// 'Compact/wide view' => '',
// 'No results match:' => '',
// 'Currency' => '',
- // 'Start time' => '',
- // 'End time' => '',
- // 'Comment' => '',
- // 'All day' => '',
- // 'Day' => '',
- // 'Manage timetable' => '',
- // 'Overtime timetable' => '',
- // 'Time off timetable' => '',
- // 'Timetable' => '',
- // 'Work timetable' => '',
- // 'Week timetable' => '',
- // 'Day timetable' => '',
- // 'From' => '',
- // 'To' => '',
- // 'Time slot created successfully.' => '',
- // 'Unable to save this time slot.' => '',
- // 'Time slot removed successfully.' => '',
- // 'Unable to remove this time slot.' => '',
- // 'Do you really want to remove this time slot?' => '',
- // 'Remove time slot' => '',
- // 'Add new time slot' => '',
- // 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => '',
// 'Files' => '',
// 'Images' => '',
// 'Private project' => '',
@@ -707,7 +685,6 @@ 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 (forecast of future work)' => '',
// 'Transitions' => '',
// 'Executer' => '',
// 'Time spent in the column' => '',
diff --git a/app/Locale/fr_FR/translations.php b/app/Locale/fr_FR/translations.php
index 848b7624..4c149b9a 100644
--- a/app/Locale/fr_FR/translations.php
+++ b/app/Locale/fr_FR/translations.php
@@ -668,28 +668,6 @@ return array(
'Compact/wide view' => 'Basculer entre la vue compacte et étendue',
'No results match:' => 'Aucun résultat :',
'Currency' => 'Devise',
- 'Start time' => 'Date de début',
- 'End time' => 'Date de fin',
- 'Comment' => 'Commentaire',
- 'All day' => 'Toute la journée',
- 'Day' => 'Jour',
- 'Manage timetable' => 'Gérer les horaires',
- 'Overtime timetable' => 'Heures supplémentaires',
- 'Time off timetable' => 'Heures d\'absences',
- 'Timetable' => 'Horaires',
- 'Work timetable' => 'Horaires travaillés',
- 'Week timetable' => 'Horaires de la semaine',
- 'Day timetable' => 'Horaire d\'une journée',
- 'From' => 'Depuis',
- 'To' => 'À',
- 'Time slot created successfully.' => 'Créneau horaire créé avec succès.',
- 'Unable to save this time slot.' => 'Impossible de sauvegarder ce créneau horaire.',
- 'Time slot removed successfully.' => 'Créneau horaire supprimé avec succès.',
- 'Unable to remove this time slot.' => 'Impossible de supprimer ce créneau horaire.',
- 'Do you really want to remove this time slot?' => 'Voulez-vous vraiment supprimer ce créneau horaire ?',
- 'Remove time slot' => 'Supprimer un créneau horaire',
- 'Add new time slot' => 'Ajouter un créneau horaire',
- 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => 'Ces horaires sont utilisés lorsque la case « Toute la journée » est cochée pour les heures d\'absences ou supplémentaires programmées.',
'Files' => 'Fichiers',
'Images' => 'Images',
'Private project' => 'Projet privé',
@@ -709,7 +687,6 @@ 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 (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',
diff --git a/app/Locale/hu_HU/translations.php b/app/Locale/hu_HU/translations.php
index a3bbd8f5..0bb99954 100644
--- a/app/Locale/hu_HU/translations.php
+++ b/app/Locale/hu_HU/translations.php
@@ -666,28 +666,6 @@ return array(
'Compact/wide view' => 'Kompakt/széles nézet',
'No results match:' => 'Nincs találat:',
'Currency' => 'Pénznem',
- 'Start time' => 'Kezdés ideje',
- 'End time' => 'Végzés ideje',
- 'Comment' => 'Megjegyzés',
- 'All day' => 'Egész nap',
- 'Day' => 'Nap',
- 'Manage timetable' => 'Időbeosztás kezelése',
- 'Overtime timetable' => 'Túlóra időbeosztás',
- 'Time off timetable' => 'Szabadság időbeosztás',
- 'Timetable' => 'Időbeosztás',
- 'Work timetable' => 'Munka időbeosztás',
- 'Week timetable' => 'Heti időbeosztás',
- 'Day timetable' => 'Napi időbeosztás',
- 'From' => 'Feladó:',
- 'To' => 'Címzett:',
- 'Time slot created successfully.' => 'Időszelet sikeresen létrehozva.',
- 'Unable to save this time slot.' => 'Időszelet mentése sikertelen.',
- 'Time slot removed successfully.' => 'Időszelet sikeresen törölve.',
- 'Unable to remove this time slot.' => 'Időszelet törlése sikertelen.',
- 'Do you really want to remove this time slot?' => 'Biztos törli ezt az időszeletet?',
- 'Remove time slot' => 'Időszelet törlése',
- 'Add new time slot' => 'Új Időszelet',
- 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => 'Ez az időbeosztás van használatban ha az "egész nap" jelölőnégyzet be van jelölve a tervezett szabadságnál és túlóránál.',
'Files' => 'Fájlok',
'Images' => 'Képek',
'Private project' => 'Privát projekt',
@@ -707,7 +685,6 @@ 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 (forecast of future work)' => '',
// 'Transitions' => '',
// 'Executer' => '',
// 'Time spent in the column' => '',
diff --git a/app/Locale/id_ID/translations.php b/app/Locale/id_ID/translations.php
index a7b52c6f..1945e60b 100644
--- a/app/Locale/id_ID/translations.php
+++ b/app/Locale/id_ID/translations.php
@@ -25,7 +25,7 @@ return array(
'Dark Grey' => 'Abu-abu Gelap',
'Pink' => 'Merah Muda',
'Teal' => 'Teal',
- 'Cyan'=> 'Sian',
+ 'Cyan' => 'Sian',
'Lime' => 'Lime',
'Light Green' => 'Hijau Muda',
'Amber' => 'Amber',
@@ -338,7 +338,7 @@ return array(
'Display another project' => 'Lihat proyek lain',
'Login with my Github Account' => 'Masuk menggunakan akun Github saya',
'Link my Github Account' => 'Hubungkan akun Github saya ',
- 'Unlink my Github Account' => 'Putuskan akun Github saya',
+ 'Unlink my Github Account' => 'Putuskan akun Github saya',
'Created by %s' => 'Dibuat oleh %s',
'Last modified on %B %e, %Y at %k:%M %p' => 'Modifikasi terakhir pada tanggal %d/%m/%Y à %H:%M',
'Tasks Export' => 'Ekspor Tugas',
@@ -365,14 +365,12 @@ return array(
'Time tracking:' => 'Pelacakan waktu :',
'New sub-task' => 'Sub-tugas baru',
'New attachment added "%s"' => 'Lampiran baru ditambahkan « %s »',
- 'Comment updated' => 'Komentar ditambahkan',
+ 'Comment updated' => 'Komentar diperbaharui',
'New comment posted by %s' => 'Komentar baru ditambahkan oleh « %s »',
'New attachment' => 'Lampirkan baru',
'New comment' => 'Komentar baru',
- 'Comment updated' => 'Komentar diperbaharui',
'New subtask' => 'Sub-tugas baru',
'Subtask updated' => 'Sub-tugas diperbaharui',
- 'New task' => 'Tugas baru',
'Task updated' => 'Tugas diperbaharui',
'Task closed' => 'Tugas ditutup',
'Task opened' => 'Tugas dibuka',
@@ -397,8 +395,6 @@ return array(
'Remote' => 'Jauh',
'Enabled' => 'Aktif',
'Disabled' => 'Nonaktif',
- 'Google account linked' => 'Akun Google yang terhubung',
- 'Github account linked' => 'Akun Github yang terhubung',
'Username:' => 'Nama pengguna :',
'Name:' => 'Nama :',
'Email:' => 'Email :',
@@ -669,75 +665,26 @@ return array(
'Horizontal scrolling' => 'Horisontal bergulir',
'Compact/wide view' => 'Beralih antara tampilan kompak dan diperluas',
'No results match:' => 'Tidak ada hasil :',
- 'Remove hourly rate' => 'Hapus tarif per jam',
- 'Do you really want to remove this hourly rate?' => 'Apakah anda yakin akan menghapus tarif per jam ini?',
- 'Hourly rates' => 'Tarif per jam',
- 'Hourly rate' => 'Tarif per jam',
'Currency' => 'Mata uang',
- 'Effective date' => 'Tanggal berlaku',
- 'Add new rate' => 'Tambah tarif per jam baru',
- 'Rate removed successfully.' => 'Tarif per jam berhasil dihapus.',
- 'Unable to remove this rate.' => 'Tidak dapat menghapus tarif per jam ini.',
- 'Unable to save the hourly rate.' => 'Tidak dapat menyimpan tarif per jam.',
- 'Hourly rate created successfully.' => 'Tarif per jam berhasil dibuat.',
- 'Start time' => 'Waktu mulai',
- 'End time' => 'Waktu selesai',
- 'Comment' => 'Komentar',
- 'All day' => 'Semua hari',
- 'Day' => 'Hari',
- 'Manage timetable' => 'Mengatur jadwal',
- 'Overtime timetable' => 'Jadwal lembur',
- 'Time off timetable' => 'Jam absensi',
- 'Timetable' => 'Jadwal',
- 'Work timetable' => 'Jadwal kerja',
- 'Week timetable' => 'Jadwal mingguan',
- 'Day timetable' => 'Jadwal harian',
- 'From' => 'Dari',
- 'To' => 'Untuk',
- 'Time slot created successfully.' => 'Slot waktu berhasil dibuat.',
- 'Unable to save this time slot.' => 'Tidak dapat menyimpan slot waktu ini.',
- 'Time slot removed successfully.' => 'Slot waktu berhasil dihapus.',
- 'Unable to remove this time slot.' => 'Tidak dapat menghapus slot waktu ini.',
- 'Do you really want to remove this time slot?' => 'Apakah anda yakin akan menghapus slot waktu ini?',
- 'Remove time slot' => 'Hapus slot waktu',
- 'Add new time slot' => 'Tambah slot waktu baru',
- 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => 'Jadwal ini digunakan ketika kotak centang "sepanjang hari" dicentang untuk dijadwalkan cuti dan lembur.',
'Files' => 'Arsip',
'Images' => 'Gambar',
'Private project' => 'Proyek pribadi',
- 'Amount' => 'Jumlah',
'AUD - Australian Dollar' => 'AUD - Dollar Australia',
- 'Budget' => 'Anggaran',
- 'Budget line' => 'Garis anggaran',
- 'Budget line removed successfully.' => 'Garis anggaran berhasil dihapus.',
- 'Budget lines' => 'Garis anggaran',
'CAD - Canadian Dollar' => 'CAD - Dollar Kanada',
'CHF - Swiss Francs' => 'CHF - Swiss Prancis',
- 'Cost' => 'Biaya',
- 'Cost breakdown' => 'Rincian biaya',
'Custom Stylesheet' => 'Kustomisasi Stylesheet',
'download' => 'unduh',
- 'Do you really want to remove this budget line?' => 'Apakah anda yakin akan menghapus garis anggaran ini?',
'EUR - Euro' => 'EUR - Euro',
- 'Expenses' => 'Beban',
'GBP - British Pound' => 'GBP - Poundsterling inggris',
'INR - Indian Rupee' => 'INR - Rupe India',
'JPY - Japanese Yen' => 'JPY - Yen Jepang',
- 'New budget line' => 'Garis anggaran baru',
'NZD - New Zealand Dollar' => 'NZD - Dollar Selandia baru',
- 'Remove a budget line' => 'Hapus garis anggaran',
- 'Remove budget line' => 'Hapus garis anggaran',
'RSD - Serbian dinar' => 'RSD - Dinar Serbia',
- 'The budget line have been created successfully.' => 'Garis anggaran berhasil dibuat.',
- 'Unable to create the budget line.' => 'Tidak dapat membuat garis anggaran.',
- 'Unable to remove this budget line.' => 'Tidak dapat menghapus garis anggaran.',
'USD - US Dollar' => 'USD - Dollar Amerika',
- 'Remaining' => 'Sisa',
'Destination column' => 'Kolom tujuan',
'Move the task to another column when assigned to a user' => 'Pindahkan tugas ke kolom lain ketika ditugaskan ke pengguna',
'Move the task to another column when assignee is cleared' => 'Pindahkan tugas ke kolom lain ketika orang yang ditugaskan dibersihkan',
'Source column' => 'Sumber kolom',
- 'Show subtask estimates (forecast of future work)' => 'Lihat perkiraan subtugas(perkiraan di masa depan)',
'Transitions' => 'Transisi',
'Executer' => 'Eksekusi',
'Time spent in the column' => 'Waktu yang dihabiskan dalam kolom',
@@ -748,7 +695,6 @@ return array(
'Rate' => 'Tarif',
'Change reference currency' => 'Mengubah referensi mata uang',
'Add a new currency rate' => 'Tambahkan nilai tukar mata uang baru',
- 'Currency rates are used to calculate project budget.' => 'Nilai tukar mata uang digunakan untuk menghitung anggaran proyek.',
'Reference currency' => 'Referensi mata uang',
'The currency rate have been added successfully.' => 'Nilai tukar mata uang berhasil ditambahkan.',
'Unable to add this currency rate.' => 'Tidak dapat menambahkan nilai tukar mata uang',
@@ -880,9 +826,6 @@ return array(
'%s moved the task #%d to the first swimlane' => '%s memindahkan tugas n°%d ke swimlane pertama',
'%s moved the task #%d to the swimlane "%s"' => '%s memindahkan tugas n°%d ke swimlane « %s »',
'Swimlane' => 'Swimlane',
- 'Budget overview' => 'Gambaran anggaran',
- 'Type' => 'Tipe',
- 'There is not enough data to show something.' => 'Tidak ada data yang cukup untuk menunjukkan sesuatu.',
'Gravatar' => 'Gravatar',
'Hipchat' => 'Hipchat',
'Slack' => 'Slack',
diff --git a/app/Locale/it_IT/translations.php b/app/Locale/it_IT/translations.php
index e27245f9..5d6d33f6 100644
--- a/app/Locale/it_IT/translations.php
+++ b/app/Locale/it_IT/translations.php
@@ -666,28 +666,6 @@ return array(
'Compact/wide view' => 'Vista compatta/estesa',
'No results match:' => 'Nessun risultato trovato:',
'Currency' => 'Valuta',
- 'Start time' => 'Data di inizio',
- 'End time' => 'Data di completamento',
- 'Comment' => 'Commento',
- 'All day' => 'Tutto il giorno',
- 'Day' => 'Giorno',
- 'Manage timetable' => 'Gestisci orario',
- 'Overtime timetable' => 'Straordinari',
- 'Time off timetable' => 'Fuori orario',
- 'Timetable' => 'Orario',
- 'Work timetable' => 'Orario di lavoro',
- 'Week timetable' => 'Orario settimanale',
- 'Day timetable' => 'Orario giornaliero',
- 'From' => 'Da',
- 'To' => 'A',
- 'Time slot created successfully.' => 'Fascia oraria creata con successo.',
- 'Unable to save this time slot.' => 'Impossibile creare questa fascia oraria.',
- 'Time slot removed successfully.' => 'Fascia oraria rimossa con successo.',
- 'Unable to remove this time slot.' => 'Impossibile rimuovere questa fascia oraria.',
- 'Do you really want to remove this time slot?' => 'Vuoi davvero rimuovere questa fascia oraria?',
- 'Remove time slot' => 'Rimuovi fascia oraria',
- 'Add new time slot' => 'Aggiungi nuova fascia oraria',
- 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => 'Questo orario è utilizzato quando la casella "tutto il giorno" è selezionata per i fuori orari e per gli straordinari',
// 'Files' => '',
'Images' => 'Immagini',
'Private project' => 'Progetto privato',
@@ -707,7 +685,6 @@ 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 (forecast of future work)' => '',
'Transitions' => 'Transizioni',
'Executer' => 'Esecutore',
'Time spent in the column' => 'Tempo trascorso nella colonna',
diff --git a/app/Locale/ja_JP/translations.php b/app/Locale/ja_JP/translations.php
index 49f92f27..b46ec1c4 100644
--- a/app/Locale/ja_JP/translations.php
+++ b/app/Locale/ja_JP/translations.php
@@ -666,28 +666,6 @@ return array(
'Compact/wide view' => 'コンパクト/ワイドビュー',
'No results match:' => '結果が一致しませんでした',
'Currency' => '通貨',
- 'Start time' => '開始時間',
- 'End time' => '終了時間',
- 'Comment' => 'コメント',
- 'All day' => '終日',
- 'Day' => '日',
- 'Manage timetable' => 'タイムテーブルの管理',
- 'Overtime timetable' => '残業タイムテーブル',
- 'Time off timetable' => '休暇タイムテーブル',
- 'Timetable' => 'タイムテーブル',
- 'Work timetable' => 'ワークタイムテーブル',
- 'Week timetable' => '週次タイムテーブル',
- 'Day timetable' => '日時タイムテーブル',
- 'From' => 'ここから',
- 'To' => 'ここまで',
- // 'Time slot created successfully.' => '',
- // 'Unable to save this time slot.' => '',
- // 'Time slot removed successfully.' => '',
- // 'Unable to remove this time slot.' => '',
- // 'Do you really want to remove this time slot?' => '',
- 'Remove time slot' => 'タイムスロットの削除',
- 'Add new time slot' => 'タイムラインの追加',
- 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => 'このタイムテーブルは、残業や休暇で全日がチェックされた場合に用いられます。',
'Files' => 'ファイル',
'Images' => '画像',
'Private project' => 'プライベートプロジェクト',
@@ -707,7 +685,6 @@ 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 (forecast of future work)' => '',
'Transitions' => '履歴',
'Executer' => '実行者',
'Time spent in the column' => 'カラムでの時間消費',
diff --git a/app/Locale/nb_NO/translations.php b/app/Locale/nb_NO/translations.php
index 9880b921..8ee800e6 100755
--- a/app/Locale/nb_NO/translations.php
+++ b/app/Locale/nb_NO/translations.php
@@ -126,7 +126,6 @@ return array(
'The project name is required' => 'Prosjektnavn er pkrevet',
'This project must be unique' => 'Prosjektnavnet skal vre unikt',
'The title is required' => 'Tittel er prevet',
- 'There is no active project, the first step is to create a new project.' => 'Det er ingen aktive prosjekter. Frstesteg er opprette et nytt prosjekt.',
'Settings saved successfully.' => 'Innstillinger lagret.',
'Unable to save your settings.' => 'Innstillinger kunne ikke lagres.',
'Database optimization done.' => 'Databaseoptimering er fullfrt.',
@@ -165,8 +164,6 @@ return array(
'Date created' => 'Dato for opprettelse',
'Date completed' => 'Dato for fullfrt',
'Id' => 'ID',
- 'Completed tasks' => 'Fullfrte oppgaver',
- 'Completed tasks for "%s"' => 'Fullfrte oppgaver for "%s"',
'%d closed tasks' => '%d lukkede oppgaver',
'No task for this project' => 'Ingen oppgaver i dette prosjektet',
'Public link' => 'Offentligt lenke',
@@ -255,25 +252,21 @@ return array(
'Expiration date' => 'Utlpsdato',
'Remember Me' => 'Husk meg',
'Creation date' => 'Opprettelsesdato',
- 'Filter by user' => 'Filtrer efter bruker',
- 'Filter by due date' => 'Filtrer etter forfallsdato',
'Everybody' => 'Alle',
'Open' => 'pen',
'Closed' => 'Lukket',
'Search' => 'Sk',
'Nothing found.' => 'Intet funnet.',
- 'Search in the project "%s"' => 'Sk i prosjektet "%s"',
'Due date' => 'Forfallsdato',
'Others formats accepted: %s and %s' => 'Andre formater: %s og %s',
'Description' => 'Beskrivelse',
'%d comments' => '%d kommentarer',
'%d comment' => '%d kommentar',
'Email address invalid' => 'Ugyldig epost',
- 'Your Google Account is not linked anymore to your profile.' => 'Din Google-konto er ikke lengre knyttet til din profil.',
- 'Unable to unlink your Google Account.' => 'Det var ikke mulig fjerne din Google-konto.',
- 'Google authentication failed' => 'Google godjenning mislyktes',
- 'Unable to link your Google Account.' => 'Det var ikke mulig knytte opp til din Google-konto.',
- 'Your Google Account is linked to your profile successfully.' => 'Din Google-konto er knyttet til din profil.',
+ // 'Your external account is not linked anymore to your profile.' => '',
+ // 'Unable to unlink your external account.' => '',
+ // 'External authentication failed' => '',
+ // 'Your external account is linked to your profile successfully.' => '',
'Email' => 'Epost',
'Link my Google Account' => 'Knytt til min Google-konto',
'Unlink my Google Account' => 'Fjern knytningen til min Google-konto',
@@ -301,7 +294,6 @@ return array(
'Category Name' => 'Kategorinavn',
'Add a new category' => 'Legg til ny kategori',
'Do you really want to remove this category: "%s"?' => 'Vil du fjerne kategorien: "%s"?',
- 'Filter by category' => 'Filter etter kategori',
'All categories' => 'Alle kategorier',
'No category' => 'Ingen kategori',
'The name is required' => 'Navnet er pkrevet',
@@ -344,14 +336,9 @@ return array(
'Maximum size: ' => 'Maksimum strrelse: ',
'Unable to upload the file.' => 'Filen kunne ikke lastes opp.',
'Display another project' => 'Vis annet prosjekt...',
- 'Your GitHub account was successfully linked to your profile.' => 'Din GitHub-konto er knyttet til din profil.',
- 'Unable to link your GitHub Account.' => 'Det var ikke mulig knytte din GitHub-konto.',
- 'GitHub authentication failed' => 'GitHub godkjenning mislyktes',
- 'Your GitHub account is no longer linked to your profile.' => 'Din GitHub-konto er ikke lengere knyttet til din profil.',
- 'Unable to unlink your GitHub Account.' => 'Det var ikke muligt at fjerne forbindelsen til din GitHub-konto.',
- 'Login with my GitHub Account' => 'Login med min GitHub-konto',
- 'Link my GitHub Account' => 'Knytt min GitHub-konto',
- 'Unlink my GitHub Account' => 'Fjern knytningen til min GitHub-konto',
+ // 'Login with my Github Account' => '',
+ // 'Link my Github Account' => '',
+ // 'Unlink my Github Account' => '',
'Created by %s' => 'Opprettet av %s',
'Last modified on %B %e, %Y at %k:%M %p' => 'Sist endret %d.%m.%Y - %H:%M',
'Tasks Export' => 'Oppgave eksport',
@@ -408,8 +395,6 @@ return array(
'Remote' => 'Fjernstyrt',
'Enabled' => 'Aktiv',
'Disabled' => 'Deaktivert',
- 'Google account linked' => 'Google-konto knyttet',
- 'Github account linked' => 'GitHub-konto knyttet',
'Username:' => 'Brukernavn',
'Name:' => 'Navn:',
'Email:' => 'Epost:',
@@ -445,7 +430,6 @@ return array(
'%s updated a comment on the task %s' => '%s oppdaterte en kommentar til oppgaven %s',
'%s commented the task %s' => '%s har kommentert oppgaven %s',
'%s\'s activity' => '%s\'s aktvitet',
- 'No activity.' => 'Ingen aktivitet',
'RSS feed' => 'RSS feed',
'%s updated a comment on the task #%d' => '%s oppdaterte en kommentar til oppgaven #%d',
'%s commented on the task #%d' => '%s kommenterte oppgaven #%d',
@@ -605,14 +589,9 @@ return array(
'Language:' => 'Sprk',
'Timezone:' => 'Tidssone',
'All columns' => 'Alle kolonner',
- 'Calendar for "%s"' => 'Kalender for "%s"',
- 'Filter by column' => 'Filtrer etter kolonne',
- 'Filter by status' => 'Filtrer etter status',
'Calendar' => 'Kalender',
'Next' => 'Neste',
// '#%d' => '',
- 'Filter by color' => 'Filtrer etter farge',
- 'Filter by swimlane' => 'Filtrer etter svmmebane',
'All swimlanes' => 'Alle svmmebaner',
'All colors' => 'Alle farger',
'All status' => 'Alle statuser',
@@ -627,14 +606,7 @@ return array(
// 'Time Tracking' => '',
// 'You already have one subtask in progress' => '',
'Which parts of the project do you want to duplicate?' => 'Hvilke deler av dette prosjektet nsker du kopiere?',
- 'Change dashboard view' => 'Endre visning',
- 'Show/hide activities' => 'Vis/skjul aktiviteter',
- 'Show/hide projects' => 'Vis/skjul prosjekter',
- 'Show/hide subtasks' => 'Vis/skjul deloppgaver',
- 'Show/hide tasks' => 'Vis/skjul oppgaver',
- 'Disable login form' => 'Deaktiver innlogging',
- 'Show/hide calendar' => 'Vis/skjul kalender',
- 'User calendar' => 'Brukerens kalender',
+ // 'Disallow login form' => '',
// 'Bitbucket commit received' => '',
// 'Bitbucket webhooks' => '',
// 'Help on Bitbucket webhooks' => '',
@@ -688,82 +660,31 @@ return array(
'Keyboard shortcuts' => 'Hurtigtaster',
// 'Open board switcher' => '',
// 'Application' => '',
- 'Filter recently updated' => 'Filter nylig oppdatert',
'since %B %e, %Y at %k:%M %p' => 'siden %B %e, %Y at %k:%M %p',
- 'More filters' => 'Flere filtre',
'Compact view' => 'Kompakt visning',
'Horizontal scrolling' => 'Bla horisontalt',
'Compact/wide view' => 'Kompakt/bred visning',
'No results match:' => 'Ingen resultater',
- // 'Remove hourly rate' => '',
- // 'Do you really want to remove this hourly rate?' => '',
- 'Hourly rates' => 'Timepriser',
- 'Hourly rate' => 'Timepris',
'Currency' => 'Valuta',
- // 'Effective date' => '',
- // 'Add new rate' => '',
- // 'Rate removed successfully.' => '',
- // 'Unable to remove this rate.' => '',
- // 'Unable to save the hourly rate.' => '',
- // 'Hourly rate created successfully.' => '',
- // 'Start time' => '',
- // 'End time' => '',
- 'Comment' => 'Kommentar',
- 'All day' => 'Alle dager',
- 'Day' => 'Dag',
- 'Manage timetable' => 'Tidstabell',
- 'Overtime timetable' => 'Overtidstabell',
- 'Time off timetable' => 'Fritidstabell',
- 'Timetable' => 'Tidstabell',
- 'Work timetable' => 'Arbeidstidstabell',
- 'Week timetable' => 'Uketidstabell',
- 'Day timetable' => 'Dagtidstabell',
- 'From' => 'Fra',
- 'To' => 'Til',
- // 'Time slot created successfully.' => '',
- // 'Unable to save this time slot.' => '',
- // 'Time slot removed successfully.' => '',
- // 'Unable to remove this time slot.' => '',
- // 'Do you really want to remove this time slot?' => '',
- // 'Remove time slot' => '',
- // 'Add new time slot' => '',
- // 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => '',
'Files' => 'Filer',
'Images' => 'Bilder',
'Private project' => 'Privat prosjekt',
- 'Amount' => 'Belp',
// 'AUD - Australian Dollar' => '',
- 'Budget' => 'Budsjett',
- // 'Budget line' => '',
- // 'Budget line removed successfully.' => '',
- 'Budget lines' => 'Budsjettlinjer',
// 'CAD - Canadian Dollar' => '',
// 'CHF - Swiss Francs' => '',
- 'Cost' => 'Kostnad',
- 'Cost breakdown' => 'Kostnadsnedbryting',
// 'Custom Stylesheet' => '',
'download' => 'last ned',
- // 'Do you really want to remove this budget line?' => '',
// 'EUR - Euro' => '',
- // 'Expenses' => '',
// 'GBP - British Pound' => '',
// 'INR - Indian Rupee' => '',
// 'JPY - Japanese Yen' => '',
- // 'New budget line' => '',
// 'NZD - New Zealand Dollar' => '',
- // 'Remove a budget line' => '',
- // 'Remove budget line' => '',
// 'RSD - Serbian dinar' => '',
- // 'The budget line have been created successfully.' => '',
- // 'Unable to create the budget line.' => '',
- // 'Unable to remove this budget line.' => '',
// 'USD - US Dollar' => '',
- // 'Remaining' => '',
'Destination column' => 'Ny kolonne',
'Move the task to another column when assigned to a user' => 'Flytt oppgaven til en annen kolonne nr den er tildelt en bruker',
'Move the task to another column when assignee is cleared' => 'Flytt oppgaven til en annen kolonne nr ppgavetildeling fjernes ',
'Source column' => 'Opprinnelig kolonne',
- // 'Show subtask estimates (forecast of future work)' => '',
'Transitions' => 'Statusendringer',
// 'Executer' => '',
// 'Time spent in the column' => '',
@@ -774,7 +695,6 @@ return array(
// 'Rate' => '',
// 'Change reference currency' => '',
// 'Add a new currency rate' => '',
- // 'Currency rates are used to calculate project budget.' => '',
// 'Reference currency' => '',
// 'The currency rate have been added successfully.' => '',
// 'Unable to add this currency rate.' => '',
@@ -906,9 +826,6 @@ return array(
// '%s moved the task #%d to the first swimlane' => '',
// '%s moved the task #%d to the swimlane "%s"' => '',
'Swimlane' => 'Svmmebane',
- 'Budget overview' => 'Budsjettoversikt',
- // 'Type' => '',
- // 'There is not enough data to show something.' => '',
// 'Gravatar' => '',
// 'Hipchat' => '',
// 'Slack' => '',
@@ -921,7 +838,6 @@ return array(
// 'The task have been moved to the first swimlane' => '',
// 'The task have been moved to another swimlane:' => '',
// 'Overdue tasks for the project "%s"' => '',
- 'There is no completed tasks at the moment.' => 'Ingen fullfrte oppgaver funnet.',
// 'New title: %s' => '',
// 'The task is not assigned anymore' => '',
// 'New assignee: %s' => '',
@@ -938,7 +854,6 @@ return array(
// 'The description have been modified' => '',
// 'Do you really want to close the task "%s" as well as all subtasks?' => '',
'Swimlane: %s' => 'Svmmebane: %s',
- 'Project calendar' => 'Prosjektkalender',
'I want to receive notifications for:' => 'Jeg vil motta varslinger om:',
'All tasks' => 'Alle oppgaver',
'Only for tasks assigned to me' => 'Kun oppgaver som er tildelt meg',
@@ -951,7 +866,7 @@ return array(
// '%k:%M %p' => '',
// '%%Y-%%m-%%d' => '',
'Total for all columns' => 'Totalt for alle kolonner',
- //'You need at least 2 days of data to show the chart.' => '',
+ // 'You need at least 2 days of data to show the chart.' => '',
// '<15m' => '',
// '<30m' => '',
'Stop timer' => 'Stopp timer',
diff --git a/app/Locale/nl_NL/translations.php b/app/Locale/nl_NL/translations.php
index 8be0c61d..7c623914 100644
--- a/app/Locale/nl_NL/translations.php
+++ b/app/Locale/nl_NL/translations.php
@@ -666,28 +666,6 @@ return array(
// 'Compact/wide view' => '',
// 'No results match:' => '',
// 'Currency' => '',
- // 'Start time' => '',
- // 'End time' => '',
- // 'Comment' => '',
- // 'All day' => '',
- // 'Day' => '',
- // 'Manage timetable' => '',
- // 'Overtime timetable' => '',
- // 'Time off timetable' => '',
- // 'Timetable' => '',
- // 'Work timetable' => '',
- // 'Week timetable' => '',
- // 'Day timetable' => '',
- // 'From' => '',
- // 'To' => '',
- // 'Time slot created successfully.' => '',
- // 'Unable to save this time slot.' => '',
- // 'Time slot removed successfully.' => '',
- // 'Unable to remove this time slot.' => '',
- // 'Do you really want to remove this time slot?' => '',
- // 'Remove time slot' => '',
- // 'Add new time slot' => '',
- // 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => '',
// 'Files' => '',
// 'Images' => '',
// 'Private project' => '',
@@ -707,7 +685,6 @@ 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 (forecast of future work)' => '',
// 'Transitions' => '',
// 'Executer' => '',
// 'Time spent in the column' => '',
diff --git a/app/Locale/pl_PL/translations.php b/app/Locale/pl_PL/translations.php
index d9cfcdbc..e7683d9a 100644
--- a/app/Locale/pl_PL/translations.php
+++ b/app/Locale/pl_PL/translations.php
@@ -666,28 +666,6 @@ return array(
'Compact/wide view' => 'Pełny/Kompaktowy widok',
'No results match:' => 'Brak wyników:',
'Currency' => 'Waluta',
- 'Start time' => 'Rozpoczęto',
- 'End time' => 'Zakończono',
- 'Comment' => 'Komentarz',
- 'All day' => 'Cały dzień',
- 'Day' => 'Dzień',
- 'Manage timetable' => 'Zarządzaj rozkładami zajęć',
- 'Overtime timetable' => 'Rozkład zajęć - nadgodziny',
- 'Time off timetable' => 'Rozkład zajęć - czas wolny',
- 'Timetable' => 'Rozkład zajęć',
- 'Work timetable' => 'Rozkład zajęć - praca',
- 'Week timetable' => 'Tygodniowy rozkład zajęć',
- 'Day timetable' => 'Dzienny rozkład zajęć',
- 'From' => 'Od',
- 'To' => 'Do',
- 'Time slot created successfully.' => 'Przydział czasowy utworzony.',
- 'Unable to save this time slot.' => 'Nie można zapisać tego przydziału czasowego.',
- 'Time slot removed successfully.' => 'Przydział czasowy usunięty.',
- 'Unable to remove this time slot.' => 'Nie można usunąć tego przydziału czasowego.',
- 'Do you really want to remove this time slot?' => 'Czy na pewno chcesz usunąć ten przedział czasowy?',
- 'Remove time slot' => 'Usuń przedział czasowy',
- 'Add new time slot' => 'Dodaj przedział czasowy',
- 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => 'Ten rozkład zajęć jest używany przypadku zaznaczenia "cały dzień" dla zaplanowanego czasu wolnego i nadgodzin',
'Files' => 'Pliki',
'Images' => 'Obrazy',
'Private project' => 'Projekt prywatny',
@@ -707,7 +685,6 @@ return array(
'Move the task to another column when assigned to a user' => 'Przenieś zadanie do innej kolumny gdy zostanie przypisane do osoby',
'Move the task to another column when assignee is cleared' => 'Przenieś zadanie do innej kolumny gdy osoba odpowiedzialna zostanie usunięta',
'Source column' => 'Kolumna źródłowa',
- 'Show subtask estimates (forecast of future work)' => 'Pokaż planowane czasy wykonania pod-zadań',
'Transitions' => 'Przeniesienia',
'Executer' => 'Wykonał',
'Time spent in the column' => 'Czas spędzony w tej kolumnie',
diff --git a/app/Locale/pt_BR/translations.php b/app/Locale/pt_BR/translations.php
index 5f849457..57cfe761 100644
--- a/app/Locale/pt_BR/translations.php
+++ b/app/Locale/pt_BR/translations.php
@@ -666,28 +666,6 @@ return array(
'Compact/wide view' => 'Alternar entre a vista compacta e ampliada',
'No results match:' => 'Nenhum resultado:',
'Currency' => 'Moeda',
- 'Start time' => 'Horário de início',
- 'End time' => 'Horário de término',
- 'Comment' => 'comentário',
- 'All day' => 'Dia inteiro',
- 'Day' => 'Dia',
- 'Manage timetable' => 'Gestão dos horários',
- 'Overtime timetable' => 'Horas extras',
- 'Time off timetable' => 'Horas de ausência',
- 'Timetable' => 'Horários',
- 'Work timetable' => 'Horas trabalhadas',
- 'Week timetable' => 'Horário da semana',
- 'Day timetable' => 'Horário de un dia',
- 'From' => 'Desde',
- 'To' => 'A',
- 'Time slot created successfully.' => 'Intervalo de tempo criado com sucesso.',
- 'Unable to save this time slot.' => 'Impossível de guardar este intervalo de tempo.',
- 'Time slot removed successfully.' => 'Intervalo de tempo removido com sucesso.',
- 'Unable to remove this time slot.' => 'Impossível de remover esse intervalo de tempo.',
- 'Do you really want to remove this time slot?' => 'Você deseja realmente remover este intervalo de tempo?',
- 'Remove time slot' => 'Remover um intervalo de tempo',
- 'Add new time slot' => 'Adicionar um intervalo de tempo',
- 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => 'Esses horários são usados quando a caixa de seleção "Dia inteiro" está marcada para Horas de ausência ou Extras',
'Files' => 'Arquivos',
'Images' => 'Imagens',
'Private project' => 'Projeto privado',
@@ -707,7 +685,6 @@ 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 (forecast of future work)' => 'Mostrar a estimativa das subtarefas (previsão para o trabalho futuro)',
'Transitions' => 'Transições',
'Executer' => 'Executor(a)',
'Time spent in the column' => 'Tempo gasto na coluna',
diff --git a/app/Locale/pt_PT/translations.php b/app/Locale/pt_PT/translations.php
index 9e20b112..cb2fc53e 100644
--- a/app/Locale/pt_PT/translations.php
+++ b/app/Locale/pt_PT/translations.php
@@ -666,28 +666,6 @@ return array(
'Compact/wide view' => 'Alternar entre a vista compacta e ampliada',
'No results match:' => 'Nenhum resultado:',
'Currency' => 'Moeda',
- 'Start time' => 'Horário de início',
- 'End time' => 'Horário de término',
- 'Comment' => 'comentário',
- 'All day' => 'Dia inteiro',
- 'Day' => 'Dia',
- 'Manage timetable' => 'Gestão dos horários',
- 'Overtime timetable' => 'Horas extras',
- 'Time off timetable' => 'Horas de ausência',
- 'Timetable' => 'Horários',
- 'Work timetable' => 'Horas trabalhadas',
- 'Week timetable' => 'Horário da semana',
- 'Day timetable' => 'Horário de um dia',
- 'From' => 'Desde',
- 'To' => 'A',
- 'Time slot created successfully.' => 'Intervalo de tempo criado com sucesso.',
- 'Unable to save this time slot.' => 'Impossível guardar este intervalo de tempo.',
- 'Time slot removed successfully.' => 'Intervalo de tempo removido com sucesso.',
- 'Unable to remove this time slot.' => 'Impossível remover esse intervalo de tempo.',
- 'Do you really want to remove this time slot?' => 'Tem a certeza que quer remover este intervalo de tempo?',
- 'Remove time slot' => 'Remover um intervalo de tempo',
- 'Add new time slot' => 'Adicionar um intervalo de tempo',
- 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => 'Esses horários são usados quando a caixa de seleção "Dia inteiro" está marcada para Horas de ausência ou Extras',
'Files' => 'Arquivos',
'Images' => 'Imagens',
'Private project' => 'Projecto privado',
@@ -707,7 +685,6 @@ 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 utilizador',
'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 (forecast of future work)' => 'Mostrar a estimativa das subtarefas (previsão para o trabalho futuro)',
'Transitions' => 'Transições',
'Executer' => 'Executor(a)',
'Time spent in the column' => 'Tempo gasto na coluna',
diff --git a/app/Locale/ru_RU/translations.php b/app/Locale/ru_RU/translations.php
index 054e2ac8..53303506 100644
--- a/app/Locale/ru_RU/translations.php
+++ b/app/Locale/ru_RU/translations.php
@@ -666,28 +666,6 @@ return array(
'Compact/wide view' => 'Компактный/широкий вид',
'No results match:' => 'Отсутствуют результаты:',
'Currency' => 'Валюта',
- 'Start time' => 'Время начала',
- 'End time' => 'Время завершения',
- 'Comment' => 'Комментарий',
- 'All day' => 'Весь день',
- 'Day' => 'День',
- 'Manage timetable' => 'Управление графиками',
- 'Overtime timetable' => 'График сверхурочных',
- 'Time off timetable' => 'Время в графике',
- 'Timetable' => 'График',
- 'Work timetable' => 'Work timetable',
- 'Week timetable' => 'График на неделю',
- 'Day timetable' => 'График на день',
- 'From' => 'От кого',
- 'To' => 'Кому',
- 'Time slot created successfully.' => 'Временной интервал успешно создан.',
- 'Unable to save this time slot.' => 'Невозможно сохранить этот временной интервал.',
- 'Time slot removed successfully.' => 'Временной интервал успешно удален.',
- 'Unable to remove this time slot.' => 'Не удается удалить этот временной интервал.',
- 'Do you really want to remove this time slot?' => 'Вы действительно хотите удалить этот период времени?',
- 'Remove time slot' => 'Удалить новый интервал времени',
- 'Add new time slot' => 'Добавить новый интервал времени',
- 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => 'Это расписание используется, когда флажок "весь день" проверяется на установленное время выключения и сверхурочное время.',
'Files' => 'Файлы',
'Images' => 'Изображения',
'Private project' => 'Приватный проект',
@@ -707,7 +685,6 @@ 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 (forecast of future work)' => 'Показать оценку подзадач (прогноз будущей работы)',
'Transitions' => 'Перемещения',
'Executer' => 'Исполнитель',
'Time spent in the column' => 'Время проведенное в колонке',
@@ -849,9 +826,6 @@ return array(
'%s moved the task #%d to the first swimlane' => '%s задач перемещено #%d в первой дорожке',
'%s moved the task #%d to the swimlane "%s"' => '%s задач перемещено #%d в дорожке "%s"',
'Swimlane' => 'Дорожки',
- 'Budget overview' => 'Обзор бюджета',
- 'Type' => 'Тип',
- 'There is not enough data to show something.' => 'Недостаточно существующих данных, что бы что-то показать.',
'Gravatar' => 'Граватар',
'Hipchat' => 'Hipchat',
'Slack' => 'Slack',
diff --git a/app/Locale/sr_Latn_RS/translations.php b/app/Locale/sr_Latn_RS/translations.php
index a05d67d3..562b8f22 100644
--- a/app/Locale/sr_Latn_RS/translations.php
+++ b/app/Locale/sr_Latn_RS/translations.php
@@ -666,28 +666,6 @@ return array(
// 'Compact/wide view' => '',
// 'No results match:' => '',
// 'Currency' => '',
- // 'Start time' => '',
- // 'End time' => '',
- // 'Comment' => '',
- // 'All day' => '',
- // 'Day' => '',
- // 'Manage timetable' => '',
- // 'Overtime timetable' => '',
- // 'Time off timetable' => '',
- // 'Timetable' => '',
- // 'Work timetable' => '',
- // 'Week timetable' => '',
- // 'Day timetable' => '',
- // 'From' => '',
- // 'To' => '',
- // 'Time slot created successfully.' => '',
- // 'Unable to save this time slot.' => '',
- // 'Time slot removed successfully.' => '',
- // 'Unable to remove this time slot.' => '',
- // 'Do you really want to remove this time slot?' => '',
- // 'Remove time slot' => '',
- // 'Add new time slot' => '',
- // 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => '',
// 'Files' => '',
// 'Images' => '',
// 'Private project' => '',
@@ -707,7 +685,6 @@ 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 (forecast of future work)' => '',
// 'Transitions' => '',
// 'Executer' => '',
// 'Time spent in the column' => '',
diff --git a/app/Locale/sv_SE/translations.php b/app/Locale/sv_SE/translations.php
index e8bdb9ce..c37759c7 100644
--- a/app/Locale/sv_SE/translations.php
+++ b/app/Locale/sv_SE/translations.php
@@ -666,28 +666,6 @@ return array(
'Compact/wide view' => 'Kompakt/bred vy',
'No results match:' => 'Inga matchande resultat',
'Currency' => 'Valuta',
- 'Start time' => 'Starttid',
- 'End time' => 'Sluttid',
- 'Comment' => 'Kommentar',
- 'All day' => 'Hela dagen',
- 'Day' => 'Dag',
- 'Manage timetable' => 'Hantera timplan',
- 'Overtime timetable' => 'Övertidstimplan',
- 'Time off timetable' => 'Ledighetstimplan',
- 'Timetable' => 'Timplan',
- 'Work timetable' => 'Arbetstimplan',
- 'Week timetable' => 'Veckotidplan',
- 'Day timetable' => 'Dagstimplan',
- 'From' => 'Från',
- 'To' => 'Till',
- 'Time slot created successfully.' => 'Tidslucka skapad.',
- 'Unable to save this time slot.' => 'Kunde inte spara tidsluckan.',
- 'Time slot removed successfully.' => 'Tidsluckan tog bort.',
- 'Unable to remove this time slot.' => 'Kunde inte ta bort tidsluckan.',
- 'Do you really want to remove this time slot?' => 'Vill du verkligen ta bort tidsluckan?',
- 'Remove time slot' => 'Ta bort tidslucka',
- 'Add new time slot' => 'Lägg till ny tidslucka',
- 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => 'Denna tidslucka används när kryssrutan "hela dagen" är kryssad vid schemalagd ledighet eller övertid.',
'Files' => 'Filer',
'Images' => 'Bilder',
'Private project' => 'Privat projekt',
@@ -707,7 +685,6 @@ 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 (forecast of future work)' => 'Visa uppskattningar för deluppgifter (prognos för framtida arbete)',
'Transitions' => 'Övergångar',
'Executer' => 'Verkställare',
'Time spent in the column' => 'Tid i kolumnen.',
diff --git a/app/Locale/th_TH/translations.php b/app/Locale/th_TH/translations.php
index d94107ad..1fdb5d34 100644
--- a/app/Locale/th_TH/translations.php
+++ b/app/Locale/th_TH/translations.php
@@ -666,28 +666,6 @@ return array(
'Compact/wide view' => 'พอดี/กว้าง มุมมอง',
'No results match:' => 'ไม่มีผลลัพท์ที่ตรง',
'Currency' => 'สกุลเงิน',
- 'Start time' => 'เวลาเริ่มต้น',
- 'End time' => 'เวลาจบ',
- 'Comment' => 'ความคิดเห็น',
- 'All day' => 'ทั้งวัน',
- 'Day' => 'วัน',
- 'Manage timetable' => 'จัดการตารางเวลา',
- 'Overtime timetable' => 'ตารางเวลาโอที',
- 'Time off timetable' => 'ตารางเวลาวันหยุด',
- 'Timetable' => 'ตารางเวลา',
- 'Work timetable' => 'ตารางเวลางาน',
- 'Week timetable' => 'ตารางเวลาสัปดาห์',
- 'Day timetable' => 'ตารางเวลาวัน',
- 'From' => 'จาก',
- 'To' => 'ถึง',
- 'Time slot created successfully.' => 'สร้างช่วงเวลาเรียบร้อยแล้ว',
- 'Unable to save this time slot.' => 'ไม่สามารถบันทึกช่วงเวลานี้',
- 'Time slot removed successfully.' => 'ลบช่วงเวลาเรียบร้อยแล้ว',
- 'Unable to remove this time slot.' => 'ไม่สามารถลบช่วงเวลาได้',
- 'Do you really want to remove this time slot?' => 'คุณต้องการลบช่วงเวลานี้?',
- 'Remove time slot' => 'ลบช่วงเวลา',
- 'Add new time slot' => 'เพิ่มช่วงเวลาใหม่',
- // 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => '',
'Files' => 'ไฟล์',
'Images' => 'รูปภาพ',
'Private project' => 'โปรเจคส่วนตัว',
@@ -707,7 +685,6 @@ 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 (forecast of future work)' => '',
'Transitions' => 'การเปลี่ยนคอลัมน์',
'Executer' => 'ผู้ประมวลผล',
'Time spent in the column' => 'เวลาที่ใช้ในคอลัมน์',
diff --git a/app/Locale/tr_TR/translations.php b/app/Locale/tr_TR/translations.php
index 87cccac7..44f973d1 100644
--- a/app/Locale/tr_TR/translations.php
+++ b/app/Locale/tr_TR/translations.php
@@ -666,28 +666,6 @@ return array(
'Compact/wide view' => 'Ekrana sığdır / Geniş görünüm',
// 'No results match:' => '',
// 'Currency' => '',
- // 'Start time' => '',
- // 'End time' => '',
- // 'Comment' => '',
- // 'All day' => '',
- // 'Day' => '',
- // 'Manage timetable' => '',
- // 'Overtime timetable' => '',
- // 'Time off timetable' => '',
- // 'Timetable' => '',
- // 'Work timetable' => '',
- // 'Week timetable' => '',
- // 'Day timetable' => '',
- // 'From' => '',
- // 'To' => '',
- // 'Time slot created successfully.' => '',
- // 'Unable to save this time slot.' => '',
- // 'Time slot removed successfully.' => '',
- // 'Unable to remove this time slot.' => '',
- // 'Do you really want to remove this time slot?' => '',
- // 'Remove time slot' => '',
- // 'Add new time slot' => '',
- // 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => '',
// 'Files' => '',
// 'Images' => '',
// 'Private project' => '',
@@ -707,7 +685,6 @@ 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 (forecast of future work)' => '',
// 'Transitions' => '',
// 'Executer' => '',
// 'Time spent in the column' => '',
diff --git a/app/Locale/zh_CN/translations.php b/app/Locale/zh_CN/translations.php
index 102252e5..5ad5e9c8 100644
--- a/app/Locale/zh_CN/translations.php
+++ b/app/Locale/zh_CN/translations.php
@@ -666,28 +666,6 @@ return array(
'Compact/wide view' => '紧凑/宽视图',
'No results match:' => '无匹配结果:',
'Currency' => '货币',
- 'Start time' => '开始时间',
- 'End time' => '结束时1间',
- 'Comment' => '注释',
- 'All day' => '全天',
- 'Day' => '日期',
- 'Manage timetable' => '管理时间表',
- // 'Overtime timetable' => '',
- 'Time off timetable' => '加班时间表',
- 'Timetable' => '时间表',
- 'Work timetable' => '工作时间表',
- 'Week timetable' => '周时间表',
- 'Day timetable' => '日时间表',
- 'From' => '从',
- 'To' => '到',
- 'Time slot created successfully.' => '成功创建时间段。',
- 'Unable to save this time slot.' => '无法保存此时间段。',
- 'Time slot removed successfully.' => '成功删除时间段。',
- 'Unable to remove this time slot.' => '无法删除此时间段。',
- 'Do you really want to remove this time slot?' => '确认要删除此时间段吗?',
- 'Remove time slot' => '删除时间段',
- 'Add new time slot' => '添加新时间段',
- 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => '如果在放假和加班计划中选择全天,则会使用这里配置的时间段。',
'Files' => '文件',
'Images' => '图片',
'Private project' => '私人项目',
@@ -707,7 +685,6 @@ 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 (forecast of future work)' => '',
'Transitions' => '变更',
'Executer' => '执行者',
'Time spent in the column' => '栏目中的时间消耗',
diff --git a/app/Model/SubtaskTimeTracking.php b/app/Model/SubtaskTimeTracking.php
index 56998769..d65f2f75 100644
--- a/app/Model/SubtaskTimeTracking.php
+++ b/app/Model/SubtaskTimeTracking.php
@@ -150,13 +150,14 @@ class SubtaskTimeTracking extends Base
*
* @access public
* @param integer $user_id
- * @param integer $start
- * @param integer $end
+ * @param string $start ISO-8601 format
+ * @param string $end
* @return array
*/
public function getUserCalendarEvents($user_id, $start, $end)
{
- $result = $this->getUserQuery($user_id)
+ $hook = 'model:subtask-time-tracking:calendar:events';
+ $events = $this->getUserQuery($user_id)
->addCondition($this->getCalendarCondition(
$this->dateParser->getTimestampFromIsoFormat($start),
$this->dateParser->getTimestampFromIsoFormat($end),
@@ -165,9 +166,16 @@ class SubtaskTimeTracking extends Base
))
->findAll();
- $result = $this->timetable->calculateEventsIntersect($user_id, $result, $start, $end);
+ if ($this->hook->exists($hook)) {
+ $events = $this->hook->first($hook, array(
+ 'user_id' => $user_id,
+ 'events' => $events,
+ 'start' => $start,
+ 'end' => $end,
+ ));
+ }
- return $this->toCalendarEvents($result);
+ return $this->toCalendarEvents($events);
}
/**
@@ -293,6 +301,7 @@ class SubtaskTimeTracking extends Base
*/
public function getTimeSpent($subtask_id, $user_id)
{
+ $hook = 'model:subtask-time-tracking:calculate:time-spent';
$start_time = $this->db
->table(self::TABLE)
->eq('subtask_id', $subtask_id)
@@ -300,14 +309,23 @@ class SubtaskTimeTracking extends Base
->eq('end', 0)
->findOneColumn('start');
- if ($start_time) {
- $start = new DateTime;
- $start->setTimestamp($start_time);
+ if (empty($start_time)) {
+ return 0;
+ }
+
+ $end = new DateTime;
+ $start = new DateTime;
+ $start->setTimestamp($start_time);
- return $this->timetable->calculateEffectiveDuration($user_id, $start, new DateTime);
+ if ($this->hook->exists($hook)) {
+ return $this->hook->first($hook, array(
+ 'user_id' => $user_id,
+ 'start' => $start,
+ 'end' => $end,
+ ));
}
- return 0;
+ return $this->dateParser->getHours($start, $end);
}
/**
diff --git a/app/Model/Timetable.php b/app/Model/Timetable.php
deleted file mode 100644
index 6ddf826b..00000000
--- a/app/Model/Timetable.php
+++ /dev/null
@@ -1,356 +0,0 @@
-<?php
-
-namespace Model;
-
-use DateTime;
-use DateInterval;
-
-/**
- * Timetable
- *
- * @package model
- * @author Frederic Guillot
- */
-class Timetable extends Base
-{
- /**
- * User time slots
- *
- * @access private
- * @var array
- */
- private $day;
- private $week;
- private $overtime;
- private $timeoff;
-
- /**
- * Get a set of events by using the intersection between the timetable and the time tracking data
- *
- * @access public
- * @param integer $user_id
- * @param array $events Time tracking data
- * @param string $start ISO8601 date
- * @param string $end ISO8601 date
- * @return array
- */
- public function calculateEventsIntersect($user_id, array $events, $start, $end)
- {
- $start_dt = new DateTime($start);
- $start_dt->setTime(0, 0);
-
- $end_dt = new DateTime($end);
- $end_dt->setTime(23, 59);
-
- $timetable = $this->calculate($user_id, $start_dt, $end_dt);
-
- // The user has no timetable
- if (empty($this->week)) {
- return $events;
- }
-
- $results = array();
-
- foreach ($events as $event) {
- $results = array_merge($results, $this->calculateEventIntersect($event, $timetable));
- }
-
- return $results;
- }
-
- /**
- * Get a serie of events based on the timetable and the provided event
- *
- * @access public
- * @param array $event
- * @param array $timetable
- * @return array
- */
- public function calculateEventIntersect(array $event, array $timetable)
- {
- $events = array();
-
- foreach ($timetable as $slot) {
-
- $start_ts = $slot[0]->getTimestamp();
- $end_ts = $slot[1]->getTimestamp();
-
- if ($start_ts > $event['end']) {
- break;
- }
-
- if ($event['start'] <= $start_ts) {
- $event['start'] = $start_ts;
- }
-
- if ($event['start'] >= $start_ts && $event['start'] <= $end_ts) {
-
- if ($event['end'] >= $end_ts) {
- $events[] = array_merge($event, array('end' => $end_ts));
- }
- else {
- $events[] = $event;
- break;
- }
- }
- }
-
- return $events;
- }
-
- /**
- * Calculate effective worked hours by taking into consideration the timetable
- *
- * @access public
- * @param integer $user_id
- * @param \DateTime $start
- * @param \DateTime $end
- * @return float
- */
- public function calculateEffectiveDuration($user_id, DateTime $start, DateTime $end)
- {
- $end_timetable = clone($end);
- $end_timetable->setTime(23, 59);
-
- $timetable = $this->calculate($user_id, $start, $end_timetable);
- $found_start = false;
- $hours = 0;
-
- // The user has no timetable
- if (empty($this->week)) {
- return $this->dateParser->getHours($start, $end);
- }
-
- foreach ($timetable as $slot) {
-
- $isStartSlot = $this->dateParser->withinDateRange($start, $slot[0], $slot[1]);
- $isEndSlot = $this->dateParser->withinDateRange($end, $slot[0], $slot[1]);
-
- // Start and end are within the same time slot
- if ($isStartSlot && $isEndSlot) {
- return $this->dateParser->getHours($start, $end);
- }
-
- // We found the start slot
- if (! $found_start && $isStartSlot) {
- $found_start = true;
- $hours = $this->dateParser->getHours($start, $slot[1]);
- }
- else if ($found_start) {
-
- // We found the end slot
- if ($isEndSlot) {
- $hours += $this->dateParser->getHours($slot[0], $end);
- break;
- }
- else {
-
- // Sum hours of the intermediate time slots
- $hours += $this->dateParser->getHours($slot[0], $slot[1]);
- }
- }
- }
-
- // The start date was not found in regular hours so we get the nearest time slot
- if (! empty($timetable) && ! $found_start) {
- $slot = $this->findClosestTimeSlot($start, $timetable);
-
- if ($start < $slot[0]) {
- return $this->calculateEffectiveDuration($user_id, $slot[0], $end);
- }
- }
-
- return $hours;
- }
-
- /**
- * Find the nearest time slot
- *
- * @access public
- * @param DateTime $date
- * @param array $timetable
- * @return array
- */
- public function findClosestTimeSlot(DateTime $date, array $timetable)
- {
- $values = array();
-
- foreach ($timetable as $slot) {
- $t1 = abs($slot[0]->getTimestamp() - $date->getTimestamp());
- $t2 = abs($slot[1]->getTimestamp() - $date->getTimestamp());
-
- $values[] = min($t1, $t2);
- }
-
- asort($values);
- return $timetable[key($values)];
- }
-
- /**
- * Get the timetable for a user for a given date range
- *
- * @access public
- * @param integer $user_id
- * @param \DateTime $start
- * @param \DateTime $end
- * @return array
- */
- public function calculate($user_id, DateTime $start, DateTime $end)
- {
- $timetable = array();
-
- $this->day = $this->timetableDay->getByUser($user_id);
- $this->week = $this->timetableWeek->getByUser($user_id);
- $this->overtime = $this->timetableExtra->getByUserAndDate($user_id, $start->format('Y-m-d'), $end->format('Y-m-d'));
- $this->timeoff = $this->timetableOff->getByUserAndDate($user_id, $start->format('Y-m-d'), $end->format('Y-m-d'));
-
- for ($today = clone($start); $today <= $end; $today->add(new DateInterval('P1D'))) {
- $week_day = $today->format('N');
- $timetable = array_merge($timetable, $this->getWeekSlots($today, $week_day));
- $timetable = array_merge($timetable, $this->getOvertimeSlots($today, $week_day));
- }
-
- return $timetable;
- }
-
- /**
- * Return worked time slots for the given day
- *
- * @access public
- * @param \DateTime $today
- * @param string $week_day
- * @return array
- */
- public function getWeekSlots(DateTime $today, $week_day)
- {
- $slots = array();
- $dayoff = $this->getDayOff($today);
-
- if (! empty($dayoff) && $dayoff['all_day'] == 1) {
- return array();
- }
-
- foreach ($this->week as $slot) {
- if ($week_day == $slot['day']) {
- $slots = array_merge($slots, $this->getDayWorkSlots($slot, $dayoff, $today));
- }
- }
-
- return $slots;
- }
-
- /**
- * Get the overtime time slots for the given day
- *
- * @access public
- * @param \DateTime $today
- * @param string $week_day
- * @return array
- */
- public function getOvertimeSlots(DateTime $today, $week_day)
- {
- $slots = array();
-
- foreach ($this->overtime as $slot) {
-
- $day = new DateTime($slot['date']);
-
- if ($week_day == $day->format('N')) {
-
- if ($slot['all_day'] == 1) {
- $slots = array_merge($slots, $this->getDaySlots($today));
- }
- else {
- $slots[] = $this->getTimeSlot($slot, $day);
- }
- }
- }
-
- return $slots;
- }
-
- /**
- * Get worked time slots and remove time off
- *
- * @access public
- * @param array $slot
- * @param array $dayoff
- * @param \DateTime $today
- * @return array
- */
- public function getDayWorkSlots(array $slot, array $dayoff, DateTime $today)
- {
- $slots = array();
-
- if (! empty($dayoff) && $dayoff['start'] < $slot['end']) {
-
- if ($dayoff['start'] > $slot['start']) {
- $slots[] = $this->getTimeSlot(array('end' => $dayoff['start']) + $slot, $today);
- }
-
- if ($dayoff['end'] < $slot['end']) {
- $slots[] = $this->getTimeSlot(array('start' => $dayoff['end']) + $slot, $today);
- }
- }
- else {
- $slots[] = $this->getTimeSlot($slot, $today);
- }
-
- return $slots;
- }
-
- /**
- * Get regular day work time slots
- *
- * @access public
- * @param \DateTime $today
- * @return array
- */
- public function getDaySlots(DateTime $today)
- {
- $slots = array();
-
- foreach ($this->day as $day) {
- $slots[] = $this->getTimeSlot($day, $today);
- }
-
- return $slots;
- }
-
- /**
- * Get the start and end time slot for a given day
- *
- * @access public
- * @param array $slot
- * @param \DateTime $today
- * @return array
- */
- public function getTimeSlot(array $slot, DateTime $today)
- {
- $date = $today->format('Y-m-d');
-
- return array(
- new DateTime($date.' '.$slot['start']),
- new DateTime($date.' '.$slot['end']),
- );
- }
-
- /**
- * Return day off time slot
- *
- * @access public
- * @param \DateTime $today
- * @return array
- */
- public function getDayOff(DateTime $today)
- {
- foreach ($this->timeoff as $day) {
-
- if ($day['date'] === $today->format('Y-m-d')) {
- return $day;
- }
- }
-
- return array();
- }
-}
diff --git a/app/Model/TimetableDay.php b/app/Model/TimetableDay.php
deleted file mode 100644
index 0c7bf20b..00000000
--- a/app/Model/TimetableDay.php
+++ /dev/null
@@ -1,87 +0,0 @@
-<?php
-
-namespace Model;
-
-use SimpleValidator\Validator;
-use SimpleValidator\Validators;
-
-/**
- * Timetable Workweek
- *
- * @package model
- * @author Frederic Guillot
- */
-class TimetableDay extends Base
-{
- /**
- * SQL table name
- *
- * @var string
- */
- const TABLE = 'timetable_day';
-
- /**
- * Get the timetable for a given user
- *
- * @access public
- * @param integer $user_id User id
- * @return array
- */
- public function getByUser($user_id)
- {
- return $this->db->table(self::TABLE)->eq('user_id', $user_id)->asc('start')->findAll();
- }
-
- /**
- * Add a new time slot in the database
- *
- * @access public
- * @param integer $user_id User id
- * @param string $start Start hour (24h format)
- * @param string $end End hour (24h format)
- * @return boolean|integer
- */
- public function create($user_id, $start, $end)
- {
- $values = array(
- 'user_id' => $user_id,
- 'start' => $start,
- 'end' => $end,
- );
-
- return $this->persist(self::TABLE, $values);
- }
-
- /**
- * Remove a specific time slot
- *
- * @access public
- * @param integer $slot_id
- * @return boolean
- */
- public function remove($slot_id)
- {
- return $this->db->table(self::TABLE)->eq('id', $slot_id)->remove();
- }
-
- /**
- * Validate creation
- *
- * @access public
- * @param array $values Form values
- * @return array $valid, $errors [0] = Success or not, [1] = List of errors
- */
- public function validateCreation(array $values)
- {
- $v = new Validator($values, array(
- new Validators\Required('user_id', t('Field required')),
- new Validators\Required('start', t('Field required')),
- new Validators\Required('end', t('Field required')),
- ));
-
- return array(
- $v->execute(),
- $v->getErrors()
- );
- }
-}
diff --git a/app/Model/TimetableExtra.php b/app/Model/TimetableExtra.php
deleted file mode 100644
index 48db662d..00000000
--- a/app/Model/TimetableExtra.php
+++ /dev/null
@@ -1,22 +0,0 @@
-<?php
-
-namespace Model;
-
-use SimpleValidator\Validator;
-use SimpleValidator\Validators;
-
-/**
- * Timetable over-time
- *
- * @package model
- * @author Frederic Guillot
- */
-class TimetableExtra extends TimetableOff
-{
- /**
- * SQL table name
- *
- * @var string
- */
- const TABLE = 'timetable_extra';
-}
diff --git a/app/Model/TimetableOff.php b/app/Model/TimetableOff.php
deleted file mode 100644
index e4fe32d2..00000000
--- a/app/Model/TimetableOff.php
+++ /dev/null
@@ -1,125 +0,0 @@
-<?php
-
-namespace Model;
-
-use SimpleValidator\Validator;
-use SimpleValidator\Validators;
-
-/**
- * Timetable time off
- *
- * @package model
- * @author Frederic Guillot
- */
-class TimetableOff extends Base
-{
- /**
- * SQL table name
- *
- * @var string
- */
- const TABLE = 'timetable_off';
-
- /**
- * Get query to fetch everything (pagination)
- *
- * @access public
- * @param integer $user_id User id
- * @return \PicoDb\Table
- */
- public function getUserQuery($user_id)
- {
- return $this->db->table(static::TABLE)->eq('user_id', $user_id);
- }
-
- /**
- * Get the timetable for a given user
- *
- * @access public
- * @param integer $user_id User id
- * @return array
- */
- public function getByUser($user_id)
- {
- return $this->db->table(static::TABLE)->eq('user_id', $user_id)->desc('date')->asc('start')->findAll();
- }
-
- /**
- * Get the timetable for a given user
- *
- * @access public
- * @param integer $user_id User id
- * @param string $start_date
- * @param string $end_date
- * @return array
- */
- public function getByUserAndDate($user_id, $start_date, $end_date)
- {
- return $this->db->table(static::TABLE)
- ->eq('user_id', $user_id)
- ->gte('date', $start_date)
- ->lte('date', $end_date)
- ->desc('date')
- ->asc('start')
- ->findAll();
- }
-
- /**
- * Add a new time slot in the database
- *
- * @access public
- * @param integer $user_id User id
- * @param string $date Day (ISO8601 format)
- * @param boolean $all_day All day flag
- * @param float $start Start hour (24h format)
- * @param float $end End hour (24h format)
- * @param string $comment
- * @return boolean|integer
- */
- public function create($user_id, $date, $all_day, $start = '', $end = '', $comment = '')
- {
- $values = array(
- 'user_id' => $user_id,
- 'date' => $date,
- 'all_day' => (int) $all_day, // Postgres fix
- 'start' => $all_day ? '' : $start,
- 'end' => $all_day ? '' : $end,
- 'comment' => $comment,
- );
-
- return $this->persist(static::TABLE, $values);
- }
-
- /**
- * Remove a specific time slot
- *
- * @access public
- * @param integer $slot_id
- * @return boolean
- */
- public function remove($slot_id)
- {
- return $this->db->table(static::TABLE)->eq('id', $slot_id)->remove();
- }
-
- /**
- * Validate creation
- *
- * @access public
- * @param array $values Form values
- * @return array $valid, $errors [0] = Success or not, [1] = List of errors
- */
- public function validateCreation(array $values)
- {
- $v = new Validator($values, array(
- new Validators\Required('user_id', t('Field required')),
- new Validators\Required('date', t('Field required')),
- new Validators\Numeric('all_day', t('This value must be numeric')),
- ));
-
- return array(
- $v->execute(),
- $v->getErrors()
- );
- }
-}
diff --git a/app/Model/TimetableWeek.php b/app/Model/TimetableWeek.php
deleted file mode 100644
index b22b3b7e..00000000
--- a/app/Model/TimetableWeek.php
+++ /dev/null
@@ -1,91 +0,0 @@
-<?php
-
-namespace Model;
-
-use SimpleValidator\Validator;
-use SimpleValidator\Validators;
-
-/**
- * Timetable Workweek
- *
- * @package model
- * @author Frederic Guillot
- */
-class TimetableWeek extends Base
-{
- /**
- * SQL table name
- *
- * @var string
- */
- const TABLE = 'timetable_week';
-
- /**
- * Get the timetable for a given user
- *
- * @access public
- * @param integer $user_id User id
- * @return array
- */
- public function getByUser($user_id)
- {
- return $this->db->table(self::TABLE)->eq('user_id', $user_id)->asc('day')->asc('start')->findAll();
- }
-
- /**
- * Add a new time slot in the database
- *
- * @access public
- * @param integer $user_id User id
- * @param string $day Day of the week (ISO-8601)
- * @param string $start Start hour (24h format)
- * @param string $end End hour (24h format)
- * @return boolean|integer
- */
- public function create($user_id, $day, $start, $end)
- {
- $values = array(
- 'user_id' => $user_id,
- 'day' => $day,
- 'start' => $start,
- 'end' => $end,
- );
-
- return $this->persist(self::TABLE, $values);
- }
-
- /**
- * Remove a specific time slot
- *
- * @access public
- * @param integer $slot_id
- * @return boolean
- */
- public function remove($slot_id)
- {
- return $this->db->table(self::TABLE)->eq('id', $slot_id)->remove();
- }
-
- /**
- * Validate creation
- *
- * @access public
- * @param array $values Form values
- * @return array $valid, $errors [0] = Success or not, [1] = List of errors
- */
- public function validateCreation(array $values)
- {
- $v = new Validator($values, array(
- new Validators\Required('user_id', t('Field required')),
- new Validators\Required('day', t('Field required')),
- new Validators\Numeric('day', t('This value must be numeric')),
- new Validators\Required('start', t('Field required')),
- new Validators\Required('end', t('Field required')),
- ));
-
- return array(
- $v->execute(),
- $v->getErrors()
- );
- }
-}
diff --git a/app/Schema/Mysql.php b/app/Schema/Mysql.php
index 23a7a90a..c146eb0c 100644
--- a/app/Schema/Mysql.php
+++ b/app/Schema/Mysql.php
@@ -321,52 +321,6 @@ function version_53($pdo)
$pdo->exec("ALTER TABLE subtask_time_tracking ADD COLUMN time_spent FLOAT DEFAULT 0");
}
-function version_51($pdo)
-{
- $pdo->exec('CREATE TABLE timetable_day (
- id INT NOT NULL AUTO_INCREMENT,
- user_id INT NOT NULL,
- start VARCHAR(5) NOT NULL,
- end VARCHAR(5) NOT NULL,
- FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE,
- PRIMARY KEY(id)
- ) ENGINE=InnoDB CHARSET=utf8');
-
- $pdo->exec('CREATE TABLE timetable_week (
- id INT NOT NULL AUTO_INCREMENT,
- user_id INTEGER NOT NULL,
- day INT NOT NULL,
- start VARCHAR(5) NOT NULL,
- end VARCHAR(5) NOT NULL,
- FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE,
- PRIMARY KEY(id)
- ) ENGINE=InnoDB CHARSET=utf8');
-
- $pdo->exec('CREATE TABLE timetable_off (
- id INT NOT NULL AUTO_INCREMENT,
- user_id INT NOT NULL,
- date VARCHAR(10) NOT NULL,
- all_day TINYINT(1) DEFAULT 0,
- start VARCHAR(5) DEFAULT 0,
- end VARCHAR(5) DEFAULT 0,
- comment TEXT,
- FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE,
- PRIMARY KEY(id)
- ) ENGINE=InnoDB CHARSET=utf8');
-
- $pdo->exec('CREATE TABLE timetable_extra (
- id INT NOT NULL AUTO_INCREMENT,
- user_id INT NOT NULL,
- date VARCHAR(10) NOT NULL,
- all_day TINYINT(1) DEFAULT 0,
- start VARCHAR(5) DEFAULT 0,
- end VARCHAR(5) DEFAULT 0,
- comment TEXT,
- FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE,
- PRIMARY KEY(id)
- ) ENGINE=InnoDB CHARSET=utf8');
-}
-
function version_49($pdo)
{
$pdo->exec('ALTER TABLE subtasks ADD COLUMN position INTEGER DEFAULT 1');
diff --git a/app/Schema/Postgres.php b/app/Schema/Postgres.php
index cd4c295e..695d8f1f 100644
--- a/app/Schema/Postgres.php
+++ b/app/Schema/Postgres.php
@@ -314,48 +314,6 @@ function version_34($pdo)
$pdo->exec("ALTER TABLE subtask_time_tracking ADD COLUMN time_spent REAL DEFAULT 0");
}
-function version_32($pdo)
-{
- $pdo->exec('CREATE TABLE timetable_day (
- "id" SERIAL PRIMARY KEY,
- "user_id" INTEGER NOT NULL,
- "start" VARCHAR(5) NOT NULL,
- "end" VARCHAR(5) NOT NULL,
- FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
- )');
-
- $pdo->exec('CREATE TABLE timetable_week (
- "id" SERIAL PRIMARY KEY,
- "user_id" INTEGER NOT NULL,
- "day" INTEGER NOT NULL,
- "start" VARCHAR(5) NOT NULL,
- "end" VARCHAR(5) NOT NULL,
- FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
- )');
-
- $pdo->exec('CREATE TABLE timetable_off (
- "id" SERIAL PRIMARY KEY,
- "user_id" INTEGER NOT NULL,
- "date" VARCHAR(10) NOT NULL,
- "all_day" BOOLEAN DEFAULT \'0\',
- "start" VARCHAR(5) DEFAULT 0,
- "end" VARCHAR(5) DEFAULT 0,
- "comment" TEXT,
- FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
- )');
-
- $pdo->exec('CREATE TABLE timetable_extra (
- "id" SERIAL PRIMARY KEY,
- "user_id" INTEGER NOT NULL,
- "date" VARCHAR(10) NOT NULL,
- "all_day" BOOLEAN DEFAULT \'0\',
- "start" VARCHAR(5) DEFAULT 0,
- "end" VARCHAR(5) DEFAULT 0,
- "comment" TEXT,
- FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
- )');
-}
-
function version_30($pdo)
{
$pdo->exec('ALTER TABLE subtasks ADD COLUMN position INTEGER DEFAULT 1');
diff --git a/app/Schema/Sqlite.php b/app/Schema/Sqlite.php
index 175a583c..26ad96c7 100644
--- a/app/Schema/Sqlite.php
+++ b/app/Schema/Sqlite.php
@@ -291,48 +291,6 @@ function version_52($pdo)
$pdo->exec("ALTER TABLE subtask_time_tracking ADD COLUMN time_spent REAL DEFAULT 0");
}
-function version_50($pdo)
-{
- $pdo->exec('CREATE TABLE timetable_day (
- "id" INTEGER PRIMARY KEY,
- "user_id" INTEGER NOT NULL,
- "start" TEXT NOT NULL,
- "end" TEXT NOT NULL,
- FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
- )');
-
- $pdo->exec('CREATE TABLE timetable_week (
- "id" INTEGER PRIMARY KEY,
- "user_id" INTEGER NOT NULL,
- "day" INTEGER NOT NULL,
- "start" TEXT NOT NULL,
- "end" TEXT NOT NULL,
- FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
- )');
-
- $pdo->exec('CREATE TABLE timetable_off (
- "id" INTEGER PRIMARY KEY,
- "user_id" INTEGER NOT NULL,
- "date" TEXT NOT NULL,
- "all_day" INTEGER DEFAULT 0,
- "start" TEXT DEFAULT 0,
- "end" TEXT DEFAULT 0,
- "comment" TEXT,
- FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
- )');
-
- $pdo->exec('CREATE TABLE timetable_extra (
- "id" INTEGER PRIMARY KEY,
- "user_id" INTEGER NOT NULL,
- "date" TEXT NOT NULL,
- "all_day" INTEGER DEFAULT 0,
- "start" TEXT DEFAULT 0,
- "end" TEXT DEFAULT 0,
- "comment" TEXT,
- FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
- )');
-}
-
function version_48($pdo)
{
$pdo->exec('ALTER TABLE subtasks ADD COLUMN position INTEGER DEFAULT 1');
diff --git a/app/ServiceProvider/ClassProvider.php b/app/ServiceProvider/ClassProvider.php
index ee5ddbe4..e72d880a 100644
--- a/app/ServiceProvider/ClassProvider.php
+++ b/app/ServiceProvider/ClassProvider.php
@@ -56,11 +56,6 @@ class ClassProvider implements ServiceProviderInterface
'TaskPosition',
'TaskStatus',
'TaskValidator',
- 'Timetable',
- 'TimetableDay',
- 'TimetableExtra',
- 'TimetableWeek',
- 'TimetableOff',
'Transition',
'User',
'UserSession',
diff --git a/app/Template/config/calendar.php b/app/Template/config/calendar.php
index 25f4b43d..f5250132 100644
--- a/app/Template/config/calendar.php
+++ b/app/Template/config/calendar.php
@@ -6,22 +6,24 @@
<?= $this->form->csrf() ?>
- <h3><?= t('Project calendar view') ?></h3>
<div class="listing">
+ <h3><?= t('Project calendar view') ?></h3>
<?= $this->form->radios('calendar_project_tasks', array(
'date_creation' => t('Show tasks based on the creation date'),
'date_started' => t('Show tasks based on the start date'),
), $values) ?>
</div>
- <h3><?= t('User calendar view') ?></h3>
<div class="listing">
+ <h3><?= t('User calendar view') ?></h3>
<?= $this->form->radios('calendar_user_tasks', array(
'date_creation' => t('Show tasks based on the creation date'),
'date_started' => t('Show tasks based on the start date'),
), $values) ?>
+ </div>
- <h4><?= t('Subtasks time tracking') ?></h4>
+ <div class="listing">
+ <h3><?= t('Subtasks time tracking') ?></h3>
<?= $this->form->checkbox('calendar_user_subtasks_time_tracking', t('Show subtasks based on the time tracking'), 1, $values['calendar_user_subtasks_time_tracking'] == 1) ?>
</div>
diff --git a/app/Template/timetable/index.php b/app/Template/timetable/index.php
deleted file mode 100644
index 7a63a2ec..00000000
--- a/app/Template/timetable/index.php
+++ /dev/null
@@ -1,44 +0,0 @@
-<div class="page-header">
- <h2><?= t('Timetable') ?></h2>
- <ul>
- <li><?= $this->url->link(t('Day timetable'), 'timetableday', 'index', array('user_id' => $user['id'])) ?></li>
- <li><?= $this->url->link(t('Week timetable'), 'timetableweek', 'index', array('user_id' => $user['id'])) ?></li>
- <li><?= $this->url->link(t('Time off timetable'), 'timetableoff', 'index', array('user_id' => $user['id'])) ?></li>
- <li><?= $this->url->link(t('Overtime timetable'), 'timetableextra', 'index', array('user_id' => $user['id'])) ?></li>
- </ul>
-</div>
-
-<form method="get" action="?" autocomplete="off" class="form-inline">
-
- <?= $this->form->hidden('controller', $values) ?>
- <?= $this->form->hidden('action', $values) ?>
- <?= $this->form->hidden('user_id', $values) ?>
-
- <?= $this->form->label(t('From'), 'from') ?>
- <?= $this->form->text('from', $values, array(), array(), 'form-date') ?>
-
- <?= $this->form->label(t('To'), 'to') ?>
- <?= $this->form->text('to', $values, array(), array(), 'form-date') ?>
-
- <input type="submit" value="<?= t('Execute') ?>" class="btn btn-blue"/>
-</form>
-
-<?php if (! empty($timetable)): ?>
-<hr/>
-<h3><?= t('Work timetable') ?></h3>
-<table class="table-fixed table-stripped">
- <tr>
- <th><?= t('Day') ?></th>
- <th><?= t('Start') ?></th>
- <th><?= t('End') ?></th>
- </tr>
- <?php foreach ($timetable as $slot): ?>
- <tr>
- <td><?= dt('%B %e, %Y', $slot[0]->getTimestamp()) ?></td>
- <td><?= dt('%k:%M %p', $slot[0]->getTimestamp()) ?></td>
- <td><?= dt('%k:%M %p', $slot[1]->getTimestamp()) ?></td>
- </tr>
- <?php endforeach ?>
-</table>
-
-<?php endif ?> \ No newline at end of file
diff --git a/app/Template/timetable_day/index.php b/app/Template/timetable_day/index.php
deleted file mode 100644
index 386ceec2..00000000
--- a/app/Template/timetable_day/index.php
+++ /dev/null
@@ -1,45 +0,0 @@
-<div class="page-header">
- <h2><?= t('Day timetable') ?></h2>
-</div>
-
-<?php if (! empty($timetable)): ?>
-
-<table class="table-fixed table-stripped">
- <tr>
- <th><?= t('Start time') ?></th>
- <th><?= t('End time') ?></th>
- <th><?= t('Action') ?></th>
- </tr>
- <?php foreach ($timetable as $slot): ?>
- <tr>
- <td><?= $slot['start'] ?></td>
- <td><?= $slot['end'] ?></td>
- <td>
- <?= $this->url->link(t('Remove'), 'timetableday', 'confirm', array('user_id' => $user['id'], 'slot_id' => $slot['id'])) ?>
- </td>
- </tr>
- <?php endforeach ?>
-</table>
-
-<h3><?= t('Add new time slot') ?></h3>
-<?php endif ?>
-
-<form method="post" action="<?= $this->url->href('timetableday', 'save', array('user_id' => $user['id'])) ?>" autocomplete="off">
-
- <?= $this->form->hidden('user_id', $values) ?>
- <?= $this->form->csrf() ?>
-
- <?= $this->form->label(t('Start time'), 'start') ?>
- <?= $this->form->select('start', $this->dt->getDayHours(), $values, $errors) ?>
-
- <?= $this->form->label(t('End time'), 'end') ?>
- <?= $this->form->select('end', $this->dt->getDayHours(), $values, $errors) ?>
-
- <div class="form-actions">
- <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/>
- </div>
-</form>
-
-<p class="alert alert-info">
- <?= t('This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.') ?>
-</p> \ No newline at end of file
diff --git a/app/Template/timetable_day/remove.php b/app/Template/timetable_day/remove.php
deleted file mode 100644
index 1b33b266..00000000
--- a/app/Template/timetable_day/remove.php
+++ /dev/null
@@ -1,13 +0,0 @@
-<div class="page-header">
- <h2><?= t('Remove time slot') ?></h2>
-</div>
-
-<div class="confirm">
- <p class="alert alert-info"><?= t('Do you really want to remove this time slot?') ?></p>
-
- <div class="form-actions">
- <?= $this->url->link(t('Yes'), 'timetableday', 'remove', array('user_id' => $user['id'], 'slot_id' => $slot_id), true, 'btn btn-red') ?>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'timetableday', 'index', array('user_id' => $user['id'])) ?>
- </div>
-</div> \ No newline at end of file
diff --git a/app/Template/timetable_extra/index.php b/app/Template/timetable_extra/index.php
deleted file mode 100644
index e9982335..00000000
--- a/app/Template/timetable_extra/index.php
+++ /dev/null
@@ -1,56 +0,0 @@
-<div class="page-header">
- <h2><?= t('Overtime timetable') ?></h2>
-</div>
-
-<?php if (! $paginator->isEmpty()): ?>
-
-<table class="table-fixed table-stripped">
- <tr>
- <th><?= $paginator->order(t('Day'), 'Day') ?></th>
- <th><?= $paginator->order(t('All day'), 'all_day') ?></th>
- <th><?= $paginator->order(t('Start time'), 'start') ?></th>
- <th><?= $paginator->order(t('End time'), 'end') ?></th>
- <th class="column-40"><?= t('Comment') ?></th>
- <th><?= t('Action') ?></th>
- </tr>
- <?php foreach ($paginator->getCollection() as $slot): ?>
- <tr>
- <td><?= $slot['date'] ?></td>
- <td><?= $slot['all_day'] == 1 ? t('Yes') : t('No') ?></td>
- <td><?= $slot['start'] ?></td>
- <td><?= $slot['end'] ?></td>
- <td><?= $this->e($slot['comment']) ?></td>
- <td>
- <?= $this->url->link(t('Remove'), 'timetableextra', 'confirm', array('user_id' => $user['id'], 'slot_id' => $slot['id'])) ?>
- </td>
- </tr>
- <?php endforeach ?>
-</table>
-
-<?= $paginator ?>
-
-<?php endif ?>
-
-<form method="post" action="<?= $this->url->href('timetableextra', 'save', array('user_id' => $user['id'])) ?>" autocomplete="off">
-
- <?= $this->form->hidden('user_id', $values) ?>
- <?= $this->form->csrf() ?>
-
- <?= $this->form->label(t('Day'), 'date') ?>
- <?= $this->form->text('date', $values, $errors, array('required'), 'form-date') ?>
-
- <?= $this->form->checkbox('all_day', t('All day'), 1) ?>
-
- <?= $this->form->label(t('Start time'), 'start') ?>
- <?= $this->form->select('start', $this->dt->getDayHours(), $values, $errors) ?>
-
- <?= $this->form->label(t('End time'), 'end') ?>
- <?= $this->form->select('end', $this->dt->getDayHours(), $values, $errors) ?>
-
- <?= $this->form->label(t('Comment'), 'comment') ?>
- <?= $this->form->text('comment', $values, $errors) ?>
-
- <div class="form-actions">
- <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/>
- </div>
-</form> \ No newline at end of file
diff --git a/app/Template/timetable_extra/remove.php b/app/Template/timetable_extra/remove.php
deleted file mode 100644
index fc907438..00000000
--- a/app/Template/timetable_extra/remove.php
+++ /dev/null
@@ -1,13 +0,0 @@
-<div class="page-header">
- <h2><?= t('Remove time slot') ?></h2>
-</div>
-
-<div class="confirm">
- <p class="alert alert-info"><?= t('Do you really want to remove this time slot?') ?></p>
-
- <div class="form-actions">
- <?= $this->url->link(t('Yes'), 'timetableextra', 'remove', array('user_id' => $user['id'], 'slot_id' => $slot_id), true, 'btn btn-red') ?>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'timetableextra', 'index', array('user_id' => $user['id'])) ?>
- </div>
-</div> \ No newline at end of file
diff --git a/app/Template/timetable_off/index.php b/app/Template/timetable_off/index.php
deleted file mode 100644
index 615c2b8d..00000000
--- a/app/Template/timetable_off/index.php
+++ /dev/null
@@ -1,56 +0,0 @@
-<div class="page-header">
- <h2><?= t('Time off timetable') ?></h2>
-</div>
-
-<?php if (! $paginator->isEmpty()): ?>
-
-<table class="table-fixed table-stripped">
- <tr>
- <th><?= $paginator->order(t('Day'), 'Day') ?></th>
- <th><?= $paginator->order(t('All day'), 'all_day') ?></th>
- <th><?= $paginator->order(t('Start time'), 'start') ?></th>
- <th><?= $paginator->order(t('End time'), 'end') ?></th>
- <th class="column-40"><?= t('Comment') ?></th>
- <th><?= t('Action') ?></th>
- </tr>
- <?php foreach ($paginator->getCollection() as $slot): ?>
- <tr>
- <td><?= $slot['date'] ?></td>
- <td><?= $slot['all_day'] == 1 ? t('Yes') : t('No') ?></td>
- <td><?= $slot['start'] ?></td>
- <td><?= $slot['end'] ?></td>
- <td><?= $this->e($slot['comment']) ?></td>
- <td>
- <?= $this->url->link(t('Remove'), 'timetableoff', 'confirm', array('user_id' => $user['id'], 'slot_id' => $slot['id'])) ?>
- </td>
- </tr>
- <?php endforeach ?>
-</table>
-
-<?= $paginator ?>
-
-<?php endif ?>
-
-<form method="post" action="<?= $this->url->href('timetableoff', 'save', array('user_id' => $user['id'])) ?>" autocomplete="off">
-
- <?= $this->form->hidden('user_id', $values) ?>
- <?= $this->form->csrf() ?>
-
- <?= $this->form->label(t('Day'), 'date') ?>
- <?= $this->form->text('date', $values, $errors, array('required'), 'form-date') ?>
-
- <?= $this->form->checkbox('all_day', t('All day'), 1) ?>
-
- <?= $this->form->label(t('Start time'), 'start') ?>
- <?= $this->form->select('start', $this->dt->getDayHours(), $values, $errors) ?>
-
- <?= $this->form->label(t('End time'), 'end') ?>
- <?= $this->form->select('end', $this->dt->getDayHours(), $values, $errors) ?>
-
- <?= $this->form->label(t('Comment'), 'comment') ?>
- <?= $this->form->text('comment', $values, $errors) ?>
-
- <div class="form-actions">
- <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/>
- </div>
-</form> \ No newline at end of file
diff --git a/app/Template/timetable_off/remove.php b/app/Template/timetable_off/remove.php
deleted file mode 100644
index 621e191c..00000000
--- a/app/Template/timetable_off/remove.php
+++ /dev/null
@@ -1,13 +0,0 @@
-<div class="page-header">
- <h2><?= t('Remove time slot') ?></h2>
-</div>
-
-<div class="confirm">
- <p class="alert alert-info"><?= t('Do you really want to remove this time slot?') ?></p>
-
- <div class="form-actions">
- <?= $this->url->link(t('Yes'), 'timetableoff', 'remove', array('user_id' => $user['id'], 'slot_id' => $slot_id), true, 'btn btn-red') ?>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'timetableoff', 'index', array('user_id' => $user['id'])) ?>
- </div>
-</div> \ No newline at end of file
diff --git a/app/Template/timetable_week/index.php b/app/Template/timetable_week/index.php
deleted file mode 100644
index d58c6cfb..00000000
--- a/app/Template/timetable_week/index.php
+++ /dev/null
@@ -1,46 +0,0 @@
-<div class="page-header">
- <h2><?= t('Week timetable') ?></h2>
-</div>
-
-<?php if (! empty($timetable)): ?>
-
-<table class="table-fixed table-stripped">
- <tr>
- <th><?= t('Day') ?></th>
- <th><?= t('Start time') ?></th>
- <th><?= t('End time') ?></th>
- <th><?= t('Action') ?></th>
- </tr>
- <?php foreach ($timetable as $slot): ?>
- <tr>
- <td><?= $this->dt->getWeekDay($slot['day']) ?></td>
- <td><?= $slot['start'] ?></td>
- <td><?= $slot['end'] ?></td>
- <td>
- <?= $this->url->link(t('Remove'), 'timetableweek', 'confirm', array('user_id' => $user['id'], 'slot_id' => $slot['id'])) ?>
- </td>
- </tr>
- <?php endforeach ?>
-</table>
-
-<h3><?= t('Add new time slot') ?></h3>
-<?php endif ?>
-
-<form method="post" action="<?= $this->url->href('timetableweek', 'save', array('user_id' => $user['id'])) ?>" autocomplete="off">
-
- <?= $this->form->hidden('user_id', $values) ?>
- <?= $this->form->csrf() ?>
-
- <?= $this->form->label(t('Day'), 'day') ?>
- <?= $this->form->select('day', $this->dt->getWeekDays(), $values, $errors) ?>
-
- <?= $this->form->label(t('Start time'), 'start') ?>
- <?= $this->form->select('start', $this->dt->getDayHours(), $values, $errors) ?>
-
- <?= $this->form->label(t('End time'), 'end') ?>
- <?= $this->form->select('end', $this->dt->getDayHours(), $values, $errors) ?>
-
- <div class="form-actions">
- <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/>
- </div>
-</form> \ No newline at end of file
diff --git a/app/Template/timetable_week/remove.php b/app/Template/timetable_week/remove.php
deleted file mode 100644
index f5a10199..00000000
--- a/app/Template/timetable_week/remove.php
+++ /dev/null
@@ -1,13 +0,0 @@
-<div class="page-header">
- <h2><?= t('Remove time slot') ?></h2>
-</div>
-
-<div class="confirm">
- <p class="alert alert-info"><?= t('Do you really want to remove this time slot?') ?></p>
-
- <div class="form-actions">
- <?= $this->url->link(t('Yes'), 'timetableweek', 'remove', array('user_id' => $user['id'], 'slot_id' => $slot_id), true, 'btn btn-red') ?>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'timetableweek', 'index', array('user_id' => $user['id'])) ?>
- </div>
-</div> \ No newline at end of file
diff --git a/app/Template/user/sidebar.php b/app/Template/user/sidebar.php
index 6a4e9c47..640c8b80 100644
--- a/app/Template/user/sidebar.php
+++ b/app/Template/user/sidebar.php
@@ -62,9 +62,6 @@
<li <?= $this->app->getRouterController() === 'user' && $this->app->getRouterAction() === 'authentication' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Edit Authentication'), 'user', 'authentication', array('user_id' => $user['id'])) ?>
</li>
- <li <?= $this->app->getRouterController() === 'timetable' ? 'class="active"' : '' ?>>
- <?= $this->url->link(t('Manage timetable'), 'timetable', 'index', array('user_id' => $user['id'])) ?>
- </li>
<?php endif ?>
<?= $this->hook->render('template:user:sidebar:actions', array('user' => $user)) ?>
diff --git a/doc/budget.markdown b/doc/budget.markdown
deleted file mode 100644
index 63408d46..00000000
--- a/doc/budget.markdown
+++ /dev/null
@@ -1,34 +0,0 @@
-Budget management
-=================
-
-Budget management is based on the subtask time tracking, the user timetable and the user hourly rate.
-
-This section is available from project settings page: **Project > Budget**. There is also a shortcut from the dropdown menu on the board.
-
-Budget lines
-------------
-
-![Cost Lines](http://kanboard.net/screenshots/documentation/budget-lines.png)
-
-Budget lines are used to define a budget for the project.
-This budget can be adjusted by adding a new entry with an effective date.
-
-Cost breakdown
---------------
-
-![Cost Breakdown](http://kanboard.net/screenshots/documentation/budget-cost-breakdown.png)
-
-Based on the subtask time tracking table and user information you can see the cost of each subtask.
-
-The time spent is rounded to nearest quarter.
-
-Budget graph
-------------
-
-![Budget Graph](http://kanboard.net/screenshots/documentation/budget-graph.png)
-
-Finally, by combining all information we can generate a graph:
-
-- Expenses represents user cost
-- Budget lines are the provisioned budget
-- Remaining is the budget left at the given time
diff --git a/doc/fr/budget.markdown b/doc/fr/budget.markdown
deleted file mode 100644
index 3eac20d5..00000000
--- a/doc/fr/budget.markdown
+++ /dev/null
@@ -1,34 +0,0 @@
-Gestion du budget
-=================
-
-La gestion du budget repose sur le suivi du temps d'une sous-tâche, l'emploi du temps de l'utilisateur et le taux horaire de l'utilisateur.
-
-Cette section est accessible depuis la page de paramètres du projet : **Project > Budget**. Il existe également un raccourci depuis le menu déroulant sur le tableau.
-
-Lignes budgétaires
-------------
-
-![Ligne des coûts](http://kanboard.net/screenshots/documentation/budget-lines.png)
-
-Les lignes budgétaires sont utilisées pour définir le budget du projet.
-Celui-ci peut être ajusté en ajoutant une nouvelle entrée avec une date effective.
-
-Détail des coûts
---------------
-
-![Détail des coûts](http://kanboard.net/screenshots/documentation/budget-cost-breakdown.png)
-
-Selon le tableau qui donne le suivi temporel de la sous-tâche et les informations sur l'utilisateur vous pouvez voir le coût de chaque sous-tâche.
-
-Le temps passé est arrondi au quart d'heure le plus proche.
-
-Graphique du budget
-------------
-
-![Graphique du budget](http://kanboard.net/screenshots/documentation/budget-graph.png)
-
-Finalement, en combinant toutes les informations nous pouvons générer un graphique :
-
-- Les dépenses représentent le coût utilisateur
-- Les lignes budgétaires sont le budget prévisionnel
-- Le restant est le budget qui reste après un délai donné
diff --git a/doc/hourly-rate.markdown b/doc/hourly-rate.markdown
deleted file mode 100644
index 172f2f47..00000000
--- a/doc/hourly-rate.markdown
+++ /dev/null
@@ -1,11 +0,0 @@
-Hourly Rate
-===========
-
-Each user can have a predefined hourly rate.
-This feature is used for budget calculation.
-
-To define a new price, go to **User profile > Hourly rates**.
-
-![Hourly Rate](http://kanboard.net/screenshots/documentation/hourly-rate.png)
-
-Each hourly rate can have an effective date and and different currency.
diff --git a/doc/index.markdown b/doc/index.markdown
index 96069250..a66cc720 100644
--- a/doc/index.markdown
+++ b/doc/index.markdown
@@ -26,7 +26,6 @@ Using Kanboard
- [Project permissions](project-permissions.markdown)
- [Swimlanes](swimlanes.markdown)
- [Calendar](calendar.markdown)
-- [Budget](budget.markdown)
- [Analytics](analytics.markdown)
- [Gantt chart for tasks](gantt-chart-tasks.markdown)
- [Gantt chart for projects](gantt-chart-projects.markdown)
@@ -49,8 +48,6 @@ Using Kanboard
- [User management](user-management.markdown)
- [Notifications](notifications.markdown)
-- [Hourly rate](hourly-rate.markdown)
-- [Timetable](timetable.markdown)
- [Two factor authentication](2fa.markdown)
### Settings
diff --git a/doc/plugins.markdown b/doc/plugins.markdown
index c8222a81..cccda796 100644
--- a/doc/plugins.markdown
+++ b/doc/plugins.markdown
@@ -94,6 +94,27 @@ $this->hook->on('hook_name', $callable);
The first argument is the name of the hook and the second is a PHP callable.
+### Hooks executed only one time
+
+Some hooks can have only one listener:
+
+#### model:subtask-time-tracking:calculate:time-spent
+
+- Override time spent calculation when subtask timer is stopped
+- Arguments:
+ - `$user_id` (integer)
+ - `$start` (DateTime)
+ - `$end` (DateTime)
+
+#### model:subtask-time-tracking:calendar:events
+
+- Override subtask time tracking events to display the calendar
+- Arguments:
+ - `$user_id` (integer)
+ - `$events` (array)
+ - `$start` (string, ISO-8601 format)
+ - `$end` (string, ISO-8601 format)
+
### Merge hooks
"Merge hooks" act in the same way as the function `array_merge`. The hook callback must return an array. This array will be merged with the default one.
@@ -313,5 +334,7 @@ Kanboard will compare the version defined in your schema and the version stored
Examples of plugins
-------------------
-- Budget planning: https://github.com/kanboard/plugin-budget
-- Theme plugin sample: https://github.com/kanboard/plugin-example-theme
+- [Budget planning](https://github.com/kanboard/plugin-budget)
+- [User timetable](https://github.com/kanboard/plugin-timetable)
+- [Subtask Forecast](https://github.com/kanboard/plugin-subtask-forecast)
+- [Theme plugin sample](https://github.com/kanboard/plugin-example-theme)
diff --git a/doc/timetable.markdown b/doc/timetable.markdown
deleted file mode 100644
index 5d2f4c86..00000000
--- a/doc/timetable.markdown
+++ /dev/null
@@ -1,46 +0,0 @@
-User Timetable
-==============
-
-Each user can have a predefined timetable.
-This feature mainly is used for time tracking, project budget calculation and to display subtasks in the calendar.
-
-Each user have his own timetable. At the moment, that need to be specified manually for each person.
-You can also schedule time-off or overtime.
-
-The timetable section is available from the user profile: **User profile > Timetable**.
-
-Work timetable
---------------
-
-This timetable is dynamically calculated according to the regular week timetable, time-off and overtime.
-
-![Timetable](http://kanboard.net/screenshots/documentation/timetable.png)
-
-Week timetable
---------------
-
-![Week Timetable](http://kanboard.net/screenshots/documentation/week-timetable.png)
-
-The week timetable is used to define regular work hours for the selected user.
-
-To add a new time slot, just select the day of the week and the time range.
-
-Time off timetable
-------------------
-
-The time-off timetable is used to schedule not worked time slot.
-This time is deducted from the regular work hours.
-
-When you check the box "All day", the regular day timetable is used to define the regular work hours.
-
-Overtime timetable
-------------------
-
-![Overtime Timetable](http://kanboard.net/screenshots/documentation/overtime-timetable.png)
-
-The overtime timetable is used to define worked hours outside of regular hours.
-
-Day timetable
--------------
-
-This timetable is used when the checkbox "All day" is checked for overtime and time-off entries.
diff --git a/tests/units/Core/Plugin/HookTest.php b/tests/units/Core/Plugin/HookTest.php
index 95434ce4..f8646cbf 100644
--- a/tests/units/Core/Plugin/HookTest.php
+++ b/tests/units/Core/Plugin/HookTest.php
@@ -17,6 +17,16 @@ class HookTest extends Base
$this->assertEquals(array('A', 'B'), $h->getListeners('myhook'));
}
+ public function testExists()
+ {
+ $h = new Hook;
+ $this->assertFalse($h->exists('myhook'));
+
+ $h->on('myhook', 'A');
+
+ $this->assertTrue($h->exists('myhook'));
+ }
+
public function testMergeWithNoBinding()
{
$h = new Hook;
@@ -59,4 +69,28 @@ class HookTest extends Base
$this->assertEquals($expected, $result);
$this->assertEquals($expected, $values);
}
+
+ public function testFirstWithNoBinding()
+ {
+ $h = new Hook;
+
+ $result = $h->first('myhook', array('p' => 2));
+ $this->assertEquals(null, $result);
+ }
+
+ public function testFirstWithMultipleBindings()
+ {
+ $h = new Hook;
+
+ $h->on('myhook', function($p) {
+ return $p + 1;
+ });
+
+ $h->on('myhook', function($p) {
+ return $p;
+ });
+
+ $result = $h->first('myhook', array('p' => 3));
+ $this->assertEquals(4, $result);
+ }
}
diff --git a/tests/units/Model/TimetableTest.php b/tests/units/Model/TimetableTest.php
deleted file mode 100644
index 887e1787..00000000
--- a/tests/units/Model/TimetableTest.php
+++ /dev/null
@@ -1,256 +0,0 @@
-<?php
-
-require_once __DIR__.'/../Base.php';
-
-use Model\User;
-use Model\Timetable;
-use Model\TimetableDay;
-use Model\TimetableWeek;
-use Model\TimetableOff;
-use Model\TimetableExtra;
-
-class TimetableTest extends Base
-{
- public function testCalculateWorkDays()
- {
- $w = new TimetableWeek($this->container);
- $t = new Timetable($this->container);
-
- $this->assertNotFalse($w->create(1, 1, '09:30', '12:00'));
- $this->assertNotFalse($w->create(1, 1, '13:00', '17:00'));
- $this->assertNotFalse($w->create(1, 2, '09:30', '12:00'));
- $this->assertNotFalse($w->create(1, 2, '13:00', '17:00'));
-
- $monday = new DateTime('next Monday');
-
- $timetable = $t->calculate(1, $monday, new DateTime('next Monday + 6 days'));
- $this->assertNotEmpty($timetable);
- $this->assertCount(4, $timetable);
-
- $this->assertEquals($monday->format('Y-m-d').' 09:30', $timetable[0][0]->format('Y-m-d H:i'));
- $this->assertEquals($monday->format('Y-m-d').' 12:00', $timetable[0][1]->format('Y-m-d H:i'));
- $this->assertEquals($monday->format('Y-m-d').' 13:00', $timetable[1][0]->format('Y-m-d H:i'));
- $this->assertEquals($monday->format('Y-m-d').' 17:00', $timetable[1][1]->format('Y-m-d H:i'));
-
- $this->assertEquals($monday->add(new DateInterval('P1D'))->format('Y-m-d').' 09:30', $timetable[2][0]->format('Y-m-d H:i'));
- $this->assertEquals($monday->format('Y-m-d').' 12:00', $timetable[2][1]->format('Y-m-d H:i'));
- $this->assertEquals($monday->format('Y-m-d').' 13:00', $timetable[3][0]->format('Y-m-d H:i'));
- $this->assertEquals($monday->format('Y-m-d').' 17:00', $timetable[3][1]->format('Y-m-d H:i'));
- }
-
- public function testCalculateOverTime()
- {
- $d = new TimetableDay($this->container);
- $w = new TimetableWeek($this->container);
- $e = new TimetableExtra($this->container);
- $t = new Timetable($this->container);
-
- $monday = new DateTime('next Monday');
- $tuesday = new DateTime('next Monday + 1 day');
- $friday = new DateTime('next Monday + 4 days');
-
- $this->assertNotFalse($d->create(1, '08:00', '12:00'));
- $this->assertNotFalse($d->create(1, '14:00', '18:00'));
-
- $this->assertNotFalse($w->create(1, 1, '09:30', '12:00'));
- $this->assertNotFalse($w->create(1, 1, '13:00', '17:00'));
- $this->assertNotFalse($w->create(1, 2, '09:30', '12:00'));
- $this->assertNotFalse($w->create(1, 2, '13:00', '17:00'));
-
- $this->assertNotFalse($e->create(1, $tuesday->format('Y-m-d'), 0, '17:00', '22:00'));
- $this->assertNotFalse($e->create(1, $friday->format('Y-m-d'), 1));
-
- $timetable = $t->calculate(1, $monday, new DateTime('next Monday + 6 days'));
- $this->assertNotEmpty($timetable);
- $this->assertCount(7, $timetable);
-
- $this->assertEquals($monday->format('Y-m-d').' 09:30', $timetable[0][0]->format('Y-m-d H:i'));
- $this->assertEquals($monday->format('Y-m-d').' 12:00', $timetable[0][1]->format('Y-m-d H:i'));
- $this->assertEquals($monday->format('Y-m-d').' 13:00', $timetable[1][0]->format('Y-m-d H:i'));
- $this->assertEquals($monday->format('Y-m-d').' 17:00', $timetable[1][1]->format('Y-m-d H:i'));
-
- $this->assertEquals($tuesday->format('Y-m-d').' 09:30', $timetable[2][0]->format('Y-m-d H:i'));
- $this->assertEquals($tuesday->format('Y-m-d').' 12:00', $timetable[2][1]->format('Y-m-d H:i'));
- $this->assertEquals($tuesday->format('Y-m-d').' 13:00', $timetable[3][0]->format('Y-m-d H:i'));
- $this->assertEquals($tuesday->format('Y-m-d').' 17:00', $timetable[3][1]->format('Y-m-d H:i'));
-
- $this->assertEquals($tuesday->format('Y-m-d').' 17:00', $timetable[4][0]->format('Y-m-d H:i'));
- $this->assertEquals($tuesday->format('Y-m-d').' 22:00', $timetable[4][1]->format('Y-m-d H:i'));
-
- $this->assertEquals($friday->format('Y-m-d').' 08:00', $timetable[5][0]->format('Y-m-d H:i'));
- $this->assertEquals($friday->format('Y-m-d').' 12:00', $timetable[5][1]->format('Y-m-d H:i'));
-
- $this->assertEquals($friday->format('Y-m-d').' 14:00', $timetable[6][0]->format('Y-m-d H:i'));
- $this->assertEquals($friday->format('Y-m-d').' 18:00', $timetable[6][1]->format('Y-m-d H:i'));
- }
-
- public function testCalculateTimeOff()
- {
- $d = new TimetableDay($this->container);
- $w = new TimetableWeek($this->container);
- $o = new TimetableOff($this->container);
- $t = new Timetable($this->container);
-
- $monday = new DateTime('next Monday');
- $tuesday = new DateTime('next Monday + 1 day');
- $friday = new DateTime('next Monday + 4 days');
-
- $this->assertNotFalse($d->create(1, '08:00', '12:00'));
- $this->assertNotFalse($d->create(1, '14:00', '18:00'));
-
- $this->assertNotFalse($w->create(1, 1, '09:30', '12:00'));
- $this->assertNotFalse($w->create(1, 1, '13:00', '17:00'));
- $this->assertNotFalse($w->create(1, 2, '09:30', '12:00'));
- $this->assertNotFalse($w->create(1, 2, '13:00', '17:00'));
- $this->assertNotFalse($w->create(1, 5, '09:30', '12:00'));
- $this->assertNotFalse($w->create(1, 5, '13:00', '17:00'));
-
- $this->assertNotFalse($o->create(1, $tuesday->format('Y-m-d'), 0, '14:00', '15:00'));
- $this->assertNotFalse($o->create(1, $monday->format('Y-m-d'), 1));
-
- $timetable = $t->calculate(1, $monday, new DateTime('next Monday + 6 days'));
- $this->assertNotEmpty($timetable);
- $this->assertCount(5, $timetable);
-
- $this->assertEquals($tuesday->format('Y-m-d').' 09:30', $timetable[0][0]->format('Y-m-d H:i'));
- $this->assertEquals($tuesday->format('Y-m-d').' 12:00', $timetable[0][1]->format('Y-m-d H:i'));
-
- $this->assertEquals($tuesday->format('Y-m-d').' 13:00', $timetable[1][0]->format('Y-m-d H:i'));
- $this->assertEquals($tuesday->format('Y-m-d').' 14:00', $timetable[1][1]->format('Y-m-d H:i'));
-
- $this->assertEquals($tuesday->format('Y-m-d').' 15:00', $timetable[2][0]->format('Y-m-d H:i'));
- $this->assertEquals($tuesday->format('Y-m-d').' 17:00', $timetable[2][1]->format('Y-m-d H:i'));
-
- $this->assertEquals($friday->format('Y-m-d').' 09:30', $timetable[3][0]->format('Y-m-d H:i'));
- $this->assertEquals($friday->format('Y-m-d').' 12:00', $timetable[3][1]->format('Y-m-d H:i'));
-
- $this->assertEquals($friday->format('Y-m-d').' 13:00', $timetable[4][0]->format('Y-m-d H:i'));
- $this->assertEquals($friday->format('Y-m-d').' 17:00', $timetable[4][1]->format('Y-m-d H:i'));
- }
-
- public function testClosestTimeSlot()
- {
- $w = new TimetableWeek($this->container);
- $t = new Timetable($this->container);
-
- $this->assertNotFalse($w->create(1, 1, '09:30', '12:00'));
- $this->assertNotFalse($w->create(1, 1, '13:00', '17:00'));
- $this->assertNotFalse($w->create(1, 2, '09:30', '12:00'));
- $this->assertNotFalse($w->create(1, 2, '13:00', '17:00'));
-
- $monday = new DateTime('next Monday');
- $tuesday = new DateTime('next Monday + 1 day');
-
- $timetable = $t->calculate(1, new DateTime('next Monday'), new DateTime('next Monday + 6 days'));
- $this->assertNotEmpty($timetable);
- $this->assertCount(4, $timetable);
-
- // Start to work before timetable
- $date = clone($monday);
- $date->setTime(5, 02);
-
- $slot = $t->findClosestTimeSlot($date, $timetable);
- $this->assertNotEmpty($slot);
- $this->assertEquals($monday->format('Y-m-d').' 09:30', $slot[0]->format('Y-m-d H:i'));
- $this->assertEquals($monday->format('Y-m-d').' 12:00', $slot[1]->format('Y-m-d H:i'));
-
- // Start to work at the end of the timeslot
- $date = clone($monday);
- $date->setTime(12, 02);
-
- $slot = $t->findClosestTimeSlot($date, $timetable);
- $this->assertNotEmpty($slot);
- $this->assertEquals($monday->format('Y-m-d').' 09:30', $slot[0]->format('Y-m-d H:i'));
- $this->assertEquals($monday->format('Y-m-d').' 12:00', $slot[1]->format('Y-m-d H:i'));
-
- // Start to work at lunch time
- $date = clone($monday);
- $date->setTime(12, 32);
-
- $slot = $t->findClosestTimeSlot($date, $timetable);
- $this->assertNotEmpty($slot);
- $this->assertEquals($monday->format('Y-m-d').' 13:00', $slot[0]->format('Y-m-d H:i'));
- $this->assertEquals($monday->format('Y-m-d').' 17:00', $slot[1]->format('Y-m-d H:i'));
-
- // Start to work early in the morning
- $date = clone($tuesday);
- $date->setTime(8, 02);
-
- $slot = $t->findClosestTimeSlot($date, $timetable);
- $this->assertNotEmpty($slot);
- $this->assertEquals($tuesday->format('Y-m-d').' 09:30', $slot[0]->format('Y-m-d H:i'));
- $this->assertEquals($tuesday->format('Y-m-d').' 12:00', $slot[1]->format('Y-m-d H:i'));
- }
-
- public function testCalculateDuration()
- {
- $w = new TimetableWeek($this->container);
- $t = new Timetable($this->container);
-
- $this->assertNotFalse($w->create(1, 1, '09:30', '12:00'));
- $this->assertNotFalse($w->create(1, 1, '13:00', '17:00'));
- $this->assertNotFalse($w->create(1, 2, '09:30', '12:00'));
- $this->assertNotFalse($w->create(1, 2, '13:00', '17:00'));
-
- $monday = new DateTime('next Monday');
- $tuesday = new DateTime('next Monday + 1 day');
-
- // Different day
- $start = clone($monday);
- $start->setTime(16, 02);
-
- $end = clone($tuesday);
- $end->setTime(10, 03);
-
- $this->assertEquals(1.5, $t->calculateEffectiveDuration(1, $start, $end));
-
- // Same time slot
- $start = clone($monday);
- $start->setTime(16, 02);
-
- $end = clone($monday);
- $end->setTime(17, 03);
-
- $this->assertEquals(1, $t->calculateEffectiveDuration(1, $start, $end));
-
- // Intermediate time slot
- $start = clone($monday);
- $start->setTime(10, 02);
-
- $end = clone($tuesday);
- $end->setTime(16, 03);
-
- $this->assertEquals(11.5, $t->calculateEffectiveDuration(1, $start, $end));
-
- // Different day
- $start = clone($monday);
- $start->setTime(9, 02);
-
- $end = clone($tuesday);
- $end->setTime(10, 03);
-
- $this->assertEquals(7, $t->calculateEffectiveDuration(1, $start, $end));
-
- // Start before first time slot
- $start = clone($monday);
- $start->setTime(5, 32);
-
- $end = clone($tuesday);
- $end->setTime(11, 17);
-
- $this->assertEquals(8.25, $t->calculateEffectiveDuration(1, $start, $end));
- }
-
- public function testCalculateDurationWithEmptyTimetable()
- {
- $t = new Timetable($this->container);
-
- $start = new DateTime('next Monday');
- $start->setTime(16, 02);
-
- $end = new DateTime('next Monday');
- $end->setTime(17, 03);
-
- $this->assertEquals(1, $t->calculateEffectiveDuration(1, $start, $end));
- }
-}