From 6c711f696f73bc59813f6834ec241aef3b626cbd Mon Sep 17 00:00:00 2001 From: Frederic Guillot Date: Sat, 29 Aug 2015 20:00:53 -0400 Subject: Include documentation in the application --- ChangeLog | 1 + Makefile | 1 - README.md | 2 +- app/Controller/Doc.php | 51 + app/Helper/Url.php | 13 + app/Locale/cs_CZ/translations.php | 7 + app/Locale/da_DK/translations.php | 7 + app/Locale/de_DE/translations.php | 7 + app/Locale/es_ES/translations.php | 7 + app/Locale/fi_FI/translations.php | 7 + app/Locale/fr_FR/translations.php | 7 + app/Locale/hu_HU/translations.php | 7 + app/Locale/it_IT/translations.php | 7 + app/Locale/ja_JP/translations.php | 7 + app/Locale/nb_NO/translations.php | 7 + app/Locale/nl_NL/translations.php | 7 + app/Locale/pl_PL/translations.php | 7 + app/Locale/pt_BR/translations.php | 7 + app/Locale/pt_PT/translations.php | 7 + app/Locale/ru_RU/translations.php | 7 + app/Locale/sr_Latn_RS/translations.php | 7 + app/Locale/sv_SE/translations.php | 7 + app/Locale/th_TH/translations.php | 7 + app/Locale/tr_TR/translations.php | 7 + app/Locale/zh_CN/translations.php | 7 + app/Template/app/filters_helper.php | 3 +- app/Template/category/edit.php | 2 +- app/Template/column/edit.php | 2 +- app/Template/column/index.php | 2 +- app/Template/comment/create.php | 2 +- app/Template/comment/edit.php | 2 +- app/Template/config/integrations.php | 18 +- app/Template/config/sidebar.php | 3 + app/Template/doc/show.php | 13 + app/Template/project/edit.php | 2 +- app/Template/project/integrations.php | 12 +- app/Template/project/users.php | 1 + app/Template/search/index.php | 2 +- app/Template/task_creation/form.php | 2 +- .../task_modification/edit_description.php | 2 +- assets/css/app.css | 2 +- assets/css/print.css | 2 +- assets/css/src/markdown.css | 29 +- composer.json | 2 +- composer.lock | 12 +- doc/.htaccess | 1 + doc/2fa.markdown | 33 + doc/analytics-tasks.markdown | 24 + doc/analytics.markdown | 70 + doc/api-json-rpc.markdown | 4366 ++++++++++++++++++++ doc/application-configuration.markdown | 40 + doc/assets.markdown | 25 + doc/automatic-actions.markdown | 138 + doc/bitbucket-webhooks.markdown | 55 + doc/board-collapsed-expanded.markdown | 19 + doc/board-configuration.markdown | 24 + ...-horizontal-scrolling-and-compact-view.markdown | 12 + doc/board-show-hide-columns.markdown | 11 + doc/bruteforce-protection.markdown | 26 + doc/budget.markdown | 34 + doc/calendar-configuration.markdown | 42 + doc/calendar.markdown | 20 + doc/centos-installation.markdown | 77 + doc/cli.markdown | 144 + doc/closing-tasks.markdown | 16 + doc/coding-standards.markdown | 24 + doc/config.markdown | 242 ++ doc/contributing.markdown | 69 + doc/create-tasks-by-email.markdown | 44 + doc/creating-projects.markdown | 31 + doc/creating-tasks.markdown | 27 + doc/currency-rate.markdown | 11 + doc/debian-installation.markdown | 63 + doc/docker.markdown | 47 + doc/duplicate-move-tasks.markdown | 58 + doc/editing-projects.markdown | 16 + doc/email-configuration.markdown | 173 + doc/faq.markdown | 113 + doc/freebsd-installation.markdown | 127 + doc/gantt-chart-projects.markdown | 16 + doc/gantt-chart-tasks.markdown | 20 + doc/github-authentication.markdown | 80 + doc/github-webhooks.markdown | 99 + doc/gitlab-authentication.markdown | 78 + doc/gitlab-webhooks.markdown | 65 + doc/google-authentication.markdown | 64 + doc/heroku.markdown | 38 + doc/hipchat.markdown | 38 + doc/hourly-rate.markdown | 11 + doc/ical.markdown | 78 + doc/index.markdown | 138 + doc/installation.markdown | 40 + doc/jabber.markdown | 34 + doc/kanban-vs-todo-and-scrum.markdown | 37 + doc/keyboard-shortcuts.markdown | 24 + doc/ldap-authentication.markdown | 234 ++ doc/link-labels.markdown | 11 + doc/mailgun.markdown | 28 + doc/mysql-configuration.markdown | 44 + doc/nginx-ssl-php-fpm.markdown | 238 ++ doc/nice-urls.markdown | 36 + doc/notifications.markdown | 30 + doc/postgresql-configuration.markdown | 40 + doc/postmark.markdown | 29 + doc/project-configuration.markdown | 42 + doc/project-permissions.markdown | 49 + doc/project-views.markdown | 37 + doc/recommended-configuration.markdown | 36 + doc/recurring-tasks.markdown | 24 + doc/reverse-proxy-authentication.markdown | 64 + doc/rss.markdown | 23 + doc/screenshots.markdown | 25 + doc/search.markdown | 138 + doc/sendgrid.markdown | 24 + doc/sharing-projects.markdown | 35 + doc/slack.markdown | 38 + doc/sqlite-database.markdown | 50 + doc/subtasks.markdown | 47 + doc/swimlanes.markdown | 29 + doc/syntax-guide.markdown | 139 + doc/task-links.markdown | 22 + doc/tests.markdown | 176 + doc/time-tracking.markdown | 43 + doc/timetable.markdown | 46 + doc/transitions.markdown | 20 + doc/translations.markdown | 79 + doc/ubuntu-installation.markdown | 28 + doc/update.markdown | 26 + doc/usage-examples.markdown | 67 + doc/user-management.markdown | 81 + doc/vagrant.markdown | 64 + doc/webhooks.markdown | 306 ++ doc/what-is-kanban.markdown | 32 + doc/windows-apache-installation.markdown | 126 + doc/windows-iis-installation.markdown | 68 + docs/.htaccess | 1 - docs/2fa.markdown | 33 - docs/analytics-tasks.markdown | 24 - docs/analytics.markdown | 70 - docs/api-json-rpc.markdown | 4366 -------------------- docs/application-configuration.markdown | 40 - docs/assets.markdown | 25 - docs/automatic-actions.markdown | 138 - docs/bitbucket-webhooks.markdown | 55 - docs/board-collapsed-expanded.markdown | 19 - docs/board-configuration.markdown | 24 - ...-horizontal-scrolling-and-compact-view.markdown | 12 - docs/board-show-hide-columns.markdown | 11 - docs/bruteforce-protection.markdown | 26 - docs/budget.markdown | 34 - docs/calendar-configuration.markdown | 42 - docs/calendar.markdown | 20 - docs/centos-installation.markdown | 77 - docs/cli.markdown | 144 - docs/closing-tasks.markdown | 16 - docs/coding-standards.markdown | 24 - docs/config.markdown | 242 -- docs/contributing.markdown | 69 - docs/create-tasks-by-email.markdown | 44 - docs/creating-projects.markdown | 31 - docs/creating-tasks.markdown | 27 - docs/currency-rate.markdown | 11 - docs/debian-installation.markdown | 63 - docs/docker.markdown | 47 - docs/duplicate-move-tasks.markdown | 58 - docs/editing-projects.markdown | 16 - docs/email-configuration.markdown | 173 - docs/faq.markdown | 113 - docs/freebsd-installation.markdown | 127 - docs/gantt-chart-projects.markdown | 16 - docs/gantt-chart-tasks.markdown | 20 - docs/github-authentication.markdown | 80 - docs/github-webhooks.markdown | 99 - docs/gitlab-authentication.markdown | 78 - docs/gitlab-webhooks.markdown | 65 - docs/google-authentication.markdown | 64 - docs/heroku.markdown | 38 - docs/hipchat.markdown | 38 - docs/hourly-rate.markdown | 11 - docs/ical.markdown | 78 - docs/index.markdown | 138 - docs/installation.markdown | 40 - docs/jabber.markdown | 34 - docs/kanban-vs-todo-and-scrum.markdown | 37 - docs/keyboard-shortcuts.markdown | 24 - docs/ldap-authentication.markdown | 234 -- docs/link-labels.markdown | 11 - docs/mailgun.markdown | 28 - docs/mysql-configuration.markdown | 44 - docs/nginx-ssl-php-fpm.markdown | 238 -- docs/nice-urls.markdown | 36 - docs/notifications.markdown | 30 - docs/postgresql-configuration.markdown | 40 - docs/postmark.markdown | 29 - docs/project-configuration.markdown | 42 - docs/project-permissions.markdown | 49 - docs/project-views.markdown | 37 - docs/recommended-configuration.markdown | 36 - docs/recurring-tasks.markdown | 24 - docs/reverse-proxy-authentication.markdown | 64 - docs/rss.markdown | 23 - docs/screenshots.markdown | 25 - docs/search.markdown | 138 - docs/sendgrid.markdown | 24 - docs/sharing-projects.markdown | 35 - docs/slack.markdown | 38 - docs/sqlite-database.markdown | 50 - docs/subtasks.markdown | 47 - docs/swimlanes.markdown | 29 - docs/syntax-guide.markdown | 139 - docs/task-links.markdown | 22 - docs/tests.markdown | 176 - docs/time-tracking.markdown | 43 - docs/timetable.markdown | 46 - docs/transitions.markdown | 20 - docs/translations.markdown | 79 - docs/ubuntu-installation.markdown | 28 - docs/update.markdown | 26 - docs/usage-examples.markdown | 67 - docs/user-management.markdown | 81 - docs/vagrant.markdown | 64 - docs/webhooks.markdown | 306 -- docs/what-is-kanban.markdown | 32 - docs/windows-apache-installation.markdown | 126 - docs/windows-iis-installation.markdown | 68 - 225 files changed, 10041 insertions(+), 9794 deletions(-) create mode 100644 app/Controller/Doc.php create mode 100644 app/Template/doc/show.php create mode 100644 doc/.htaccess create mode 100644 doc/2fa.markdown create mode 100644 doc/analytics-tasks.markdown create mode 100644 doc/analytics.markdown create mode 100644 doc/api-json-rpc.markdown create mode 100644 doc/application-configuration.markdown create mode 100644 doc/assets.markdown create mode 100644 doc/automatic-actions.markdown create mode 100644 doc/bitbucket-webhooks.markdown create mode 100644 doc/board-collapsed-expanded.markdown create mode 100644 doc/board-configuration.markdown create mode 100644 doc/board-horizontal-scrolling-and-compact-view.markdown create mode 100644 doc/board-show-hide-columns.markdown create mode 100644 doc/bruteforce-protection.markdown create mode 100644 doc/budget.markdown create mode 100644 doc/calendar-configuration.markdown create mode 100644 doc/calendar.markdown create mode 100644 doc/centos-installation.markdown create mode 100644 doc/cli.markdown create mode 100644 doc/closing-tasks.markdown create mode 100644 doc/coding-standards.markdown create mode 100644 doc/config.markdown create mode 100644 doc/contributing.markdown create mode 100644 doc/create-tasks-by-email.markdown create mode 100644 doc/creating-projects.markdown create mode 100644 doc/creating-tasks.markdown create mode 100644 doc/currency-rate.markdown create mode 100644 doc/debian-installation.markdown create mode 100644 doc/docker.markdown create mode 100644 doc/duplicate-move-tasks.markdown create mode 100644 doc/editing-projects.markdown create mode 100644 doc/email-configuration.markdown create mode 100644 doc/faq.markdown create mode 100644 doc/freebsd-installation.markdown create mode 100644 doc/gantt-chart-projects.markdown create mode 100644 doc/gantt-chart-tasks.markdown create mode 100644 doc/github-authentication.markdown create mode 100644 doc/github-webhooks.markdown create mode 100644 doc/gitlab-authentication.markdown create mode 100644 doc/gitlab-webhooks.markdown create mode 100644 doc/google-authentication.markdown create mode 100644 doc/heroku.markdown create mode 100644 doc/hipchat.markdown create mode 100644 doc/hourly-rate.markdown create mode 100644 doc/ical.markdown create mode 100644 doc/index.markdown create mode 100644 doc/installation.markdown create mode 100644 doc/jabber.markdown create mode 100644 doc/kanban-vs-todo-and-scrum.markdown create mode 100644 doc/keyboard-shortcuts.markdown create mode 100644 doc/ldap-authentication.markdown create mode 100644 doc/link-labels.markdown create mode 100644 doc/mailgun.markdown create mode 100644 doc/mysql-configuration.markdown create mode 100644 doc/nginx-ssl-php-fpm.markdown create mode 100644 doc/nice-urls.markdown create mode 100644 doc/notifications.markdown create mode 100644 doc/postgresql-configuration.markdown create mode 100644 doc/postmark.markdown create mode 100644 doc/project-configuration.markdown create mode 100644 doc/project-permissions.markdown create mode 100644 doc/project-views.markdown create mode 100644 doc/recommended-configuration.markdown create mode 100644 doc/recurring-tasks.markdown create mode 100644 doc/reverse-proxy-authentication.markdown create mode 100644 doc/rss.markdown create mode 100644 doc/screenshots.markdown create mode 100644 doc/search.markdown create mode 100644 doc/sendgrid.markdown create mode 100644 doc/sharing-projects.markdown create mode 100644 doc/slack.markdown create mode 100644 doc/sqlite-database.markdown create mode 100644 doc/subtasks.markdown create mode 100644 doc/swimlanes.markdown create mode 100644 doc/syntax-guide.markdown create mode 100644 doc/task-links.markdown create mode 100644 doc/tests.markdown create mode 100644 doc/time-tracking.markdown create mode 100644 doc/timetable.markdown create mode 100644 doc/transitions.markdown create mode 100644 doc/translations.markdown create mode 100644 doc/ubuntu-installation.markdown create mode 100644 doc/update.markdown create mode 100644 doc/usage-examples.markdown create mode 100644 doc/user-management.markdown create mode 100644 doc/vagrant.markdown create mode 100644 doc/webhooks.markdown create mode 100644 doc/what-is-kanban.markdown create mode 100644 doc/windows-apache-installation.markdown create mode 100644 doc/windows-iis-installation.markdown delete mode 100644 docs/.htaccess delete mode 100644 docs/2fa.markdown delete mode 100644 docs/analytics-tasks.markdown delete mode 100644 docs/analytics.markdown delete mode 100644 docs/api-json-rpc.markdown delete mode 100644 docs/application-configuration.markdown delete mode 100644 docs/assets.markdown delete mode 100644 docs/automatic-actions.markdown delete mode 100644 docs/bitbucket-webhooks.markdown delete mode 100644 docs/board-collapsed-expanded.markdown delete mode 100644 docs/board-configuration.markdown delete mode 100644 docs/board-horizontal-scrolling-and-compact-view.markdown delete mode 100644 docs/board-show-hide-columns.markdown delete mode 100644 docs/bruteforce-protection.markdown delete mode 100644 docs/budget.markdown delete mode 100644 docs/calendar-configuration.markdown delete mode 100644 docs/calendar.markdown delete mode 100644 docs/centos-installation.markdown delete mode 100644 docs/cli.markdown delete mode 100644 docs/closing-tasks.markdown delete mode 100644 docs/coding-standards.markdown delete mode 100644 docs/config.markdown delete mode 100644 docs/contributing.markdown delete mode 100644 docs/create-tasks-by-email.markdown delete mode 100644 docs/creating-projects.markdown delete mode 100644 docs/creating-tasks.markdown delete mode 100644 docs/currency-rate.markdown delete mode 100644 docs/debian-installation.markdown delete mode 100644 docs/docker.markdown delete mode 100644 docs/duplicate-move-tasks.markdown delete mode 100644 docs/editing-projects.markdown delete mode 100644 docs/email-configuration.markdown delete mode 100644 docs/faq.markdown delete mode 100644 docs/freebsd-installation.markdown delete mode 100644 docs/gantt-chart-projects.markdown delete mode 100644 docs/gantt-chart-tasks.markdown delete mode 100644 docs/github-authentication.markdown delete mode 100644 docs/github-webhooks.markdown delete mode 100644 docs/gitlab-authentication.markdown delete mode 100644 docs/gitlab-webhooks.markdown delete mode 100644 docs/google-authentication.markdown delete mode 100644 docs/heroku.markdown delete mode 100644 docs/hipchat.markdown delete mode 100644 docs/hourly-rate.markdown delete mode 100644 docs/ical.markdown delete mode 100644 docs/index.markdown delete mode 100644 docs/installation.markdown delete mode 100644 docs/jabber.markdown delete mode 100644 docs/kanban-vs-todo-and-scrum.markdown delete mode 100644 docs/keyboard-shortcuts.markdown delete mode 100644 docs/ldap-authentication.markdown delete mode 100644 docs/link-labels.markdown delete mode 100644 docs/mailgun.markdown delete mode 100644 docs/mysql-configuration.markdown delete mode 100644 docs/nginx-ssl-php-fpm.markdown delete mode 100644 docs/nice-urls.markdown delete mode 100644 docs/notifications.markdown delete mode 100644 docs/postgresql-configuration.markdown delete mode 100644 docs/postmark.markdown delete mode 100644 docs/project-configuration.markdown delete mode 100644 docs/project-permissions.markdown delete mode 100644 docs/project-views.markdown delete mode 100644 docs/recommended-configuration.markdown delete mode 100644 docs/recurring-tasks.markdown delete mode 100644 docs/reverse-proxy-authentication.markdown delete mode 100644 docs/rss.markdown delete mode 100644 docs/screenshots.markdown delete mode 100644 docs/search.markdown delete mode 100644 docs/sendgrid.markdown delete mode 100644 docs/sharing-projects.markdown delete mode 100644 docs/slack.markdown delete mode 100644 docs/sqlite-database.markdown delete mode 100644 docs/subtasks.markdown delete mode 100644 docs/swimlanes.markdown delete mode 100644 docs/syntax-guide.markdown delete mode 100644 docs/task-links.markdown delete mode 100644 docs/tests.markdown delete mode 100644 docs/time-tracking.markdown delete mode 100644 docs/timetable.markdown delete mode 100644 docs/transitions.markdown delete mode 100644 docs/translations.markdown delete mode 100644 docs/ubuntu-installation.markdown delete mode 100644 docs/update.markdown delete mode 100644 docs/usage-examples.markdown delete mode 100644 docs/user-management.markdown delete mode 100644 docs/vagrant.markdown delete mode 100644 docs/webhooks.markdown delete mode 100644 docs/what-is-kanban.markdown delete mode 100644 docs/windows-apache-installation.markdown delete mode 100644 docs/windows-iis-installation.markdown diff --git a/ChangeLog b/ChangeLog index 4460edcd..13b856cc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,7 @@ Version 1.0.18 (unreleased) New features: +* Include documentation in the application * Add Gitlab authentication * Add users and categories filters on the board * Add hide/show columns diff --git a/Makefile b/Makefile index 655822b3..abf859f7 100644 --- a/Makefile +++ b/Makefile @@ -54,7 +54,6 @@ archive: @ rm -rf ${BUILD_DIR}/kanboard/data/* @ rm -rf ${BUILD_DIR}/kanboard/.git* @ rm -rf ${BUILD_DIR}/kanboard/tests - @ rm -rf ${BUILD_DIR}/kanboard/docs @ rm -rf ${BUILD_DIR}/kanboard/Makefile @ rm -rf ${BUILD_DIR}/kanboard/Vagrantfile @ rm -rf ${BUILD_DIR}/kanboard/Dockerfile diff --git a/README.md b/README.md index 47fd06c9..38265d87 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ Authors Documentation ------------- -- [Read the documentation](docs/index.markdown) +- [Read the documentation](doc/index.markdown) Related projects ---------------- diff --git a/app/Controller/Doc.php b/app/Controller/Doc.php new file mode 100644 index 00000000..19644b84 --- /dev/null +++ b/app/Controller/Doc.php @@ -0,0 +1,51 @@ +helper->url; + $data = file_get_contents($filename); + list($title,, $content) = explode("\n", $data, 3); + + $replaceUrl = function (array $matches) use ($url) { + return '('.$url->to('doc', 'show', array('file' => str_replace('.markdown', '', $matches[1]))).')'; + }; + + $content = preg_replace_callback('/\((.*.markdown)\)/', $replaceUrl, $data); + + return array( + 'content' => Parsedown::instance()->text($content), + 'title' => $title !== 'Documentation' ? t('Documentation: %s', $title) : $title, + ); + } + + public function show() + { + $filename = $this->request->getStringParam('file', 'index'); + + if (! preg_match('/^[a-z0-9\-]+/', $filename)) { + $filename = 'index'; + } + + $filename = __DIR__.'/../../doc/'.$filename.'.markdown'; + + if (! file_exists($filename)) { + $filename = __DIR__.'/../../doc/index.markdown'; + } + + $this->response->html($this->template->layout('doc/show', $this->readFile($filename) + array( + 'board_selector' => $this->projectPermission->getAllowedProjects($this->userSession->getId()), + ))); + } +} diff --git a/app/Helper/Url.php b/app/Helper/Url.php index 964e0762..22e9035e 100644 --- a/app/Helper/Url.php +++ b/app/Helper/Url.php @@ -16,6 +16,19 @@ class Url extends \Core\Base private $base = ''; private $directory = ''; + /** + * Helper to generate a link to the documentation + * + * @access public + * @param string $label + * @param string $file + * @return string + */ + public function doc($label, $file) + { + return $this->link($label, 'doc', 'show', array('file' => $file), false, '', '', true); + } + /** * HTML Link tag * diff --git a/app/Locale/cs_CZ/translations.php b/app/Locale/cs_CZ/translations.php index 6eefa33f..557a62cc 100644 --- a/app/Locale/cs_CZ/translations.php +++ b/app/Locale/cs_CZ/translations.php @@ -1060,4 +1060,11 @@ return array( // 'Gitlab Account' => '', // 'Link my Gitlab Account' => '', // 'Unlink my Gitlab Account' => '', + // 'Documentation: %s' => '', + // 'Switch to the Gantt chart view' => '', + // 'Reset the search/filter box' => '', + // 'Documentation' => '', + // 'Table of contents' => '', + // 'Gantt' => '', + // 'Help with project permissions' => '', ); diff --git a/app/Locale/da_DK/translations.php b/app/Locale/da_DK/translations.php index 35634be8..6a41f065 100644 --- a/app/Locale/da_DK/translations.php +++ b/app/Locale/da_DK/translations.php @@ -1060,4 +1060,11 @@ return array( // 'Gitlab Account' => '', // 'Link my Gitlab Account' => '', // 'Unlink my Gitlab Account' => '', + // 'Documentation: %s' => '', + // 'Switch to the Gantt chart view' => '', + // 'Reset the search/filter box' => '', + // 'Documentation' => '', + // 'Table of contents' => '', + // 'Gantt' => '', + // 'Help with project permissions' => '', ); diff --git a/app/Locale/de_DE/translations.php b/app/Locale/de_DE/translations.php index 9e3097fd..7b38e9fc 100644 --- a/app/Locale/de_DE/translations.php +++ b/app/Locale/de_DE/translations.php @@ -1060,4 +1060,11 @@ return array( // 'Gitlab Account' => '', // 'Link my Gitlab Account' => '', // 'Unlink my Gitlab Account' => '', + // 'Documentation: %s' => '', + // 'Switch to the Gantt chart view' => '', + // 'Reset the search/filter box' => '', + // 'Documentation' => '', + // 'Table of contents' => '', + // 'Gantt' => '', + // 'Help with project permissions' => '', ); diff --git a/app/Locale/es_ES/translations.php b/app/Locale/es_ES/translations.php index 43122ea3..ac7c0e4b 100644 --- a/app/Locale/es_ES/translations.php +++ b/app/Locale/es_ES/translations.php @@ -1060,4 +1060,11 @@ return array( // 'Gitlab Account' => '', // 'Link my Gitlab Account' => '', // 'Unlink my Gitlab Account' => '', + // 'Documentation: %s' => '', + // 'Switch to the Gantt chart view' => '', + // 'Reset the search/filter box' => '', + // 'Documentation' => '', + // 'Table of contents' => '', + // 'Gantt' => '', + // 'Help with project permissions' => '', ); diff --git a/app/Locale/fi_FI/translations.php b/app/Locale/fi_FI/translations.php index fc517b0b..d8c749a3 100644 --- a/app/Locale/fi_FI/translations.php +++ b/app/Locale/fi_FI/translations.php @@ -1060,4 +1060,11 @@ return array( // 'Gitlab Account' => '', // 'Link my Gitlab Account' => '', // 'Unlink my Gitlab Account' => '', + // 'Documentation: %s' => '', + // 'Switch to the Gantt chart view' => '', + // 'Reset the search/filter box' => '', + // 'Documentation' => '', + // 'Table of contents' => '', + // 'Gantt' => '', + // 'Help with project permissions' => '', ); diff --git a/app/Locale/fr_FR/translations.php b/app/Locale/fr_FR/translations.php index c63fb60b..0c95c7eb 100644 --- a/app/Locale/fr_FR/translations.php +++ b/app/Locale/fr_FR/translations.php @@ -1062,4 +1062,11 @@ return array( 'Gitlab Account' => 'Compte Gitlab', 'Link my Gitlab Account' => 'Lier mon compte Gitlab', 'Unlink my Gitlab Account' => 'Ne plus utiliser mon compte Gitlab', + 'Documentation: %s' => 'Documentation : %s', + 'Switch to the Gantt chart view' => 'Passer à la vue en diagramme de Gantt', + 'Reset the search/filter box' => 'Réinitialiser le champ de recherche', + 'Documentation' => 'Documentation', + 'Table of contents' => 'Table des matières', + 'Gantt' => 'Gantt', + 'Help with project permissions' => 'Aide avec les permissions des projets', ); diff --git a/app/Locale/hu_HU/translations.php b/app/Locale/hu_HU/translations.php index 9218c6d3..b346f1e3 100644 --- a/app/Locale/hu_HU/translations.php +++ b/app/Locale/hu_HU/translations.php @@ -1060,4 +1060,11 @@ return array( // 'Gitlab Account' => '', // 'Link my Gitlab Account' => '', // 'Unlink my Gitlab Account' => '', + // 'Documentation: %s' => '', + // 'Switch to the Gantt chart view' => '', + // 'Reset the search/filter box' => '', + // 'Documentation' => '', + // 'Table of contents' => '', + // 'Gantt' => '', + // 'Help with project permissions' => '', ); diff --git a/app/Locale/it_IT/translations.php b/app/Locale/it_IT/translations.php index a8b33e8b..06e2c5ca 100644 --- a/app/Locale/it_IT/translations.php +++ b/app/Locale/it_IT/translations.php @@ -1060,4 +1060,11 @@ return array( // 'Gitlab Account' => '', // 'Link my Gitlab Account' => '', // 'Unlink my Gitlab Account' => '', + // 'Documentation: %s' => '', + // 'Switch to the Gantt chart view' => '', + // 'Reset the search/filter box' => '', + // 'Documentation' => '', + // 'Table of contents' => '', + // 'Gantt' => '', + // 'Help with project permissions' => '', ); diff --git a/app/Locale/ja_JP/translations.php b/app/Locale/ja_JP/translations.php index 1ab82170..cb8c550b 100644 --- a/app/Locale/ja_JP/translations.php +++ b/app/Locale/ja_JP/translations.php @@ -1060,4 +1060,11 @@ return array( // 'Gitlab Account' => '', // 'Link my Gitlab Account' => '', // 'Unlink my Gitlab Account' => '', + // 'Documentation: %s' => '', + // 'Switch to the Gantt chart view' => '', + // 'Reset the search/filter box' => '', + // 'Documentation' => '', + // 'Table of contents' => '', + // 'Gantt' => '', + // 'Help with project permissions' => '', ); diff --git a/app/Locale/nb_NO/translations.php b/app/Locale/nb_NO/translations.php index dae6507a..155d49b4 100644 --- a/app/Locale/nb_NO/translations.php +++ b/app/Locale/nb_NO/translations.php @@ -1060,4 +1060,11 @@ return array( // 'Gitlab Account' => '', // 'Link my Gitlab Account' => '', // 'Unlink my Gitlab Account' => '', + // 'Documentation: %s' => '', + // 'Switch to the Gantt chart view' => '', + // 'Reset the search/filter box' => '', + // 'Documentation' => '', + // 'Table of contents' => '', + // 'Gantt' => '', + // 'Help with project permissions' => '', ); diff --git a/app/Locale/nl_NL/translations.php b/app/Locale/nl_NL/translations.php index 1f52faae..23d64163 100644 --- a/app/Locale/nl_NL/translations.php +++ b/app/Locale/nl_NL/translations.php @@ -1060,4 +1060,11 @@ return array( // 'Gitlab Account' => '', // 'Link my Gitlab Account' => '', // 'Unlink my Gitlab Account' => '', + // 'Documentation: %s' => '', + // 'Switch to the Gantt chart view' => '', + // 'Reset the search/filter box' => '', + // 'Documentation' => '', + // 'Table of contents' => '', + // 'Gantt' => '', + // 'Help with project permissions' => '', ); diff --git a/app/Locale/pl_PL/translations.php b/app/Locale/pl_PL/translations.php index 900cf8d9..9947cf31 100644 --- a/app/Locale/pl_PL/translations.php +++ b/app/Locale/pl_PL/translations.php @@ -1060,4 +1060,11 @@ return array( // 'Gitlab Account' => '', // 'Link my Gitlab Account' => '', // 'Unlink my Gitlab Account' => '', + // 'Documentation: %s' => '', + // 'Switch to the Gantt chart view' => '', + // 'Reset the search/filter box' => '', + // 'Documentation' => '', + // 'Table of contents' => '', + // 'Gantt' => '', + // 'Help with project permissions' => '', ); diff --git a/app/Locale/pt_BR/translations.php b/app/Locale/pt_BR/translations.php index 1de6cb9a..6aa2f4dd 100644 --- a/app/Locale/pt_BR/translations.php +++ b/app/Locale/pt_BR/translations.php @@ -1060,4 +1060,11 @@ return array( 'Gitlab Account' => 'Conta Gitlab', 'Link my Gitlab Account' => 'Vincular minha conta Gitlab', 'Unlink my Gitlab Account' => 'Desvincular minha conta Gitlab', + // 'Documentation: %s' => '', + // 'Switch to the Gantt chart view' => '', + // 'Reset the search/filter box' => '', + // 'Documentation' => '', + // 'Table of contents' => '', + // 'Gantt' => '', + // 'Help with project permissions' => '', ); diff --git a/app/Locale/pt_PT/translations.php b/app/Locale/pt_PT/translations.php index 1701bb11..d19a31ec 100644 --- a/app/Locale/pt_PT/translations.php +++ b/app/Locale/pt_PT/translations.php @@ -1060,4 +1060,11 @@ return array( 'Gitlab Account' => 'Conta Gitlab', 'Link my Gitlab Account' => 'Connectar a minha Conta Gitlab', 'Unlink my Gitlab Account' => 'Desconectar a minha Conta Gitlab', + // 'Documentation: %s' => '', + // 'Switch to the Gantt chart view' => '', + // 'Reset the search/filter box' => '', + // 'Documentation' => '', + // 'Table of contents' => '', + // 'Gantt' => '', + // 'Help with project permissions' => '', ); diff --git a/app/Locale/ru_RU/translations.php b/app/Locale/ru_RU/translations.php index bd2d7c6b..feb1b684 100644 --- a/app/Locale/ru_RU/translations.php +++ b/app/Locale/ru_RU/translations.php @@ -1060,4 +1060,11 @@ return array( // 'Gitlab Account' => '', // 'Link my Gitlab Account' => '', // 'Unlink my Gitlab Account' => '', + // 'Documentation: %s' => '', + // 'Switch to the Gantt chart view' => '', + // 'Reset the search/filter box' => '', + // 'Documentation' => '', + // 'Table of contents' => '', + // 'Gantt' => '', + // 'Help with project permissions' => '', ); diff --git a/app/Locale/sr_Latn_RS/translations.php b/app/Locale/sr_Latn_RS/translations.php index 2decbd68..0bc5c248 100644 --- a/app/Locale/sr_Latn_RS/translations.php +++ b/app/Locale/sr_Latn_RS/translations.php @@ -1060,4 +1060,11 @@ return array( // 'Gitlab Account' => '', // 'Link my Gitlab Account' => '', // 'Unlink my Gitlab Account' => '', + // 'Documentation: %s' => '', + // 'Switch to the Gantt chart view' => '', + // 'Reset the search/filter box' => '', + // 'Documentation' => '', + // 'Table of contents' => '', + // 'Gantt' => '', + // 'Help with project permissions' => '', ); diff --git a/app/Locale/sv_SE/translations.php b/app/Locale/sv_SE/translations.php index 79d5ec17..9c769724 100644 --- a/app/Locale/sv_SE/translations.php +++ b/app/Locale/sv_SE/translations.php @@ -1060,4 +1060,11 @@ return array( // 'Gitlab Account' => '', // 'Link my Gitlab Account' => '', // 'Unlink my Gitlab Account' => '', + // 'Documentation: %s' => '', + // 'Switch to the Gantt chart view' => '', + // 'Reset the search/filter box' => '', + // 'Documentation' => '', + // 'Table of contents' => '', + // 'Gantt' => '', + // 'Help with project permissions' => '', ); diff --git a/app/Locale/th_TH/translations.php b/app/Locale/th_TH/translations.php index 959b5f38..a5ed2474 100644 --- a/app/Locale/th_TH/translations.php +++ b/app/Locale/th_TH/translations.php @@ -1060,4 +1060,11 @@ return array( // 'Gitlab Account' => '', // 'Link my Gitlab Account' => '', // 'Unlink my Gitlab Account' => '', + // 'Documentation: %s' => '', + // 'Switch to the Gantt chart view' => '', + // 'Reset the search/filter box' => '', + // 'Documentation' => '', + // 'Table of contents' => '', + // 'Gantt' => '', + // 'Help with project permissions' => '', ); diff --git a/app/Locale/tr_TR/translations.php b/app/Locale/tr_TR/translations.php index 45ba9d27..9eb5c41e 100644 --- a/app/Locale/tr_TR/translations.php +++ b/app/Locale/tr_TR/translations.php @@ -1060,4 +1060,11 @@ return array( // 'Gitlab Account' => '', // 'Link my Gitlab Account' => '', // 'Unlink my Gitlab Account' => '', + // 'Documentation: %s' => '', + // 'Switch to the Gantt chart view' => '', + // 'Reset the search/filter box' => '', + // 'Documentation' => '', + // 'Table of contents' => '', + // 'Gantt' => '', + // 'Help with project permissions' => '', ); diff --git a/app/Locale/zh_CN/translations.php b/app/Locale/zh_CN/translations.php index eddb261a..910bc0b4 100644 --- a/app/Locale/zh_CN/translations.php +++ b/app/Locale/zh_CN/translations.php @@ -1060,4 +1060,11 @@ return array( // 'Gitlab Account' => '', // 'Link my Gitlab Account' => '', // 'Unlink my Gitlab Account' => '', + // 'Documentation: %s' => '', + // 'Switch to the Gantt chart view' => '', + // 'Reset the search/filter box' => '', + // 'Documentation' => '', + // 'Table of contents' => '', + // 'Gantt' => '', + // 'Help with project permissions' => '', ); diff --git a/app/Template/app/filters_helper.php b/app/Template/app/filters_helper.php index b7a0bba6..529aa6a5 100644 --- a/app/Template/app/filters_helper.php +++ b/app/Template/app/filters_helper.php @@ -12,8 +12,7 @@
  • - - + url->doc(t('View advanced search syntax'), 'search') ?>
  • \ No newline at end of file diff --git a/app/Template/category/edit.php b/app/Template/category/edit.php index f844eea4..1aae2f2a 100644 --- a/app/Template/category/edit.php +++ b/app/Template/category/edit.php @@ -30,7 +30,7 @@ -
    +
    url->doc(t('Write your text in Markdown'), 'syntax-guide') ?>
    diff --git a/app/Template/column/edit.php b/app/Template/column/edit.php index 691cff00..a17affd8 100644 --- a/app/Template/column/edit.php +++ b/app/Template/column/edit.php @@ -34,7 +34,7 @@
    -
    +
    url->doc(t('Write your text in Markdown'), 'syntax-guide') ?>
    diff --git a/app/Template/column/index.php b/app/Template/column/index.php index a394ee67..689cbbf5 100644 --- a/app/Template/column/index.php +++ b/app/Template/column/index.php @@ -81,7 +81,7 @@
    -
    +
    url->doc(t('Write your text in Markdown'), 'syntax-guide') ?>
    diff --git a/app/Template/comment/create.php b/app/Template/comment/create.php index 8c66d9a4..8bcbe0f7 100644 --- a/app/Template/comment/create.php +++ b/app/Template/comment/create.php @@ -24,7 +24,7 @@
    -
    +
    url->doc(t('Write your text in Markdown'), 'syntax-guide') ?>
    diff --git a/app/Template/comment/edit.php b/app/Template/comment/edit.php index d67aa387..e01f3da4 100644 --- a/app/Template/comment/edit.php +++ b/app/Template/comment/edit.php @@ -26,7 +26,7 @@
    -
    +
    url->doc(t('Write your text in Markdown'), 'syntax-guide') ?>
    diff --git a/app/Template/config/integrations.php b/app/Template/config/integrations.php index ddbd73dd..4e24a270 100644 --- a/app/Template/config/integrations.php +++ b/app/Template/config/integrations.php @@ -9,37 +9,37 @@


    -

    +

    url->doc(t('Help on Google authentication'), 'google-authentication') ?>


    -

    +

    url->doc(t('Help on Github authentication'), 'github-authentication') ?>

     


    -

    +

    url->doc(t('Help on Gitlab authentication'), 'gitlab-authentication') ?>

     


    -

    +

    url->doc(t('Help on Mailgun integration'), 'mailgun') ?>

     


    -

    +

    url->doc(t('Help on Sendgrid integration'), 'sendgrid') ?>

     


    -

    +

    url->doc(t('Help on Postmark integration'), 'postmark') ?>

     

    @@ -70,7 +70,7 @@ form->label(t('Multi-user chat room'), 'integration_jabber_room') ?> form->text('integration_jabber_room', $values, $errors, array('placeholder="myroom@conference.example.com"')) ?> -

    +

    url->doc(t('Help on Jabber integration'), 'jabber') ?>

    @@ -86,7 +86,7 @@ form->label(t('Room notification token'), 'integration_hipchat_room_token') ?> form->text('integration_hipchat_room_token', $values, $errors) ?> -

    +

    url->doc(t('Help on Hipchat integration'), 'hipchat') ?>

     

    @@ -98,7 +98,7 @@ form->label(t('Channel/Group/User (Optional)'), 'integration_slack_webhook_channel') ?> form->text('integration_slack_webhook_channel', $values, $errors) ?> -

    +

    url->doc(t('Help on Slack integration'), 'slack') ?>

    diff --git a/app/Template/config/sidebar.php b/app/Template/config/sidebar.php index b2c73292..3617979a 100644 --- a/app/Template/config/sidebar.php +++ b/app/Template/config/sidebar.php @@ -31,6 +31,9 @@
  • app->getRouterAction() === 'api' ? 'class="active"' : '' ?>> url->link(t('API'), 'config', 'api') ?>
  • +
  • + url->link(t('Documentation'), 'doc', 'show') ?> +
  • diff --git a/app/Template/doc/show.php b/app/Template/doc/show.php new file mode 100644 index 00000000..8fbadc93 --- /dev/null +++ b/app/Template/doc/show.php @@ -0,0 +1,13 @@ +
    + +
    + +
    +
    \ No newline at end of file diff --git a/app/Template/project/edit.php b/app/Template/project/edit.php index 3c64a399..8dcbb88f 100644 --- a/app/Template/project/edit.php +++ b/app/Template/project/edit.php @@ -42,7 +42,7 @@
    -
    +
    url->doc(t('Write your text in Markdown'), 'syntax-guide') ?>
    diff --git a/app/Template/project/integrations.php b/app/Template/project/integrations.php index 12a7ee4e..eb5faddf 100644 --- a/app/Template/project/integrations.php +++ b/app/Template/project/integrations.php @@ -9,21 +9,21 @@

     


    -

    +

    url->doc(t('Help on Github webhooks'), 'github-webhooks') ?>

     


    -

    +

    url->doc(t('Help on Gitlab webhooks'), 'gitlab-webhooks') ?>

     


    -

    +

    url->doc(t('Help on Bitbucket webhooks'), 'bitbucket-webhooks') ?>

    @@ -50,7 +50,7 @@ form->label(t('Multi-user chat room'), 'jabber_room') ?> form->text('jabber_room', $values, $errors, array('placeholder="myroom@conference.example.com"')) ?> -

    +

    url->doc(t('Help on Jabber integration'), 'jabber') ?>

    @@ -71,7 +71,7 @@ form->label(t('Room notification token'), 'hipchat_room_token') ?> form->text('hipchat_room_token', $values, $errors) ?> -

    +

    url->doc(t('Help on Hipchat integration'), 'hipchat') ?>

    @@ -88,7 +88,7 @@ form->label(t('Channel/Group/User (Optional)'), 'slack_webhook_channel') ?> form->text('slack_webhook_channel', $values, $errors) ?> -

    +

    url->doc(t('Help on Slack integration'), 'slack') ?>

    diff --git a/app/Template/project/users.php b/app/Template/project/users.php index d725a9e8..8863a1e4 100644 --- a/app/Template/project/users.php +++ b/app/Template/project/users.php @@ -77,5 +77,6 @@
    • +
    • url->doc(t('Help with project permissions'), 'project-permissions') ?>
    diff --git a/app/Template/search/index.php b/app/Template/search/index.php index 8940a24e..329c072a 100644 --- a/app/Template/search/index.php +++ b/app/Template/search/index.php @@ -31,7 +31,7 @@
  • description:"Something to find"
  • due:2015-07-01
  • -

    +

    url->doc(t('View advanced search syntax'), 'search') ?>

    isEmpty()): ?>

    diff --git a/app/Template/task_creation/form.php b/app/Template/task_creation/form.php index 84f28a1e..8a29896e 100644 --- a/app/Template/task_creation/form.php +++ b/app/Template/task_creation/form.php @@ -38,7 +38,7 @@
    -
    +
    url->doc(t('Write your text in Markdown'), 'syntax-guide') ?>
    form->checkbox('another_task', t('Create another task'), 1, isset($values['another_task']) && $values['another_task'] == 1) ?> diff --git a/app/Template/task_modification/edit_description.php b/app/Template/task_modification/edit_description.php index 3168f7a3..4cae939c 100644 --- a/app/Template/task_modification/edit_description.php +++ b/app/Template/task_modification/edit_description.php @@ -24,7 +24,7 @@
    -
    +
    url->doc(t('Write your text in Markdown'), 'syntax-guide') ?>
    diff --git a/assets/css/app.css b/assets/css/app.css index cf65c735..366c7eb3 100644 --- a/assets/css/app.css +++ b/assets/css/app.css @@ -17,4 +17,4 @@ */.fc{direction:ltr;text-align:left}.fc-rtl{text-align:right}body .fc{font-size:1em}.fc-unthemed .fc-divider,.fc-unthemed .fc-popover,.fc-unthemed .fc-row,.fc-unthemed tbody,.fc-unthemed td,.fc-unthemed th,.fc-unthemed thead{border-color:#ddd}.fc-unthemed .fc-popover{background-color:#fff}.fc-unthemed .fc-divider,.fc-unthemed .fc-popover .fc-header{background:#eee}.fc-unthemed .fc-popover .fc-header .fc-close{color:#666}.fc-unthemed .fc-today{background:#fcf8e3}.fc-highlight{background:#bce8f1;opacity:.3;filter:alpha(opacity=30)}.fc-bgevent{background:#8fdf82;opacity:.3;filter:alpha(opacity=30)}.fc-nonbusiness{background:#d7d7d7}.fc-icon{display:inline-block;width:1em;height:1em;line-height:1em;font-size:1em;text-align:center;overflow:hidden;font-family:"Courier New",Courier,monospace;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.fc-icon:after{position:relative;margin:0 -1em}.fc-icon-left-single-arrow:after{content:"\02039";font-weight:700;font-size:200%;top:-7%;left:3%}.fc-icon-right-single-arrow:after{content:"\0203A";font-weight:700;font-size:200%;top:-7%;left:-3%}.fc-icon-left-double-arrow:after{content:"\000AB";font-size:160%;top:-7%}.fc-icon-right-double-arrow:after{content:"\000BB";font-size:160%;top:-7%}.fc-icon-left-triangle:after{content:"\25C4";font-size:125%;top:3%;left:-2%}.fc-icon-right-triangle:after{content:"\25BA";font-size:125%;top:3%;left:2%}.fc-icon-down-triangle:after{content:"\25BC";font-size:125%;top:2%}.fc-icon-x:after{content:"\000D7";font-size:200%;top:6%}.fc button{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;margin:0;height:2.1em;padding:0 .6em;font-size:1em;white-space:nowrap;cursor:pointer}.fc button::-moz-focus-inner{margin:0;padding:0}.fc-state-default{border:1px solid}.fc-state-default.fc-corner-left{border-top-left-radius:4px;border-bottom-left-radius:4px}.fc-state-default.fc-corner-right{border-top-right-radius:4px;border-bottom-right-radius:4px}.fc button .fc-icon{position:relative;top:-.05em;margin:0 .2em;vertical-align:middle}.fc-state-default{background-color:#f5f5f5;background-image:-moz-linear-gradient(top,#fff,#e6e6e6);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6));background-image:-webkit-linear-gradient(top,#fff,#e6e6e6);background-image:-o-linear-gradient(top,#fff,#e6e6e6);background-image:linear-gradient(to bottom,#fff,#e6e6e6);background-repeat:repeat-x;border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25);color:#333;text-shadow:0 1px 1px rgba(255,255,255,.75);box-shadow:inset 0 1px 0 rgba(255,255,255,.2),0 1px 2px rgba(0,0,0,.05)}.fc-state-active,.fc-state-disabled,.fc-state-down,.fc-state-hover{color:#333;background-color:#e6e6e6}.fc-state-hover{color:#333;text-decoration:none;background-position:0 -15px;-webkit-transition:background-position .1s linear;-moz-transition:background-position .1s linear;-o-transition:background-position .1s linear;transition:background-position .1s linear}.fc-state-active,.fc-state-down{background-color:#ccc;background-image:none;box-shadow:inset 0 2px 4px rgba(0,0,0,.15),0 1px 2px rgba(0,0,0,.05)}.fc-state-disabled{cursor:default;background-image:none;opacity:.65;filter:alpha(opacity=65);box-shadow:none}.fc-button-group{display:inline-block}.fc .fc-button-group>*{float:left;margin:0 0 0 -1px}.fc .fc-button-group>:first-child{margin-left:0}.fc-popover{position:absolute;box-shadow:0 2px 6px rgba(0,0,0,.15)}.fc-popover .fc-header{padding:2px 4px}.fc-popover .fc-header .fc-title{margin:0 2px}.fc-popover .fc-header .fc-close{cursor:pointer}.fc-ltr .fc-popover .fc-header .fc-title,.fc-rtl .fc-popover .fc-header .fc-close{float:left}.fc-ltr .fc-popover .fc-header .fc-close,.fc-rtl .fc-popover .fc-header .fc-title{float:right}.fc-unthemed .fc-popover{border-width:1px;border-style:solid}.fc-unthemed .fc-popover .fc-header .fc-close{font-size:.9em;margin-top:2px}.fc-popover>.ui-widget-header+.ui-widget-content{border-top:0}.fc-divider{border-style:solid;border-width:1px}hr.fc-divider{height:0;margin:0;padding:0 0 2px;border-width:1px 0}.fc-clear{clear:both}.fc-bg,.fc-bgevent-skeleton,.fc-helper-skeleton,.fc-highlight-skeleton{position:absolute;top:0;left:0;right:0}.fc-bg{bottom:0}.fc-bg table{height:100%}.fc table{width:100%;table-layout:fixed;border-collapse:collapse;border-spacing:0;font-size:1em}.fc th{text-align:center}.fc td,.fc th{border-style:solid;border-width:1px;padding:0;vertical-align:top}.fc td.fc-today{border-style:double}.fc .fc-row{border-style:solid;border-width:0}.fc-row table{border-left:0 hidden transparent;border-right:0 hidden transparent;border-bottom:0 hidden transparent}.fc-row:first-child table{border-top:0 hidden transparent}.fc-row{position:relative}.fc-row .fc-bg{z-index:1}.fc-row .fc-bgevent-skeleton,.fc-row .fc-highlight-skeleton{bottom:0}.fc-row .fc-bgevent-skeleton table,.fc-row .fc-highlight-skeleton table{height:100%}.fc-row .fc-bgevent-skeleton td,.fc-row .fc-highlight-skeleton td{border-color:transparent}.fc-row .fc-bgevent-skeleton{z-index:2}.fc-row .fc-highlight-skeleton{z-index:3}.fc-row .fc-content-skeleton{position:relative;z-index:4;padding-bottom:2px}.fc-row .fc-helper-skeleton{z-index:5}.fc-row .fc-content-skeleton td,.fc-row .fc-helper-skeleton td{background:0 0;border-color:transparent;border-bottom:0}.fc-row .fc-content-skeleton tbody td,.fc-row .fc-helper-skeleton tbody td{border-top:0}.fc-scroller{overflow-y:scroll;overflow-x:hidden}.fc-scroller>*{position:relative;width:100%;overflow:hidden}.fc-event{position:relative;display:block;font-size:.85em;line-height:1.3;border-radius:3px;border:1px solid #3a87ad;background-color:#3a87ad;font-weight:400}.fc-event,.fc-event:hover,.ui-widget .fc-event{color:#fff;text-decoration:none}.fc-event.fc-draggable,.fc-event[href]{cursor:pointer}.fc-not-allowed,.fc-not-allowed .fc-event{cursor:not-allowed}.fc-event .fc-bg{z-index:1;background:#fff;opacity:.25;filter:alpha(opacity=25)}.fc-event .fc-content{position:relative;z-index:2}.fc-event .fc-resizer{position:absolute;z-index:3}.fc-ltr .fc-h-event.fc-not-start,.fc-rtl .fc-h-event.fc-not-end{margin-left:0;border-left-width:0;padding-left:1px;border-top-left-radius:0;border-bottom-left-radius:0}.fc-ltr .fc-h-event.fc-not-end,.fc-rtl .fc-h-event.fc-not-start{margin-right:0;border-right-width:0;padding-right:1px;border-top-right-radius:0;border-bottom-right-radius:0}.fc-h-event .fc-resizer{top:-1px;bottom:-1px;left:-1px;right:-1px;width:5px}.fc-ltr .fc-h-event .fc-start-resizer,.fc-ltr .fc-h-event .fc-start-resizer:after,.fc-ltr .fc-h-event .fc-start-resizer:before,.fc-rtl .fc-h-event .fc-end-resizer,.fc-rtl .fc-h-event .fc-end-resizer:after,.fc-rtl .fc-h-event .fc-end-resizer:before{right:auto;cursor:w-resize}.fc-ltr .fc-h-event .fc-end-resizer,.fc-ltr .fc-h-event .fc-end-resizer:after,.fc-ltr .fc-h-event .fc-end-resizer:before,.fc-rtl .fc-h-event .fc-start-resizer,.fc-rtl .fc-h-event .fc-start-resizer:after,.fc-rtl .fc-h-event .fc-start-resizer:before{left:auto;cursor:e-resize}.fc-day-grid-event{margin:1px 2px 0;padding:0 1px}.fc-day-grid-event .fc-content{white-space:nowrap;overflow:hidden}.fc-day-grid-event .fc-time{font-weight:700}.fc-day-grid-event .fc-resizer{left:-3px;right:-3px;width:7px}a.fc-more{margin:1px 3px;font-size:.85em;cursor:pointer;text-decoration:none}a.fc-more:hover{text-decoration:underline}.fc-limited{display:none}.fc-day-grid .fc-row{z-index:1}.fc-more-popover{z-index:2;width:220px}.fc-more-popover .fc-event-container{padding:10px}.fc-toolbar{text-align:center;margin-bottom:1em}.fc-toolbar .fc-left{float:left}.fc-toolbar .fc-right{float:right}.fc-toolbar .fc-center{display:inline-block}.fc .fc-toolbar>*>*{float:left;margin-left:.75em}.fc .fc-toolbar>*>:first-child{margin-left:0}.fc-toolbar h2{margin:0}.fc-toolbar button{position:relative}.fc-toolbar .fc-state-hover,.fc-toolbar .ui-state-hover{z-index:2}.fc-toolbar .fc-state-down{z-index:3}.fc-toolbar .fc-state-active,.fc-toolbar .ui-state-active{z-index:4}.fc-toolbar button:focus{z-index:5}.fc-view-container *,.fc-view-container :after,.fc-view-container :before{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}.fc-view,.fc-view>table{position:relative;z-index:1}.fc-basicDay-view .fc-content-skeleton,.fc-basicWeek-view .fc-content-skeleton{padding-top:1px;padding-bottom:1em}.fc-basic-view .fc-body .fc-row{min-height:4em}.fc-row.fc-rigid{overflow:hidden}.fc-row.fc-rigid .fc-content-skeleton{position:absolute;top:0;left:0;right:0}.fc-basic-view .fc-day-number,.fc-basic-view .fc-week-number{padding:0 2px}.fc-basic-view td.fc-day-number,.fc-basic-view td.fc-week-number span{padding-top:2px;padding-bottom:2px}.fc-basic-view .fc-week-number{text-align:center}.fc-basic-view .fc-week-number span{display:inline-block;min-width:1.25em}.fc-ltr .fc-basic-view .fc-day-number{text-align:right}.fc-rtl .fc-basic-view .fc-day-number{text-align:left}.fc-day-number.fc-other-month{opacity:.3;filter:alpha(opacity=30)}.fc-agenda-view .fc-day-grid{position:relative;z-index:2}.fc-agenda-view .fc-day-grid .fc-row{min-height:3em}.fc-agenda-view .fc-day-grid .fc-row .fc-content-skeleton{padding-top:1px;padding-bottom:1em}.fc .fc-axis{vertical-align:middle;padding:0 4px;white-space:nowrap}.fc-ltr .fc-axis{text-align:right}.fc-rtl .fc-axis{text-align:left}.ui-widget td.fc-axis{font-weight:400}.fc-time-grid,.fc-time-grid-container{position:relative;z-index:1}.fc-time-grid{min-height:100%}.fc-time-grid table{border:0 hidden transparent}.fc-time-grid>.fc-bg{z-index:1}.fc-time-grid .fc-slats,.fc-time-grid>hr{position:relative;z-index:2}.fc-time-grid .fc-bgevent-skeleton,.fc-time-grid .fc-content-skeleton{position:absolute;top:0;left:0;right:0}.fc-time-grid .fc-bgevent-skeleton{z-index:3}.fc-time-grid .fc-highlight-skeleton{z-index:4}.fc-time-grid .fc-content-skeleton{z-index:5}.fc-time-grid .fc-helper-skeleton{z-index:6}.fc-time-grid .fc-slats td{height:1.5em;border-bottom:0}.fc-time-grid .fc-slats .fc-minor td{border-top-style:dotted}.fc-time-grid .fc-slats .ui-widget-content{background:0 0}.fc-time-grid .fc-highlight-container{position:relative}.fc-time-grid .fc-highlight{position:absolute;left:0;right:0}.fc-time-grid .fc-bgevent-container,.fc-time-grid .fc-event-container{position:relative}.fc-ltr .fc-time-grid .fc-event-container{margin:0 2.5% 0 2px}.fc-rtl .fc-time-grid .fc-event-container{margin:0 2px 0 2.5%}.fc-time-grid .fc-bgevent,.fc-time-grid .fc-event{position:absolute;z-index:1}.fc-time-grid .fc-bgevent{left:0;right:0}.fc-v-event.fc-not-start{border-top-width:0;padding-top:1px;border-top-left-radius:0;border-top-right-radius:0}.fc-v-event.fc-not-end{border-bottom-width:0;padding-bottom:1px;border-bottom-left-radius:0;border-bottom-right-radius:0}.fc-time-grid-event{overflow:hidden}.fc-time-grid-event .fc-time,.fc-time-grid-event .fc-title{padding:0 1px}.fc-time-grid-event .fc-time{font-size:.85em;white-space:nowrap}.fc-time-grid-event.fc-short .fc-content{white-space:nowrap}.fc-time-grid-event.fc-short .fc-time,.fc-time-grid-event.fc-short .fc-title{display:inline-block;vertical-align:top}.fc-time-grid-event.fc-short .fc-time span{display:none}.fc-time-grid-event.fc-short .fc-time:before{content:attr(data-start)}.fc-time-grid-event.fc-short .fc-time:after{content:"\000A0-\000A0"}.fc-time-grid-event.fc-short .fc-title{font-size:.85em;padding:0}.fc-time-grid-event .fc-resizer{left:0;right:0;bottom:0;height:8px;overflow:hidden;line-height:8px;font-size:11px;font-family:monospace;text-align:center;cursor:s-resize}.fc-time-grid-event .fc-resizer:after{content:"="}/*! * Font Awesome 4.3.0 by @davegandy - http://fontawesome.io - @fontawesome * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) - */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.3.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.3.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.3.0') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.3.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.3.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.3.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;transform:translate(0, 0)}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-genderless:before,.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.c3 svg{font:10px sans-serif}.c3 line,.c3 path{fill:none;stroke:#000}.c3 text{-webkit-user-select:none;-moz-user-select:none;user-select:none}.c3-bars path,.c3-event-rect,.c3-legend-item-tile,.c3-xgrid-focus,.c3-ygrid{shape-rendering:crispEdges}.c3-chart-arc path{stroke:#fff}.c3-chart-arc text{fill:#fff;font-size:13px}.c3-grid line{stroke:#aaa}.c3-grid text{fill:#aaa}.c3-xgrid,.c3-ygrid{stroke-dasharray:3 3}.c3-text.c3-empty{fill:gray;font-size:2em}.c3-line{stroke-width:1px}.c3-circle._expanded_{stroke-width:1px;stroke:#fff}.c3-selected-circle{fill:#fff;stroke-width:2px}.c3-bar{stroke-width:0}.c3-bar._expanded_{fill-opacity:.75}.c3-target.c3-focused{opacity:1}.c3-target.c3-focused path.c3-line,.c3-target.c3-focused path.c3-step{stroke-width:2px}.c3-target.c3-defocused{opacity:.3!important}.c3-region{fill:#4682b4;fill-opacity:.1}.c3-brush .extent{fill-opacity:.1}.c3-legend-item{font-size:12px}.c3-legend-item-hidden{opacity:.15}.c3-legend-background{opacity:.75;fill:#fff;stroke:#d3d3d3;stroke-width:1}.c3-tooltip-container{z-index:10}.c3-tooltip{border-collapse:collapse;border-spacing:0;background-color:#fff;empty-cells:show;-webkit-box-shadow:7px 7px 12px -9px #777;-moz-box-shadow:7px 7px 12px -9px #777;box-shadow:7px 7px 12px -9px #777;opacity:.9}.c3-tooltip tr{border:1px solid #CCC}.c3-tooltip th{background-color:#aaa;font-size:14px;padding:2px 5px;text-align:left;color:#FFF}.c3-tooltip td{font-size:13px;padding:3px 6px;background-color:#fff;border-left:1px dotted #999}.c3-tooltip td>span{display:inline-block;width:10px;height:10px;margin-right:6px}.c3-tooltip td.value{text-align:right}.c3-area{stroke-width:0;opacity:.2}.c3-chart-arcs-title{dominant-baseline:middle;font-size:1.3em}.c3-chart-arcs .c3-chart-arcs-background{fill:#e0e0e0;stroke:none}.c3-chart-arcs .c3-chart-arcs-gauge-unit{fill:#000;font-size:16px}.c3-chart-arcs .c3-chart-arcs-gauge-max,.c3-chart-arcs .c3-chart-arcs-gauge-min{fill:#777}.c3-chart-arc .c3-gauge-value{fill:#000}li,ul,ol,table,tr,td,th,p,blockquote,body{margin:0;padding:0;font-size:100%}body{margin-left:10px;margin-right:10px;padding-bottom:20px;color:#333;font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;text-rendering:optimizeLegibility}.page{clear:both}ul.no-bullet li{list-style-type:none;margin-left:0}.pull-right{text-align:right}hr{border:0;height:0;border-top:1px solid rgba(0,0,0,0.1);border-bottom:1px solid rgba(255,255,255,0.3)}.chosen-select{min-height:27px}.avatar{float:left;margin-right:10px}#ui-datepicker-div{font-size:.8em}#app-loading-icon{position:fixed;right:3px;bottom:3px}a{color:#36c;border:0}a:focus{outline:0;color:#df5353;text-decoration:none;border:1px dotted #aaa}a:hover{color:#333;text-decoration:none}h1,h2,h3{font-weight:normal;color:#333}h2{font-size:1.3em;margin-bottom:10px}h3{margin-top:10px;font-size:1.2em}table{width:100%;border-collapse:collapse;border-spacing:0;margin-bottom:20px;font-size:.95em}th,td{border:1px solid #eee;padding-top:.5em;padding-bottom:.5em;padding-left:3px;padding-right:3px}td{vertical-align:top}th{background:#fbfbfb;text-align:left}td li{margin-left:20px}.table-small{font-size:.8em}th a{text-decoration:none;color:#333}th a:focus,th a:hover{text-decoration:underline}.table-fixed{table-layout:fixed;white-space:nowrap}.table-fixed th{overflow:hidden}.table-fixed td{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.table-stripped tr:nth-child(odd) td{background:#fefefe}.column-3{width:3%}.column-5{width:5%}.column-8{width:7.5%}.column-10{width:10%}.column-12{width:12%}.column-15{width:15%}.column-18{width:18%}.column-20{width:20%}.column-25{width:25%}.column-30{width:30%}.column-35{width:35%}.column-40{width:40%}.column-50{width:50%}.column-60{width:60%}.column-70{width:70%}form{margin-bottom:20px}label{cursor:pointer;display:block;margin-top:10px}input[type="number"],input[type="date"],input[type="email"],input[type="password"],input[type="text"]{color:#888;border:1px solid #ccc;width:300px;max-width:95%;font-size:100%;height:25px;padding-bottom:0;font-family:sans-serif;margin-top:10px;-webkit-appearance:none;appearance:none}input[type="number"]:focus,input[type="date"]:focus,input[type="email"]:focus,input[type="password"]:focus,input[type="text"]:focus,textarea:focus{color:#000;border-color:rgba(82,168,236,0.8);outline:0;box-shadow:0 0 8px rgba(82,168,236,0.6)}input.form-numeric,input[type="number"]{width:70px}textarea{border:1px solid #ccc;width:400px;max-width:99%;height:200px;font-size:100%;font-family:sans-serif}select{max-width:95%}select:focus{outline:0}::-webkit-input-placeholder{color:#ddd;padding-top:2px}::-ms-input-placeholder{color:#ddd;padding-top:2px}::-moz-placeholder{color:#ddd;padding-top:2px}.form-actions{padding-top:20px;clear:both}input.form-error,textarea.form-error{border:2px solid #b94a48}input.form-error:focus,textarea.form-error:focus{box-shadow:none;border:2px solid #b94a48}.form-required{color:red;padding-left:5px;font-weight:bold}.form-errors{color:#b94a48;list-style-type:none}ul.form-errors li{margin-left:0}.form-help{font-size:.8em;color:brown;margin-bottom:15px}.form-inline{padding:0;margin:0;border:0}.form-inline label{display:inline}.form-inline input,.form-inline select{margin:0;margin-right:15px}.form-inline .form-required{display:none}.form-inline-group{display:inline}input.form-datetime,input.form-date{width:150px}input.form-input-large{width:400px}.form-row{margin-top:10px;margin-bottom:20px}.form-column{float:left;padding-right:50px}.form-column:first-child{padding-left:0}.form-column ul{margin-top:15px}.form-login{width:350px;margin:0 auto;margin-top:8%}.form-column li,.form-login li{margin-left:25px;line-height:25px}.form-checkbox-group label{display:inline}label+.form-tabs{margin-top:10px}.form-tabs{width:100%;max-width:800px}.form-tabs-nav{margin-bottom:8px}.form-tabs-nav li{margin-left:0;display:inline}.form-tab{margin-right:20px}.form-tab a{color:#ccc;font-weight:bold;text-decoration:none}.form-tab a:focus,.form-tab a:hover{color:#000}.form-tab-selected a{color:#333}.preview-area{border:1px dashed #000;padding-top:5px;padding-left:5px;padding-right:5px;margin-bottom:5px;display:none;overflow:auto}.btn{-webkit-appearance:none;appearance:none;display:inline-block;color:#333;border:1px solid #ccc;background:#efefef;padding:5px;padding-left:15px;padding-right:15px;font-size:.9em;cursor:pointer;border-radius:2px}a.btn{text-decoration:none;font-weight:bold}.btn-small{padding:2px;padding-left:5px;padding-right:5px}.btn-red{border-color:#b0281a;background:#d14836;color:#fff}a.btn-red:hover,.btn-red:hover,.btn-red:focus{color:#fff;background:#c53727}a.btn-blue,.btn-blue{border-color:#3079ed;background:#4d90fe;color:#fff}a.btn-blue:hover,.btn-blue:hover,a.btn-blue:focus,.btn-blue:focus{border-color:#2f5bb7;background:#357ae8}.btn-blue:disabled{color:#ccc;border:1px solid #ccc;background:#f7f7f7}#main .alert,.page .alert{margin-top:10px}.alert{padding:8px 35px 8px 14px;margin-bottom:10px;color:#c09853;background-color:#fcf8e3;border:1px solid #fbeed5;border-radius:4px}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-normal{color:#333;background-color:#f0f0f0;border-color:#ddd}.alert ul{margin-top:10px;margin-bottom:10px}.alert li{margin-left:25px}.tooltip-arrow:after{background:#fff;border:1px solid #aaa;box-shadow:0 0 5px #aaa}div.ui-tooltip{min-width:200px;max-width:600px;font-size:.85em}.tooltip-arrow{width:20px;height:10px;overflow:hidden;position:absolute}.tooltip-arrow.top{top:-10px}.tooltip-arrow.bottom{bottom:-10px}.tooltip-arrow.align-left{left:10px}.tooltip-arrow.align-right{right:10px}.tooltip-arrow:after{content:"";position:absolute;width:14px;height:14px;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg)}.tooltip-arrow.bottom:after{top:-10px}.tooltip-arrow.top:after{bottom:-10px}.tooltip-arrow.align-left:after{left:0}.tooltip-arrow.align-right:after{right:0}.tooltip-large{width:550px}.ui-tooltip-content .markdown p{margin-bottom:0}.tooltip .fa-info-circle{color:#999;font-size:.95em}.ui-tooltip ul{margin-left:20px}header{margin-top:10px;padding-bottom:10px;border-bottom:1px solid #dedede}header h1{margin:0;padding:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:70%;float:left}header ul{text-align:right;font-size:.9em}header li{display:inline;padding-left:30px}header a{color:#777;text-decoration:none}nav .active a{color:#333;font-weight:bold}.username a{color:#000}.username a:hover{color:#df5353;text-decoration:underline}.logo{opacity:.3;color:#d40000}.logo span{color:#333}.logo:hover{opacity:.8}.logo:focus span,.logo:hover span{color:#d40000}.page-header{margin-bottom:20px}.page-header h2{margin:0;padding:0;font-size:1.4em;font-weight:bold;border-bottom:1px dotted #ccc}.page-header h2 a{color:#ddd}.page-header h2 a:focus,.page-header h2 a:hover{color:#333}.page-header ul{text-align:left;margin-top:5px;display:inline-block}.menu-inline li,.page-header li{display:inline;padding-right:10px;font-size:.95em}.menu-inline{margin-bottom:5px}@media only screen and (max-width:640px){.page-header-mobile li{display:block;margin-bottom:5px}}.public-board{margin-top:5px}.public-task{max-width:800px;margin:0 auto;margin-top:5px}#board-container{overflow-x:scroll}#board{table-layout:fixed}#board th.board-column-header{width:240px}#board td{vertical-align:top}.board-container-compact{overflow-x:initial}@media all and (-ms-high-contrast:active),(-ms-high-contrast:none){.board-container-compact #board{table-layout:auto}}#board th.board-column-header.board-column-compact{width:initial}.board-column-collapsed{display:none}td.board-column-task-collapsed{font-weight:bold;background-color:#fbfbfb}#board th.board-column-header-collapsed{width:28px;min-width:28px;text-align:center;overflow:hidden}.board-rotation-wrapper{position:relative;padding:8px 4px}.board-rotation{min-width:250px;-webkit-backface-visibility:hidden;-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg);-webkit-transform-origin:0 100%;-moz-transform-origin:0 100%;-ms-transform-origin:0 100%;transform-origin:0 100%}.board-add-icon{float:left;padding:0 5px}.board-add-icon a{text-decoration:none;color:#36c;font-size:150%;line-height:70%}.board-add-icon a:focus,.board-add-icon a:hover{text-decoration:none;color:red}.board-column-header-task-count{color:#999;font-weight:normal}th.board-column-header-collapsed .board-column-header-task-count{font-size:.85em}th.board-swimlane-header{width:120px}a.board-swimlane-toggle{font-size:.95em}.board-swimlane-toggle-title{font-size:.85em;display:none}.board-swimlane-title{vertical-align:top}.board-task-list{overflow:auto}.board-task-list-limit{background-color:#df5353}.draggable-item{cursor:pointer;user-select:none}.draggable-placeholder{border:2px dashed #000;background:#fafafa;height:70px;margin-bottom:10px}div.draggable-item-selected{border:1px solid #000}.task-board-sort-handle{float:left;padding-right:5px}.task-board{position:relative;margin-bottom:2px;border:1px solid #000;padding:2px;font-size:.85em;word-wrap:break-word}div.task-board-recent{box-shadow:2px 2px 5px rgba(0,0,0,0.25)}div.task-board-status-closed{user-select:none;border:1px dotted #555}.task-table a,.task-board a{color:#000;text-decoration:none;font-weight:bold}.task-table a:focus,.task-table a:hover,.task-board a:focus,.task-board a:hover{text-decoration:underline}.task-board-collapsed{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}a.task-board-collapsed-title{font-weight:normal}.task-board .dropdown{float:left;margin-right:5px;font-size:1.1em}.task-board-title{margin-top:5px;margin-bottom:5px;font-size:1.1em}.task-board-title a{font-weight:normal}.task-board-user{font-size:.8em}.task-board-current-user a{text-decoration:underline}.task-board-current-user a:focus,.task-board-current-user a:hover{text-decoration:none}a.task-board-nobody{font-weight:normal;font-style:italic;color:#444}.task-board-category-container{text-align:right}.task-board-category{font-weight:bold;font-size:.9em;color:#000;border:1px solid #555;padding:2px;padding-right:5px;padding-left:5px}.task-board-icons{text-align:right;margin-top:8px}.task-board-icons a{opacity:.5}.task-board-icons span{opacity:.5;margin-left:2px}.task-board-icons a:hover,.task-board-icons span:hover{opacity:1.0}.task-board-date{font-weight:bold;color:#000}span.task-board-date-overdue{color:#d90000;opacity:1.0}.task-score{font-weight:bold}.task-board .task-score{font-size:1.1em}.task-show-details .task-score{position:absolute;bottom:5px;right:5px;font-size:2em}.task-board-closed,.task-board-days{position:absolute;right:5px;top:5px;opacity:.5;font-size:.8em}.task-board-days:hover{opacity:1.0}.task-days-age{border:#666 1px solid;padding:1px 4px 1px 2px;border-top-left-radius:3px;border-bottom-left-radius:3px}.task-days-incolumn{border:#666 1px solid;border-left:0;margin-left:-5px;padding:1px 2px 1px 4px;border-top-right-radius:3px;border-bottom-right-radius:3px}.board-container-compact .task-board-days{display:none}.task-show-details{position:relative;border-radius:5px;padding-bottom:10px}.task-show-details h2{font-size:1.8em;margin:0;margin-bottom:25px;padding:0;padding-left:10px;padding-right:10px}.task-show-details li{margin-left:25px;list-style-type:circle}.task-show-section{margin-top:30px;margin-bottom:20px}.task-show-files a{font-weight:bold;text-decoration:none}.task-show-files li{margin-left:25px;list-style-type:square;line-height:25px}.task-show-file-actions{font-size:.75em}.task-show-file-actions:before{content:" ["}.task-show-file-actions:after{content:"]"}.task-show-file-actions a{color:#333}.task-show-description{border-left:4px solid #333;padding-left:20px}.task-show-description-textarea{width:99%;max-width:99%;height:300px}.task-file-viewer{position:relative}.task-file-viewer img{max-width:95%;max-height:85%;margin-top:10px}.task-time-form{margin-top:10px;margin-bottom:25px;padding:3px}.task-link-closed{text-decoration:line-through}.task-show-images{list-style-type:none}.task-show-images li img{width:100%}.task-show-images li .img_container{width:250px;height:100px;overflow:hidden}.task-show-images li{padding:10px;overflow:auto;width:250px;min-height:120px;display:inline-block;vertical-align:top}.task-show-images li p{padding:5px;font-weight:bold}.task-show-images li:hover{background:#eee}.task-show-image-actions{margin-left:5px}.task-show-file-table{width:auto}.task-show-start-link{color:#000}.task-show-start-link:hover,.task-show-start-link:focus{color:red}.flag-milestone{color:green}.comment{margin-bottom:20px}.comment:hover{background:#f7f8e0}.comment-inner{border-left:4px solid #333;padding-bottom:10px;padding-left:20px;margin-left:20px;margin-right:10px}.comment-preview{border:2px solid #000;border-radius:3px;padding:10px}.comment-preview .comment-inner{border:0;padding:0;margin:0}.comment-title{margin-bottom:8px;padding-bottom:3px;border-bottom:1px dotted #aaa}.ui-tooltip .comment-title{font-size:80%}.ui-tooltip .comment-inner{padding-bottom:0}.comment-actions{font-size:.8em;padding:0;text-align:right}.comment-actions li{display:inline;padding-left:5px;padding-right:5px;border-right:1px dotted #000}.comment-actions li:last-child{padding-right:0;border:0}.comment-username{font-weight:bold}.comment-textarea{height:200px;width:80%;max-width:800px}#comments .comment-textarea{height:80px;width:500px}.subtasks-table{font-size:.85em}.subtasks-table td{vertical-align:middle}.markdown{line-height:1.4em;font-size:1.0}.markdown h1{margin-top:5px;margin-bottom:10px;font-size:1.5em;font-weight:bold;text-decoration:underline}.markdown h2{font-size:1.2em;font-weight:bold;text-decoration:underline}.markdown h3{font-size:1.1em;text-decoration:underline}.markdown h4{font-size:1.1em;text-decoration:underline}.markdown p{margin-bottom:10px}.markdown ol,.markdown ul{margin-left:25px;margin-top:10px;margin-bottom:10px}.markdown pre{background:#fdfdfd;padding:10px;border-radius:5px;border:1px solid #ddd;overflow:auto;color:#444}.markdown blockquote{font-style:italic;border-left:3px solid #ddd;padding-left:10px;margin-bottom:10px;margin-left:20px}.markdown img{display:block;max-width:80%;margin-top:10px}.listing{border-radius:4px;padding:8px 35px 8px 14px;margin-bottom:20px;border:1px solid #ddd;color:#333;background-color:#fefefe;overflow:auto}.listing li{list-style-type:square;margin-left:20px;margin-bottom:3px}.listing ul{margin-top:15px;margin-bottom:15px}.activity-event{margin-bottom:20px}.activity-datetime{color:#999;font-size:.85em}.activity-content{margin-top:10px;margin-left:20px;padding-left:20px;border-left:2px solid #666}.activity-title{font-weight:bold;color:#000}.activity-description{font-size:.9em;color:#aaa;padding-top:5px}.activity-description ul{margin-top:10px}.activity-description li{margin-left:40px;list-style-type:circle;color:#555}.activity-description .markdown{margin-top:10px;color:#555}.activity-changes{margin-top:10px;font-size:.85em}.activity-changes ul{margin-left:25px}.dashboard-project-stats span{font-size:.75em;margin-right:10px;color:#999}.dashboard-project-stats strong{font-size:1.2em}.dashboard-table-link{font-weight:bold;color:#444;text-decoration:none}.dashboard-table-link:focus,.dashboard-table-link:hover{color:#999}.pagination{text-align:center}.pagination-next{margin-left:5px}.pagination-previous{margin-right:5px}#popover-container{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.8);overflow:auto;z-index:100}#popover-content{position:absolute;width:70%;margin:0 0 0 -35%;left:50%;top:5%;padding:15px;background:#fff;overflow:scroll;max-height:83%}#main .confirm{max-width:700px;font-size:1.1em}.sidebar-container{margin-top:10px;position:relative;clear:both}.sidebar-content{margin-left:23%;width:76%;position:absolute}.sidebar{width:20%;float:left;padding:10px;padding-top:0;border:1px solid #ddd;background:#fdfdfd;border-radius:5px}.sidebar li{list-style-type:square;margin-left:30px;line-height:1.8em}.sidebar li.active a{color:#000;font-weight:bold;text-decoration:none}.sidebar li.active a:focus,.sidebar li.active a:hover{text-decoration:underline}.sidebar-collapsed .sidebar{width:10px;padding-bottom:0;float:none}.sidebar-collapsed .sidebar-content{margin:0;margin-top:15px;width:100%}.sidebar-collapse{text-align:right}.sidebar-collapse a,.sidebar-expand a{color:#333;text-decoration:none}.sidebar-collapse a:hover,.sidebar-expand a:hover{color:#df5353}@media only screen and (max-width:1024px){.sidebar{width:25%}.sidebar-content{margin-left:30%;width:70%}}@media only screen and (max-width:767px){.sidebar{width:95%;float:none}.sidebar-content{margin:0;margin-top:15px;width:100%}}@media only screen and (max-width:1080px){div.filter-dropdowns .filters{margin-left:0}div.filter-dropdowns{display:block;margin-top:5px}}@media only screen and (max-width:1024px){li.hide-tablet,.hide-tablet{display:none}body{font-size:.85em}.form-tab{max-width:404px}.form-inline-group input[type="submit"],.form-inline-group label{display:block}.form-inline-group input[type="submit"]{margin-top:20px}td>input[type="text"]{max-width:150px}.task-time-form label{display:block}.task-time-form input[type="submit"]{margin-top:10px;display:block}.page-header .form-input-large{width:300px}}@media only screen and (max-width:1024px) and (orientation:landscape){header{padding-bottom:4px}div.chosen-container{font-size:.9em}input[type="number"],input[type="date"],input[type="email"],input[type="password"],input[type="text"]{height:18px}.page-header .form-input-large{width:300px}}@media only screen and (max-width:640px){.hide-mobile{display:none}}.dropdown{display:inline;position:relative}.dropdown ul{display:none}ul.dropdown-submenu-open{display:block;position:absolute;left:0;z-index:1000;min-width:280px;list-style:none;margin:3px 0 0 1px;padding:6px 0;background-color:#fff;border:1px solid #b2b2b2;border-radius:3px;box-shadow:0 1px 3px rgba(0,0,0,0.15)}ul.dropdown-submenu-top{bottom:0}.dropdown-submenu-open li{display:block;padding:0;padding-left:10px;padding-right:10px;margin:0;line-height:30px}.dropdown-submenu-open a{font-weight:normal}.page-header .dropdown{padding-right:10px}#screenshot-zone{position:relative;border:2px dashed #ccc;width:90%;height:250px;overflow:auto}#screenshot-inner{position:absolute;left:0;bottom:48%;width:100%;text-align:center}#screenshot-zone.screenshot-pasted{border:2px solid #333}.toolbar{font-size:.9em;padding-top:5px}.views{display:inline-block;margin-right:10px}.views li{border:1px solid #eee;padding-left:12px;padding-right:12px;padding-top:5px;padding-bottom:5px;display:inline}.menu-inline li.active a,.views li.active a{font-weight:bold;color:#000;text-decoration:none}.views li:first-child{border-right:0;border-top-left-radius:5px;border-bottom-left-radius:5px}.views li:last-child{border-left:0;border-top-right-radius:5px;border-bottom-right-radius:5px}.filters{display:inline-block;border:1px solid #eee;border-radius:5px;padding-left:10px;padding-right:10px;padding-top:5px;padding-bottom:5px;margin-left:10px}.filters ul{font-size:.8em}.page-header .filters ul{font-size:.9em}form.search{display:inline}div.search{margin-bottom:20px}.filter-dropdowns{display:inline-block}div.ganttview-hzheader-month,div.ganttview-hzheader-day,div.ganttview-vtheader,div.ganttview-vtheader-item-name,div.ganttview-vtheader-series,div.ganttview-grid,div.ganttview-grid-row-cell{float:left}div.ganttview-hzheader-month,div.ganttview-hzheader-day{text-align:center}div.ganttview-grid-row-cell.last,div.ganttview-hzheader-day.last,div.ganttview-hzheader-month.last{border-right:0}div.ganttview{border:1px solid #999}div.ganttview-hzheader-month{width:60px;height:20px;border-right:1px solid #d0d0d0;line-height:20px;overflow:hidden}div.ganttview-hzheader-day{width:20px;height:20px;border-right:1px solid #f0f0f0;border-top:1px solid #d0d0d0;line-height:20px;color:#777}div.ganttview-vtheader{margin-top:41px;width:400px;overflow:hidden;background-color:#fff}div.ganttview-vtheader-item{color:#666}div.ganttview-vtheader-series-name{width:400px;height:31px;line-height:31px;padding-left:3px;border-top:1px solid #d0d0d0;font-size:.9em;text-overflow:ellipsis;overflow:auto;white-space:nowrap}div.ganttview-vtheader-series-name a{color:#666;text-decoration:none}div.ganttview-vtheader-series-name a:hover{color:#333;text-decoration:underline}div.ganttview-vtheader-series-name a i{color:#000}div.ganttview-vtheader-series-name a:hover i{color:#666}div.ganttview-slide-container{overflow:auto;border-left:1px solid #999}div.ganttview-grid-row-cell{width:20px;height:31px;border-right:1px solid #f0f0f0;border-top:1px solid #f0f0f0}div.ganttview-grid-row-cell.ganttview-weekend{background-color:#fafafa}div.ganttview-blocks{margin-top:40px}div.ganttview-block-container{height:28px;padding-top:4px}div.ganttview-block{position:relative;height:25px;background-color:#e5ecf9;border:1px solid silver;border-radius:3px}.ganttview-block-movable{cursor:move}div.ganttview-block-not-defined{border-color:#000;background-color:#000}div.ganttview-block-text{position:absolute;height:12px;font-size:.7em;color:#999;padding:2px 3px}div.ganttview-block div.ui-resizable-handle.ui-resizable-s{bottom:-0} \ No newline at end of file + */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.3.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.3.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.3.0') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.3.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.3.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.3.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;transform:translate(0, 0)}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-genderless:before,.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.c3 svg{font:10px sans-serif}.c3 line,.c3 path{fill:none;stroke:#000}.c3 text{-webkit-user-select:none;-moz-user-select:none;user-select:none}.c3-bars path,.c3-event-rect,.c3-legend-item-tile,.c3-xgrid-focus,.c3-ygrid{shape-rendering:crispEdges}.c3-chart-arc path{stroke:#fff}.c3-chart-arc text{fill:#fff;font-size:13px}.c3-grid line{stroke:#aaa}.c3-grid text{fill:#aaa}.c3-xgrid,.c3-ygrid{stroke-dasharray:3 3}.c3-text.c3-empty{fill:gray;font-size:2em}.c3-line{stroke-width:1px}.c3-circle._expanded_{stroke-width:1px;stroke:#fff}.c3-selected-circle{fill:#fff;stroke-width:2px}.c3-bar{stroke-width:0}.c3-bar._expanded_{fill-opacity:.75}.c3-target.c3-focused{opacity:1}.c3-target.c3-focused path.c3-line,.c3-target.c3-focused path.c3-step{stroke-width:2px}.c3-target.c3-defocused{opacity:.3!important}.c3-region{fill:#4682b4;fill-opacity:.1}.c3-brush .extent{fill-opacity:.1}.c3-legend-item{font-size:12px}.c3-legend-item-hidden{opacity:.15}.c3-legend-background{opacity:.75;fill:#fff;stroke:#d3d3d3;stroke-width:1}.c3-tooltip-container{z-index:10}.c3-tooltip{border-collapse:collapse;border-spacing:0;background-color:#fff;empty-cells:show;-webkit-box-shadow:7px 7px 12px -9px #777;-moz-box-shadow:7px 7px 12px -9px #777;box-shadow:7px 7px 12px -9px #777;opacity:.9}.c3-tooltip tr{border:1px solid #CCC}.c3-tooltip th{background-color:#aaa;font-size:14px;padding:2px 5px;text-align:left;color:#FFF}.c3-tooltip td{font-size:13px;padding:3px 6px;background-color:#fff;border-left:1px dotted #999}.c3-tooltip td>span{display:inline-block;width:10px;height:10px;margin-right:6px}.c3-tooltip td.value{text-align:right}.c3-area{stroke-width:0;opacity:.2}.c3-chart-arcs-title{dominant-baseline:middle;font-size:1.3em}.c3-chart-arcs .c3-chart-arcs-background{fill:#e0e0e0;stroke:none}.c3-chart-arcs .c3-chart-arcs-gauge-unit{fill:#000;font-size:16px}.c3-chart-arcs .c3-chart-arcs-gauge-max,.c3-chart-arcs .c3-chart-arcs-gauge-min{fill:#777}.c3-chart-arc .c3-gauge-value{fill:#000}li,ul,ol,table,tr,td,th,p,blockquote,body{margin:0;padding:0;font-size:100%}body{margin-left:10px;margin-right:10px;padding-bottom:20px;color:#333;font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;text-rendering:optimizeLegibility}.page{clear:both}ul.no-bullet li{list-style-type:none;margin-left:0}.pull-right{text-align:right}hr{border:0;height:0;border-top:1px solid rgba(0,0,0,0.1);border-bottom:1px solid rgba(255,255,255,0.3)}.chosen-select{min-height:27px}.avatar{float:left;margin-right:10px}#ui-datepicker-div{font-size:.8em}#app-loading-icon{position:fixed;right:3px;bottom:3px}a{color:#36c;border:0}a:focus{outline:0;color:#df5353;text-decoration:none;border:1px dotted #aaa}a:hover{color:#333;text-decoration:none}h1,h2,h3{font-weight:normal;color:#333}h2{font-size:1.3em;margin-bottom:10px}h3{margin-top:10px;font-size:1.2em}table{width:100%;border-collapse:collapse;border-spacing:0;margin-bottom:20px;font-size:.95em}th,td{border:1px solid #eee;padding-top:.5em;padding-bottom:.5em;padding-left:3px;padding-right:3px}td{vertical-align:top}th{background:#fbfbfb;text-align:left}td li{margin-left:20px}.table-small{font-size:.8em}th a{text-decoration:none;color:#333}th a:focus,th a:hover{text-decoration:underline}.table-fixed{table-layout:fixed;white-space:nowrap}.table-fixed th{overflow:hidden}.table-fixed td{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.table-stripped tr:nth-child(odd) td{background:#fefefe}.column-3{width:3%}.column-5{width:5%}.column-8{width:7.5%}.column-10{width:10%}.column-12{width:12%}.column-15{width:15%}.column-18{width:18%}.column-20{width:20%}.column-25{width:25%}.column-30{width:30%}.column-35{width:35%}.column-40{width:40%}.column-50{width:50%}.column-60{width:60%}.column-70{width:70%}form{margin-bottom:20px}label{cursor:pointer;display:block;margin-top:10px}input[type="number"],input[type="date"],input[type="email"],input[type="password"],input[type="text"]{color:#888;border:1px solid #ccc;width:300px;max-width:95%;font-size:100%;height:25px;padding-bottom:0;font-family:sans-serif;margin-top:10px;-webkit-appearance:none;appearance:none}input[type="number"]:focus,input[type="date"]:focus,input[type="email"]:focus,input[type="password"]:focus,input[type="text"]:focus,textarea:focus{color:#000;border-color:rgba(82,168,236,0.8);outline:0;box-shadow:0 0 8px rgba(82,168,236,0.6)}input.form-numeric,input[type="number"]{width:70px}textarea{border:1px solid #ccc;width:400px;max-width:99%;height:200px;font-size:100%;font-family:sans-serif}select{max-width:95%}select:focus{outline:0}::-webkit-input-placeholder{color:#ddd;padding-top:2px}::-ms-input-placeholder{color:#ddd;padding-top:2px}::-moz-placeholder{color:#ddd;padding-top:2px}.form-actions{padding-top:20px;clear:both}input.form-error,textarea.form-error{border:2px solid #b94a48}input.form-error:focus,textarea.form-error:focus{box-shadow:none;border:2px solid #b94a48}.form-required{color:red;padding-left:5px;font-weight:bold}.form-errors{color:#b94a48;list-style-type:none}ul.form-errors li{margin-left:0}.form-help{font-size:.8em;color:brown;margin-bottom:15px}.form-inline{padding:0;margin:0;border:0}.form-inline label{display:inline}.form-inline input,.form-inline select{margin:0;margin-right:15px}.form-inline .form-required{display:none}.form-inline-group{display:inline}input.form-datetime,input.form-date{width:150px}input.form-input-large{width:400px}.form-row{margin-top:10px;margin-bottom:20px}.form-column{float:left;padding-right:50px}.form-column:first-child{padding-left:0}.form-column ul{margin-top:15px}.form-login{width:350px;margin:0 auto;margin-top:8%}.form-column li,.form-login li{margin-left:25px;line-height:25px}.form-checkbox-group label{display:inline}label+.form-tabs{margin-top:10px}.form-tabs{width:100%;max-width:800px}.form-tabs-nav{margin-bottom:8px}.form-tabs-nav li{margin-left:0;display:inline}.form-tab{margin-right:20px}.form-tab a{color:#ccc;font-weight:bold;text-decoration:none}.form-tab a:focus,.form-tab a:hover{color:#000}.form-tab-selected a{color:#333}.preview-area{border:1px dashed #000;padding-top:5px;padding-left:5px;padding-right:5px;margin-bottom:5px;display:none;overflow:auto}.btn{-webkit-appearance:none;appearance:none;display:inline-block;color:#333;border:1px solid #ccc;background:#efefef;padding:5px;padding-left:15px;padding-right:15px;font-size:.9em;cursor:pointer;border-radius:2px}a.btn{text-decoration:none;font-weight:bold}.btn-small{padding:2px;padding-left:5px;padding-right:5px}.btn-red{border-color:#b0281a;background:#d14836;color:#fff}a.btn-red:hover,.btn-red:hover,.btn-red:focus{color:#fff;background:#c53727}a.btn-blue,.btn-blue{border-color:#3079ed;background:#4d90fe;color:#fff}a.btn-blue:hover,.btn-blue:hover,a.btn-blue:focus,.btn-blue:focus{border-color:#2f5bb7;background:#357ae8}.btn-blue:disabled{color:#ccc;border:1px solid #ccc;background:#f7f7f7}#main .alert,.page .alert{margin-top:10px}.alert{padding:8px 35px 8px 14px;margin-bottom:10px;color:#c09853;background-color:#fcf8e3;border:1px solid #fbeed5;border-radius:4px}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-normal{color:#333;background-color:#f0f0f0;border-color:#ddd}.alert ul{margin-top:10px;margin-bottom:10px}.alert li{margin-left:25px}.tooltip-arrow:after{background:#fff;border:1px solid #aaa;box-shadow:0 0 5px #aaa}div.ui-tooltip{min-width:200px;max-width:600px;font-size:.85em}.tooltip-arrow{width:20px;height:10px;overflow:hidden;position:absolute}.tooltip-arrow.top{top:-10px}.tooltip-arrow.bottom{bottom:-10px}.tooltip-arrow.align-left{left:10px}.tooltip-arrow.align-right{right:10px}.tooltip-arrow:after{content:"";position:absolute;width:14px;height:14px;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg)}.tooltip-arrow.bottom:after{top:-10px}.tooltip-arrow.top:after{bottom:-10px}.tooltip-arrow.align-left:after{left:0}.tooltip-arrow.align-right:after{right:0}.tooltip-large{width:550px}.ui-tooltip-content .markdown p{margin-bottom:0}.tooltip .fa-info-circle{color:#999;font-size:.95em}.ui-tooltip ul{margin-left:20px}header{margin-top:10px;padding-bottom:10px;border-bottom:1px solid #dedede}header h1{margin:0;padding:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:70%;float:left}header ul{text-align:right;font-size:.9em}header li{display:inline;padding-left:30px}header a{color:#777;text-decoration:none}nav .active a{color:#333;font-weight:bold}.username a{color:#000}.username a:hover{color:#df5353;text-decoration:underline}.logo{opacity:.3;color:#d40000}.logo span{color:#333}.logo:hover{opacity:.8}.logo:focus span,.logo:hover span{color:#d40000}.page-header{margin-bottom:20px}.page-header h2{margin:0;padding:0;font-size:1.4em;font-weight:bold;border-bottom:1px dotted #ccc}.page-header h2 a{color:#ddd}.page-header h2 a:focus,.page-header h2 a:hover{color:#333}.page-header ul{text-align:left;margin-top:5px;display:inline-block}.menu-inline li,.page-header li{display:inline;padding-right:10px;font-size:.95em}.menu-inline{margin-bottom:5px}@media only screen and (max-width:640px){.page-header-mobile li{display:block;margin-bottom:5px}}.public-board{margin-top:5px}.public-task{max-width:800px;margin:0 auto;margin-top:5px}#board-container{overflow-x:scroll}#board{table-layout:fixed}#board th.board-column-header{width:240px}#board td{vertical-align:top}.board-container-compact{overflow-x:initial}@media all and (-ms-high-contrast:active),(-ms-high-contrast:none){.board-container-compact #board{table-layout:auto}}#board th.board-column-header.board-column-compact{width:initial}.board-column-collapsed{display:none}td.board-column-task-collapsed{font-weight:bold;background-color:#fbfbfb}#board th.board-column-header-collapsed{width:28px;min-width:28px;text-align:center;overflow:hidden}.board-rotation-wrapper{position:relative;padding:8px 4px}.board-rotation{min-width:250px;-webkit-backface-visibility:hidden;-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg);-webkit-transform-origin:0 100%;-moz-transform-origin:0 100%;-ms-transform-origin:0 100%;transform-origin:0 100%}.board-add-icon{float:left;padding:0 5px}.board-add-icon a{text-decoration:none;color:#36c;font-size:150%;line-height:70%}.board-add-icon a:focus,.board-add-icon a:hover{text-decoration:none;color:red}.board-column-header-task-count{color:#999;font-weight:normal}th.board-column-header-collapsed .board-column-header-task-count{font-size:.85em}th.board-swimlane-header{width:120px}a.board-swimlane-toggle{font-size:.95em}.board-swimlane-toggle-title{font-size:.85em;display:none}.board-swimlane-title{vertical-align:top}.board-task-list{overflow:auto}.board-task-list-limit{background-color:#df5353}.draggable-item{cursor:pointer;user-select:none}.draggable-placeholder{border:2px dashed #000;background:#fafafa;height:70px;margin-bottom:10px}div.draggable-item-selected{border:1px solid #000}.task-board-sort-handle{float:left;padding-right:5px}.task-board{position:relative;margin-bottom:2px;border:1px solid #000;padding:2px;font-size:.85em;word-wrap:break-word}div.task-board-recent{box-shadow:2px 2px 5px rgba(0,0,0,0.25)}div.task-board-status-closed{user-select:none;border:1px dotted #555}.task-table a,.task-board a{color:#000;text-decoration:none;font-weight:bold}.task-table a:focus,.task-table a:hover,.task-board a:focus,.task-board a:hover{text-decoration:underline}.task-board-collapsed{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}a.task-board-collapsed-title{font-weight:normal}.task-board .dropdown{float:left;margin-right:5px;font-size:1.1em}.task-board-title{margin-top:5px;margin-bottom:5px;font-size:1.1em}.task-board-title a{font-weight:normal}.task-board-user{font-size:.8em}.task-board-current-user a{text-decoration:underline}.task-board-current-user a:focus,.task-board-current-user a:hover{text-decoration:none}a.task-board-nobody{font-weight:normal;font-style:italic;color:#444}.task-board-category-container{text-align:right}.task-board-category{font-weight:bold;font-size:.9em;color:#000;border:1px solid #555;padding:2px;padding-right:5px;padding-left:5px}.task-board-icons{text-align:right;margin-top:8px}.task-board-icons a{opacity:.5}.task-board-icons span{opacity:.5;margin-left:2px}.task-board-icons a:hover,.task-board-icons span:hover{opacity:1.0}.task-board-date{font-weight:bold;color:#000}span.task-board-date-overdue{color:#d90000;opacity:1.0}.task-score{font-weight:bold}.task-board .task-score{font-size:1.1em}.task-show-details .task-score{position:absolute;bottom:5px;right:5px;font-size:2em}.task-board-closed,.task-board-days{position:absolute;right:5px;top:5px;opacity:.5;font-size:.8em}.task-board-days:hover{opacity:1.0}.task-days-age{border:#666 1px solid;padding:1px 4px 1px 2px;border-top-left-radius:3px;border-bottom-left-radius:3px}.task-days-incolumn{border:#666 1px solid;border-left:0;margin-left:-5px;padding:1px 2px 1px 4px;border-top-right-radius:3px;border-bottom-right-radius:3px}.board-container-compact .task-board-days{display:none}.task-show-details{position:relative;border-radius:5px;padding-bottom:10px}.task-show-details h2{font-size:1.8em;margin:0;margin-bottom:25px;padding:0;padding-left:10px;padding-right:10px}.task-show-details li{margin-left:25px;list-style-type:circle}.task-show-section{margin-top:30px;margin-bottom:20px}.task-show-files a{font-weight:bold;text-decoration:none}.task-show-files li{margin-left:25px;list-style-type:square;line-height:25px}.task-show-file-actions{font-size:.75em}.task-show-file-actions:before{content:" ["}.task-show-file-actions:after{content:"]"}.task-show-file-actions a{color:#333}.task-show-description{border-left:4px solid #333;padding-left:20px}.task-show-description-textarea{width:99%;max-width:99%;height:300px}.task-file-viewer{position:relative}.task-file-viewer img{max-width:95%;max-height:85%;margin-top:10px}.task-time-form{margin-top:10px;margin-bottom:25px;padding:3px}.task-link-closed{text-decoration:line-through}.task-show-images{list-style-type:none}.task-show-images li img{width:100%}.task-show-images li .img_container{width:250px;height:100px;overflow:hidden}.task-show-images li{padding:10px;overflow:auto;width:250px;min-height:120px;display:inline-block;vertical-align:top}.task-show-images li p{padding:5px;font-weight:bold}.task-show-images li:hover{background:#eee}.task-show-image-actions{margin-left:5px}.task-show-file-table{width:auto}.task-show-start-link{color:#000}.task-show-start-link:hover,.task-show-start-link:focus{color:red}.flag-milestone{color:green}.comment{margin-bottom:20px}.comment:hover{background:#f7f8e0}.comment-inner{border-left:4px solid #333;padding-bottom:10px;padding-left:20px;margin-left:20px;margin-right:10px}.comment-preview{border:2px solid #000;border-radius:3px;padding:10px}.comment-preview .comment-inner{border:0;padding:0;margin:0}.comment-title{margin-bottom:8px;padding-bottom:3px;border-bottom:1px dotted #aaa}.ui-tooltip .comment-title{font-size:80%}.ui-tooltip .comment-inner{padding-bottom:0}.comment-actions{font-size:.8em;padding:0;text-align:right}.comment-actions li{display:inline;padding-left:5px;padding-right:5px;border-right:1px dotted #000}.comment-actions li:last-child{padding-right:0;border:0}.comment-username{font-weight:bold}.comment-textarea{height:200px;width:80%;max-width:800px}#comments .comment-textarea{height:80px;width:500px}.subtasks-table{font-size:.85em}.subtasks-table td{vertical-align:middle}.markdown{line-height:1.4em;font-size:1.0}.markdown h1{margin-top:5px;margin-bottom:10px;font-size:1.5em;font-weight:bold;text-decoration:underline}.markdown h2{font-size:1.2em;font-weight:bold;text-decoration:underline}.markdown h3{font-size:1.1em;text-decoration:underline}.markdown h4{font-size:1.1em;text-decoration:underline}.markdown p{margin-bottom:10px}.markdown ol,.markdown ul{margin-left:25px;margin-top:10px;margin-bottom:10px}.markdown pre{background:#fbfbfb;padding:10px;border-radius:5px;border:1px solid #ddd;overflow:auto;color:#444}.markdown blockquote{font-style:italic;border-left:3px solid #ddd;padding-left:10px;margin-bottom:10px;margin-left:20px}.markdown img{display:block;max-width:80%;margin-top:10px}.documentation{margin:0 auto;padding:20px;max-width:850px;background:#fefefe;border:1px solid #ccc;border-radius:5px;font-size:1.0;color:#555}.documentation img{border:1px solid #333}.documentation h1{text-decoration:none;font-size:1.8em;margin-bottom:30px}.documentation h2{font-size:1.3em;text-decoration:none;border-bottom:1px solid #ccc;margin-bottom:25px}.listing{border-radius:4px;padding:8px 35px 8px 14px;margin-bottom:20px;border:1px solid #ddd;color:#333;background-color:#fefefe;overflow:auto}.listing li{list-style-type:square;margin-left:20px;margin-bottom:3px}.listing ul{margin-top:15px;margin-bottom:15px}.activity-event{margin-bottom:20px}.activity-datetime{color:#999;font-size:.85em}.activity-content{margin-top:10px;margin-left:20px;padding-left:20px;border-left:2px solid #666}.activity-title{font-weight:bold;color:#000}.activity-description{font-size:.9em;color:#aaa;padding-top:5px}.activity-description ul{margin-top:10px}.activity-description li{margin-left:40px;list-style-type:circle;color:#555}.activity-description .markdown{margin-top:10px;color:#555}.activity-changes{margin-top:10px;font-size:.85em}.activity-changes ul{margin-left:25px}.dashboard-project-stats span{font-size:.75em;margin-right:10px;color:#999}.dashboard-project-stats strong{font-size:1.2em}.dashboard-table-link{font-weight:bold;color:#444;text-decoration:none}.dashboard-table-link:focus,.dashboard-table-link:hover{color:#999}.pagination{text-align:center}.pagination-next{margin-left:5px}.pagination-previous{margin-right:5px}#popover-container{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.8);overflow:auto;z-index:100}#popover-content{position:absolute;width:70%;margin:0 0 0 -35%;left:50%;top:5%;padding:15px;background:#fff;overflow:scroll;max-height:83%}#main .confirm{max-width:700px;font-size:1.1em}.sidebar-container{margin-top:10px;position:relative;clear:both}.sidebar-content{margin-left:23%;width:76%;position:absolute}.sidebar{width:20%;float:left;padding:10px;padding-top:0;border:1px solid #ddd;background:#fdfdfd;border-radius:5px}.sidebar li{list-style-type:square;margin-left:30px;line-height:1.8em}.sidebar li.active a{color:#000;font-weight:bold;text-decoration:none}.sidebar li.active a:focus,.sidebar li.active a:hover{text-decoration:underline}.sidebar-collapsed .sidebar{width:10px;padding-bottom:0;float:none}.sidebar-collapsed .sidebar-content{margin:0;margin-top:15px;width:100%}.sidebar-collapse{text-align:right}.sidebar-collapse a,.sidebar-expand a{color:#333;text-decoration:none}.sidebar-collapse a:hover,.sidebar-expand a:hover{color:#df5353}@media only screen and (max-width:1024px){.sidebar{width:25%}.sidebar-content{margin-left:30%;width:70%}}@media only screen and (max-width:767px){.sidebar{width:95%;float:none}.sidebar-content{margin:0;margin-top:15px;width:100%}}@media only screen and (max-width:1080px){div.filter-dropdowns .filters{margin-left:0}div.filter-dropdowns{display:block;margin-top:5px}}@media only screen and (max-width:1024px){li.hide-tablet,.hide-tablet{display:none}body{font-size:.85em}.form-tab{max-width:404px}.form-inline-group input[type="submit"],.form-inline-group label{display:block}.form-inline-group input[type="submit"]{margin-top:20px}td>input[type="text"]{max-width:150px}.task-time-form label{display:block}.task-time-form input[type="submit"]{margin-top:10px;display:block}.page-header .form-input-large{width:300px}}@media only screen and (max-width:1024px) and (orientation:landscape){header{padding-bottom:4px}div.chosen-container{font-size:.9em}input[type="number"],input[type="date"],input[type="email"],input[type="password"],input[type="text"]{height:18px}.page-header .form-input-large{width:300px}}@media only screen and (max-width:640px){.hide-mobile{display:none}}.dropdown{display:inline;position:relative}.dropdown ul{display:none}ul.dropdown-submenu-open{display:block;position:absolute;left:0;z-index:1000;min-width:280px;list-style:none;margin:3px 0 0 1px;padding:6px 0;background-color:#fff;border:1px solid #b2b2b2;border-radius:3px;box-shadow:0 1px 3px rgba(0,0,0,0.15)}ul.dropdown-submenu-top{bottom:0}.dropdown-submenu-open li{display:block;padding:0;padding-left:10px;padding-right:10px;margin:0;line-height:30px}.dropdown-submenu-open a{font-weight:normal}.page-header .dropdown{padding-right:10px}#screenshot-zone{position:relative;border:2px dashed #ccc;width:90%;height:250px;overflow:auto}#screenshot-inner{position:absolute;left:0;bottom:48%;width:100%;text-align:center}#screenshot-zone.screenshot-pasted{border:2px solid #333}.toolbar{font-size:.9em;padding-top:5px}.views{display:inline-block;margin-right:10px}.views li{border:1px solid #eee;padding-left:12px;padding-right:12px;padding-top:5px;padding-bottom:5px;display:inline}.menu-inline li.active a,.views li.active a{font-weight:bold;color:#000;text-decoration:none}.views li:first-child{border-right:0;border-top-left-radius:5px;border-bottom-left-radius:5px}.views li:last-child{border-left:0;border-top-right-radius:5px;border-bottom-right-radius:5px}.filters{display:inline-block;border:1px solid #eee;border-radius:5px;padding-left:10px;padding-right:10px;padding-top:5px;padding-bottom:5px;margin-left:10px}.filters ul{font-size:.8em}.page-header .filters ul{font-size:.9em}form.search{display:inline}div.search{margin-bottom:20px}.filter-dropdowns{display:inline-block}div.ganttview-hzheader-month,div.ganttview-hzheader-day,div.ganttview-vtheader,div.ganttview-vtheader-item-name,div.ganttview-vtheader-series,div.ganttview-grid,div.ganttview-grid-row-cell{float:left}div.ganttview-hzheader-month,div.ganttview-hzheader-day{text-align:center}div.ganttview-grid-row-cell.last,div.ganttview-hzheader-day.last,div.ganttview-hzheader-month.last{border-right:0}div.ganttview{border:1px solid #999}div.ganttview-hzheader-month{width:60px;height:20px;border-right:1px solid #d0d0d0;line-height:20px;overflow:hidden}div.ganttview-hzheader-day{width:20px;height:20px;border-right:1px solid #f0f0f0;border-top:1px solid #d0d0d0;line-height:20px;color:#777}div.ganttview-vtheader{margin-top:41px;width:400px;overflow:hidden;background-color:#fff}div.ganttview-vtheader-item{color:#666}div.ganttview-vtheader-series-name{width:400px;height:31px;line-height:31px;padding-left:3px;border-top:1px solid #d0d0d0;font-size:.9em;text-overflow:ellipsis;overflow:auto;white-space:nowrap}div.ganttview-vtheader-series-name a{color:#666;text-decoration:none}div.ganttview-vtheader-series-name a:hover{color:#333;text-decoration:underline}div.ganttview-vtheader-series-name a i{color:#000}div.ganttview-vtheader-series-name a:hover i{color:#666}div.ganttview-slide-container{overflow:auto;border-left:1px solid #999}div.ganttview-grid-row-cell{width:20px;height:31px;border-right:1px solid #f0f0f0;border-top:1px solid #f0f0f0}div.ganttview-grid-row-cell.ganttview-weekend{background-color:#fafafa}div.ganttview-blocks{margin-top:40px}div.ganttview-block-container{height:28px;padding-top:4px}div.ganttview-block{position:relative;height:25px;background-color:#e5ecf9;border:1px solid silver;border-radius:3px}.ganttview-block-movable{cursor:move}div.ganttview-block-not-defined{border-color:#000;background-color:#000}div.ganttview-block-text{position:absolute;height:12px;font-size:.7em;color:#999;padding:2px 3px}div.ganttview-block div.ui-resizable-handle.ui-resizable-s{bottom:-0} \ No newline at end of file diff --git a/assets/css/print.css b/assets/css/print.css index 67b2ce1a..404ee87c 100644 --- a/assets/css/print.css +++ b/assets/css/print.css @@ -17,4 +17,4 @@ */.fc{direction:ltr;text-align:left}.fc-rtl{text-align:right}body .fc{font-size:1em}.fc-unthemed .fc-divider,.fc-unthemed .fc-popover,.fc-unthemed .fc-row,.fc-unthemed tbody,.fc-unthemed td,.fc-unthemed th,.fc-unthemed thead{border-color:#ddd}.fc-unthemed .fc-popover{background-color:#fff}.fc-unthemed .fc-divider,.fc-unthemed .fc-popover .fc-header{background:#eee}.fc-unthemed .fc-popover .fc-header .fc-close{color:#666}.fc-unthemed .fc-today{background:#fcf8e3}.fc-highlight{background:#bce8f1;opacity:.3;filter:alpha(opacity=30)}.fc-bgevent{background:#8fdf82;opacity:.3;filter:alpha(opacity=30)}.fc-nonbusiness{background:#d7d7d7}.fc-icon{display:inline-block;width:1em;height:1em;line-height:1em;font-size:1em;text-align:center;overflow:hidden;font-family:"Courier New",Courier,monospace;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.fc-icon:after{position:relative;margin:0 -1em}.fc-icon-left-single-arrow:after{content:"\02039";font-weight:700;font-size:200%;top:-7%;left:3%}.fc-icon-right-single-arrow:after{content:"\0203A";font-weight:700;font-size:200%;top:-7%;left:-3%}.fc-icon-left-double-arrow:after{content:"\000AB";font-size:160%;top:-7%}.fc-icon-right-double-arrow:after{content:"\000BB";font-size:160%;top:-7%}.fc-icon-left-triangle:after{content:"\25C4";font-size:125%;top:3%;left:-2%}.fc-icon-right-triangle:after{content:"\25BA";font-size:125%;top:3%;left:2%}.fc-icon-down-triangle:after{content:"\25BC";font-size:125%;top:2%}.fc-icon-x:after{content:"\000D7";font-size:200%;top:6%}.fc button{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;margin:0;height:2.1em;padding:0 .6em;font-size:1em;white-space:nowrap;cursor:pointer}.fc button::-moz-focus-inner{margin:0;padding:0}.fc-state-default{border:1px solid}.fc-state-default.fc-corner-left{border-top-left-radius:4px;border-bottom-left-radius:4px}.fc-state-default.fc-corner-right{border-top-right-radius:4px;border-bottom-right-radius:4px}.fc button .fc-icon{position:relative;top:-.05em;margin:0 .2em;vertical-align:middle}.fc-state-default{background-color:#f5f5f5;background-image:-moz-linear-gradient(top,#fff,#e6e6e6);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6));background-image:-webkit-linear-gradient(top,#fff,#e6e6e6);background-image:-o-linear-gradient(top,#fff,#e6e6e6);background-image:linear-gradient(to bottom,#fff,#e6e6e6);background-repeat:repeat-x;border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25);color:#333;text-shadow:0 1px 1px rgba(255,255,255,.75);box-shadow:inset 0 1px 0 rgba(255,255,255,.2),0 1px 2px rgba(0,0,0,.05)}.fc-state-active,.fc-state-disabled,.fc-state-down,.fc-state-hover{color:#333;background-color:#e6e6e6}.fc-state-hover{color:#333;text-decoration:none;background-position:0 -15px;-webkit-transition:background-position .1s linear;-moz-transition:background-position .1s linear;-o-transition:background-position .1s linear;transition:background-position .1s linear}.fc-state-active,.fc-state-down{background-color:#ccc;background-image:none;box-shadow:inset 0 2px 4px rgba(0,0,0,.15),0 1px 2px rgba(0,0,0,.05)}.fc-state-disabled{cursor:default;background-image:none;opacity:.65;filter:alpha(opacity=65);box-shadow:none}.fc-button-group{display:inline-block}.fc .fc-button-group>*{float:left;margin:0 0 0 -1px}.fc .fc-button-group>:first-child{margin-left:0}.fc-popover{position:absolute;box-shadow:0 2px 6px rgba(0,0,0,.15)}.fc-popover .fc-header{padding:2px 4px}.fc-popover .fc-header .fc-title{margin:0 2px}.fc-popover .fc-header .fc-close{cursor:pointer}.fc-ltr .fc-popover .fc-header .fc-title,.fc-rtl .fc-popover .fc-header .fc-close{float:left}.fc-ltr .fc-popover .fc-header .fc-close,.fc-rtl .fc-popover .fc-header .fc-title{float:right}.fc-unthemed .fc-popover{border-width:1px;border-style:solid}.fc-unthemed .fc-popover .fc-header .fc-close{font-size:.9em;margin-top:2px}.fc-popover>.ui-widget-header+.ui-widget-content{border-top:0}.fc-divider{border-style:solid;border-width:1px}hr.fc-divider{height:0;margin:0;padding:0 0 2px;border-width:1px 0}.fc-clear{clear:both}.fc-bg,.fc-bgevent-skeleton,.fc-helper-skeleton,.fc-highlight-skeleton{position:absolute;top:0;left:0;right:0}.fc-bg{bottom:0}.fc-bg table{height:100%}.fc table{width:100%;table-layout:fixed;border-collapse:collapse;border-spacing:0;font-size:1em}.fc th{text-align:center}.fc td,.fc th{border-style:solid;border-width:1px;padding:0;vertical-align:top}.fc td.fc-today{border-style:double}.fc .fc-row{border-style:solid;border-width:0}.fc-row table{border-left:0 hidden transparent;border-right:0 hidden transparent;border-bottom:0 hidden transparent}.fc-row:first-child table{border-top:0 hidden transparent}.fc-row{position:relative}.fc-row .fc-bg{z-index:1}.fc-row .fc-bgevent-skeleton,.fc-row .fc-highlight-skeleton{bottom:0}.fc-row .fc-bgevent-skeleton table,.fc-row .fc-highlight-skeleton table{height:100%}.fc-row .fc-bgevent-skeleton td,.fc-row .fc-highlight-skeleton td{border-color:transparent}.fc-row .fc-bgevent-skeleton{z-index:2}.fc-row .fc-highlight-skeleton{z-index:3}.fc-row .fc-content-skeleton{position:relative;z-index:4;padding-bottom:2px}.fc-row .fc-helper-skeleton{z-index:5}.fc-row .fc-content-skeleton td,.fc-row .fc-helper-skeleton td{background:0 0;border-color:transparent;border-bottom:0}.fc-row .fc-content-skeleton tbody td,.fc-row .fc-helper-skeleton tbody td{border-top:0}.fc-scroller{overflow-y:scroll;overflow-x:hidden}.fc-scroller>*{position:relative;width:100%;overflow:hidden}.fc-event{position:relative;display:block;font-size:.85em;line-height:1.3;border-radius:3px;border:1px solid #3a87ad;background-color:#3a87ad;font-weight:400}.fc-event,.fc-event:hover,.ui-widget .fc-event{color:#fff;text-decoration:none}.fc-event.fc-draggable,.fc-event[href]{cursor:pointer}.fc-not-allowed,.fc-not-allowed .fc-event{cursor:not-allowed}.fc-event .fc-bg{z-index:1;background:#fff;opacity:.25;filter:alpha(opacity=25)}.fc-event .fc-content{position:relative;z-index:2}.fc-event .fc-resizer{position:absolute;z-index:3}.fc-ltr .fc-h-event.fc-not-start,.fc-rtl .fc-h-event.fc-not-end{margin-left:0;border-left-width:0;padding-left:1px;border-top-left-radius:0;border-bottom-left-radius:0}.fc-ltr .fc-h-event.fc-not-end,.fc-rtl .fc-h-event.fc-not-start{margin-right:0;border-right-width:0;padding-right:1px;border-top-right-radius:0;border-bottom-right-radius:0}.fc-h-event .fc-resizer{top:-1px;bottom:-1px;left:-1px;right:-1px;width:5px}.fc-ltr .fc-h-event .fc-start-resizer,.fc-ltr .fc-h-event .fc-start-resizer:after,.fc-ltr .fc-h-event .fc-start-resizer:before,.fc-rtl .fc-h-event .fc-end-resizer,.fc-rtl .fc-h-event .fc-end-resizer:after,.fc-rtl .fc-h-event .fc-end-resizer:before{right:auto;cursor:w-resize}.fc-ltr .fc-h-event .fc-end-resizer,.fc-ltr .fc-h-event .fc-end-resizer:after,.fc-ltr .fc-h-event .fc-end-resizer:before,.fc-rtl .fc-h-event .fc-start-resizer,.fc-rtl .fc-h-event .fc-start-resizer:after,.fc-rtl .fc-h-event .fc-start-resizer:before{left:auto;cursor:e-resize}.fc-day-grid-event{margin:1px 2px 0;padding:0 1px}.fc-day-grid-event .fc-content{white-space:nowrap;overflow:hidden}.fc-day-grid-event .fc-time{font-weight:700}.fc-day-grid-event .fc-resizer{left:-3px;right:-3px;width:7px}a.fc-more{margin:1px 3px;font-size:.85em;cursor:pointer;text-decoration:none}a.fc-more:hover{text-decoration:underline}.fc-limited{display:none}.fc-day-grid .fc-row{z-index:1}.fc-more-popover{z-index:2;width:220px}.fc-more-popover .fc-event-container{padding:10px}.fc-toolbar{text-align:center;margin-bottom:1em}.fc-toolbar .fc-left{float:left}.fc-toolbar .fc-right{float:right}.fc-toolbar .fc-center{display:inline-block}.fc .fc-toolbar>*>*{float:left;margin-left:.75em}.fc .fc-toolbar>*>:first-child{margin-left:0}.fc-toolbar h2{margin:0}.fc-toolbar button{position:relative}.fc-toolbar .fc-state-hover,.fc-toolbar .ui-state-hover{z-index:2}.fc-toolbar .fc-state-down{z-index:3}.fc-toolbar .fc-state-active,.fc-toolbar .ui-state-active{z-index:4}.fc-toolbar button:focus{z-index:5}.fc-view-container *,.fc-view-container :after,.fc-view-container :before{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}.fc-view,.fc-view>table{position:relative;z-index:1}.fc-basicDay-view .fc-content-skeleton,.fc-basicWeek-view .fc-content-skeleton{padding-top:1px;padding-bottom:1em}.fc-basic-view .fc-body .fc-row{min-height:4em}.fc-row.fc-rigid{overflow:hidden}.fc-row.fc-rigid .fc-content-skeleton{position:absolute;top:0;left:0;right:0}.fc-basic-view .fc-day-number,.fc-basic-view .fc-week-number{padding:0 2px}.fc-basic-view td.fc-day-number,.fc-basic-view td.fc-week-number span{padding-top:2px;padding-bottom:2px}.fc-basic-view .fc-week-number{text-align:center}.fc-basic-view .fc-week-number span{display:inline-block;min-width:1.25em}.fc-ltr .fc-basic-view .fc-day-number{text-align:right}.fc-rtl .fc-basic-view .fc-day-number{text-align:left}.fc-day-number.fc-other-month{opacity:.3;filter:alpha(opacity=30)}.fc-agenda-view .fc-day-grid{position:relative;z-index:2}.fc-agenda-view .fc-day-grid .fc-row{min-height:3em}.fc-agenda-view .fc-day-grid .fc-row .fc-content-skeleton{padding-top:1px;padding-bottom:1em}.fc .fc-axis{vertical-align:middle;padding:0 4px;white-space:nowrap}.fc-ltr .fc-axis{text-align:right}.fc-rtl .fc-axis{text-align:left}.ui-widget td.fc-axis{font-weight:400}.fc-time-grid,.fc-time-grid-container{position:relative;z-index:1}.fc-time-grid{min-height:100%}.fc-time-grid table{border:0 hidden transparent}.fc-time-grid>.fc-bg{z-index:1}.fc-time-grid .fc-slats,.fc-time-grid>hr{position:relative;z-index:2}.fc-time-grid .fc-bgevent-skeleton,.fc-time-grid .fc-content-skeleton{position:absolute;top:0;left:0;right:0}.fc-time-grid .fc-bgevent-skeleton{z-index:3}.fc-time-grid .fc-highlight-skeleton{z-index:4}.fc-time-grid .fc-content-skeleton{z-index:5}.fc-time-grid .fc-helper-skeleton{z-index:6}.fc-time-grid .fc-slats td{height:1.5em;border-bottom:0}.fc-time-grid .fc-slats .fc-minor td{border-top-style:dotted}.fc-time-grid .fc-slats .ui-widget-content{background:0 0}.fc-time-grid .fc-highlight-container{position:relative}.fc-time-grid .fc-highlight{position:absolute;left:0;right:0}.fc-time-grid .fc-bgevent-container,.fc-time-grid .fc-event-container{position:relative}.fc-ltr .fc-time-grid .fc-event-container{margin:0 2.5% 0 2px}.fc-rtl .fc-time-grid .fc-event-container{margin:0 2px 0 2.5%}.fc-time-grid .fc-bgevent,.fc-time-grid .fc-event{position:absolute;z-index:1}.fc-time-grid .fc-bgevent{left:0;right:0}.fc-v-event.fc-not-start{border-top-width:0;padding-top:1px;border-top-left-radius:0;border-top-right-radius:0}.fc-v-event.fc-not-end{border-bottom-width:0;padding-bottom:1px;border-bottom-left-radius:0;border-bottom-right-radius:0}.fc-time-grid-event{overflow:hidden}.fc-time-grid-event .fc-time,.fc-time-grid-event .fc-title{padding:0 1px}.fc-time-grid-event .fc-time{font-size:.85em;white-space:nowrap}.fc-time-grid-event.fc-short .fc-content{white-space:nowrap}.fc-time-grid-event.fc-short .fc-time,.fc-time-grid-event.fc-short .fc-title{display:inline-block;vertical-align:top}.fc-time-grid-event.fc-short .fc-time span{display:none}.fc-time-grid-event.fc-short .fc-time:before{content:attr(data-start)}.fc-time-grid-event.fc-short .fc-time:after{content:"\000A0-\000A0"}.fc-time-grid-event.fc-short .fc-title{font-size:.85em;padding:0}.fc-time-grid-event .fc-resizer{left:0;right:0;bottom:0;height:8px;overflow:hidden;line-height:8px;font-size:11px;font-family:monospace;text-align:center;cursor:s-resize}.fc-time-grid-event .fc-resizer:after{content:"="}/*! * Font Awesome 4.3.0 by @davegandy - http://fontawesome.io - @fontawesome * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) - */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.3.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.3.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.3.0') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.3.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.3.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.3.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;transform:translate(0, 0)}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-genderless:before,.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.c3 svg{font:10px sans-serif}.c3 line,.c3 path{fill:none;stroke:#000}.c3 text{-webkit-user-select:none;-moz-user-select:none;user-select:none}.c3-bars path,.c3-event-rect,.c3-legend-item-tile,.c3-xgrid-focus,.c3-ygrid{shape-rendering:crispEdges}.c3-chart-arc path{stroke:#fff}.c3-chart-arc text{fill:#fff;font-size:13px}.c3-grid line{stroke:#aaa}.c3-grid text{fill:#aaa}.c3-xgrid,.c3-ygrid{stroke-dasharray:3 3}.c3-text.c3-empty{fill:gray;font-size:2em}.c3-line{stroke-width:1px}.c3-circle._expanded_{stroke-width:1px;stroke:#fff}.c3-selected-circle{fill:#fff;stroke-width:2px}.c3-bar{stroke-width:0}.c3-bar._expanded_{fill-opacity:.75}.c3-target.c3-focused{opacity:1}.c3-target.c3-focused path.c3-line,.c3-target.c3-focused path.c3-step{stroke-width:2px}.c3-target.c3-defocused{opacity:.3!important}.c3-region{fill:#4682b4;fill-opacity:.1}.c3-brush .extent{fill-opacity:.1}.c3-legend-item{font-size:12px}.c3-legend-item-hidden{opacity:.15}.c3-legend-background{opacity:.75;fill:#fff;stroke:#d3d3d3;stroke-width:1}.c3-tooltip-container{z-index:10}.c3-tooltip{border-collapse:collapse;border-spacing:0;background-color:#fff;empty-cells:show;-webkit-box-shadow:7px 7px 12px -9px #777;-moz-box-shadow:7px 7px 12px -9px #777;box-shadow:7px 7px 12px -9px #777;opacity:.9}.c3-tooltip tr{border:1px solid #CCC}.c3-tooltip th{background-color:#aaa;font-size:14px;padding:2px 5px;text-align:left;color:#FFF}.c3-tooltip td{font-size:13px;padding:3px 6px;background-color:#fff;border-left:1px dotted #999}.c3-tooltip td>span{display:inline-block;width:10px;height:10px;margin-right:6px}.c3-tooltip td.value{text-align:right}.c3-area{stroke-width:0;opacity:.2}.c3-chart-arcs-title{dominant-baseline:middle;font-size:1.3em}.c3-chart-arcs .c3-chart-arcs-background{fill:#e0e0e0;stroke:none}.c3-chart-arcs .c3-chart-arcs-gauge-unit{fill:#000;font-size:16px}.c3-chart-arcs .c3-chart-arcs-gauge-max,.c3-chart-arcs .c3-chart-arcs-gauge-min{fill:#777}.c3-chart-arc .c3-gauge-value{fill:#000}header,.sidebar,.form-comment,.page-header{display:none}a{color:#36c;border:0}a:focus{outline:0;color:#df5353;text-decoration:none;border:1px dotted #aaa}a:hover{color:#333;text-decoration:none}table{width:100%;border-collapse:collapse;border-spacing:0;margin-bottom:20px;font-size:.95em}th,td{border:1px solid #eee;padding-top:.5em;padding-bottom:.5em;padding-left:3px;padding-right:3px}td{vertical-align:top}th{background:#fbfbfb;text-align:left}td li{margin-left:20px}.table-small{font-size:.8em}th a{text-decoration:none;color:#333}th a:focus,th a:hover{text-decoration:underline}.table-fixed{table-layout:fixed;white-space:nowrap}.table-fixed th{overflow:hidden}.table-fixed td{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.table-stripped tr:nth-child(odd) td{background:#fefefe}.column-3{width:3%}.column-5{width:5%}.column-8{width:7.5%}.column-10{width:10%}.column-12{width:12%}.column-15{width:15%}.column-18{width:18%}.column-20{width:20%}.column-25{width:25%}.column-30{width:30%}.column-35{width:35%}.column-40{width:40%}.column-50{width:50%}.column-60{width:60%}.column-70{width:70%}.public-board{margin-top:5px}.public-task{max-width:800px;margin:0 auto;margin-top:5px}#board-container{overflow-x:scroll}#board{table-layout:fixed}#board th.board-column-header{width:240px}#board td{vertical-align:top}.board-container-compact{overflow-x:initial}@media all and (-ms-high-contrast:active),(-ms-high-contrast:none){.board-container-compact #board{table-layout:auto}}#board th.board-column-header.board-column-compact{width:initial}.board-column-collapsed{display:none}td.board-column-task-collapsed{font-weight:bold;background-color:#fbfbfb}#board th.board-column-header-collapsed{width:28px;min-width:28px;text-align:center;overflow:hidden}.board-rotation-wrapper{position:relative;padding:8px 4px}.board-rotation{min-width:250px;-webkit-backface-visibility:hidden;-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg);-webkit-transform-origin:0 100%;-moz-transform-origin:0 100%;-ms-transform-origin:0 100%;transform-origin:0 100%}.board-add-icon{float:left;padding:0 5px}.board-add-icon a{text-decoration:none;color:#36c;font-size:150%;line-height:70%}.board-add-icon a:focus,.board-add-icon a:hover{text-decoration:none;color:red}.board-column-header-task-count{color:#999;font-weight:normal}th.board-column-header-collapsed .board-column-header-task-count{font-size:.85em}th.board-swimlane-header{width:120px}a.board-swimlane-toggle{font-size:.95em}.board-swimlane-toggle-title{font-size:.85em;display:none}.board-swimlane-title{vertical-align:top}.board-task-list{overflow:auto}.board-task-list-limit{background-color:#df5353}.draggable-item{cursor:pointer;user-select:none}.draggable-placeholder{border:2px dashed #000;background:#fafafa;height:70px;margin-bottom:10px}div.draggable-item-selected{border:1px solid #000}.task-board-sort-handle{float:left;padding-right:5px}.task-board{position:relative;margin-bottom:2px;border:1px solid #000;padding:2px;font-size:.85em;word-wrap:break-word}div.task-board-recent{box-shadow:2px 2px 5px rgba(0,0,0,0.25)}div.task-board-status-closed{user-select:none;border:1px dotted #555}.task-table a,.task-board a{color:#000;text-decoration:none;font-weight:bold}.task-table a:focus,.task-table a:hover,.task-board a:focus,.task-board a:hover{text-decoration:underline}.task-board-collapsed{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}a.task-board-collapsed-title{font-weight:normal}.task-board .dropdown{float:left;margin-right:5px;font-size:1.1em}.task-board-title{margin-top:5px;margin-bottom:5px;font-size:1.1em}.task-board-title a{font-weight:normal}.task-board-user{font-size:.8em}.task-board-current-user a{text-decoration:underline}.task-board-current-user a:focus,.task-board-current-user a:hover{text-decoration:none}a.task-board-nobody{font-weight:normal;font-style:italic;color:#444}.task-board-category-container{text-align:right}.task-board-category{font-weight:bold;font-size:.9em;color:#000;border:1px solid #555;padding:2px;padding-right:5px;padding-left:5px}.task-board-icons{text-align:right;margin-top:8px}.task-board-icons a{opacity:.5}.task-board-icons span{opacity:.5;margin-left:2px}.task-board-icons a:hover,.task-board-icons span:hover{opacity:1.0}.task-board-date{font-weight:bold;color:#000}span.task-board-date-overdue{color:#d90000;opacity:1.0}.task-score{font-weight:bold}.task-board .task-score{font-size:1.1em}.task-show-details .task-score{position:absolute;bottom:5px;right:5px;font-size:2em}.task-board-closed,.task-board-days{position:absolute;right:5px;top:5px;opacity:.5;font-size:.8em}.task-board-days:hover{opacity:1.0}.task-days-age{border:#666 1px solid;padding:1px 4px 1px 2px;border-top-left-radius:3px;border-bottom-left-radius:3px}.task-days-incolumn{border:#666 1px solid;border-left:0;margin-left:-5px;padding:1px 2px 1px 4px;border-top-right-radius:3px;border-bottom-right-radius:3px}.board-container-compact .task-board-days{display:none}.task-show-details{position:relative;border-radius:5px;padding-bottom:10px}.task-show-details h2{font-size:1.8em;margin:0;margin-bottom:25px;padding:0;padding-left:10px;padding-right:10px}.task-show-details li{margin-left:25px;list-style-type:circle}.task-show-section{margin-top:30px;margin-bottom:20px}.task-show-files a{font-weight:bold;text-decoration:none}.task-show-files li{margin-left:25px;list-style-type:square;line-height:25px}.task-show-file-actions{font-size:.75em}.task-show-file-actions:before{content:" ["}.task-show-file-actions:after{content:"]"}.task-show-file-actions a{color:#333}.task-show-description{border-left:4px solid #333;padding-left:20px}.task-show-description-textarea{width:99%;max-width:99%;height:300px}.task-file-viewer{position:relative}.task-file-viewer img{max-width:95%;max-height:85%;margin-top:10px}.task-time-form{margin-top:10px;margin-bottom:25px;padding:3px}.task-link-closed{text-decoration:line-through}.task-show-images{list-style-type:none}.task-show-images li img{width:100%}.task-show-images li .img_container{width:250px;height:100px;overflow:hidden}.task-show-images li{padding:10px;overflow:auto;width:250px;min-height:120px;display:inline-block;vertical-align:top}.task-show-images li p{padding:5px;font-weight:bold}.task-show-images li:hover{background:#eee}.task-show-image-actions{margin-left:5px}.task-show-file-table{width:auto}.task-show-start-link{color:#000}.task-show-start-link:hover,.task-show-start-link:focus{color:red}.flag-milestone{color:green}.comment{margin-bottom:20px}.comment:hover{background:#f7f8e0}.comment-inner{border-left:4px solid #333;padding-bottom:10px;padding-left:20px;margin-left:20px;margin-right:10px}.comment-preview{border:2px solid #000;border-radius:3px;padding:10px}.comment-preview .comment-inner{border:0;padding:0;margin:0}.comment-title{margin-bottom:8px;padding-bottom:3px;border-bottom:1px dotted #aaa}.ui-tooltip .comment-title{font-size:80%}.ui-tooltip .comment-inner{padding-bottom:0}.comment-actions{font-size:.8em;padding:0;text-align:right}.comment-actions li{display:inline;padding-left:5px;padding-right:5px;border-right:1px dotted #000}.comment-actions li:last-child{padding-right:0;border:0}.comment-username{font-weight:bold}.comment-textarea{height:200px;width:80%;max-width:800px}#comments .comment-textarea{height:80px;width:500px}.subtasks-table{font-size:.85em}.subtasks-table td{vertical-align:middle}.markdown{line-height:1.4em;font-size:1.0}.markdown h1{margin-top:5px;margin-bottom:10px;font-size:1.5em;font-weight:bold;text-decoration:underline}.markdown h2{font-size:1.2em;font-weight:bold;text-decoration:underline}.markdown h3{font-size:1.1em;text-decoration:underline}.markdown h4{font-size:1.1em;text-decoration:underline}.markdown p{margin-bottom:10px}.markdown ol,.markdown ul{margin-left:25px;margin-top:10px;margin-bottom:10px}.markdown pre{background:#fdfdfd;padding:10px;border-radius:5px;border:1px solid #ddd;overflow:auto;color:#444}.markdown blockquote{font-style:italic;border-left:3px solid #ddd;padding-left:10px;margin-bottom:10px;margin-left:20px}.markdown img{display:block;max-width:80%;margin-top:10px} \ No newline at end of file + */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.3.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.3.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.3.0') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.3.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.3.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.3.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;transform:translate(0, 0)}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-genderless:before,.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.c3 svg{font:10px sans-serif}.c3 line,.c3 path{fill:none;stroke:#000}.c3 text{-webkit-user-select:none;-moz-user-select:none;user-select:none}.c3-bars path,.c3-event-rect,.c3-legend-item-tile,.c3-xgrid-focus,.c3-ygrid{shape-rendering:crispEdges}.c3-chart-arc path{stroke:#fff}.c3-chart-arc text{fill:#fff;font-size:13px}.c3-grid line{stroke:#aaa}.c3-grid text{fill:#aaa}.c3-xgrid,.c3-ygrid{stroke-dasharray:3 3}.c3-text.c3-empty{fill:gray;font-size:2em}.c3-line{stroke-width:1px}.c3-circle._expanded_{stroke-width:1px;stroke:#fff}.c3-selected-circle{fill:#fff;stroke-width:2px}.c3-bar{stroke-width:0}.c3-bar._expanded_{fill-opacity:.75}.c3-target.c3-focused{opacity:1}.c3-target.c3-focused path.c3-line,.c3-target.c3-focused path.c3-step{stroke-width:2px}.c3-target.c3-defocused{opacity:.3!important}.c3-region{fill:#4682b4;fill-opacity:.1}.c3-brush .extent{fill-opacity:.1}.c3-legend-item{font-size:12px}.c3-legend-item-hidden{opacity:.15}.c3-legend-background{opacity:.75;fill:#fff;stroke:#d3d3d3;stroke-width:1}.c3-tooltip-container{z-index:10}.c3-tooltip{border-collapse:collapse;border-spacing:0;background-color:#fff;empty-cells:show;-webkit-box-shadow:7px 7px 12px -9px #777;-moz-box-shadow:7px 7px 12px -9px #777;box-shadow:7px 7px 12px -9px #777;opacity:.9}.c3-tooltip tr{border:1px solid #CCC}.c3-tooltip th{background-color:#aaa;font-size:14px;padding:2px 5px;text-align:left;color:#FFF}.c3-tooltip td{font-size:13px;padding:3px 6px;background-color:#fff;border-left:1px dotted #999}.c3-tooltip td>span{display:inline-block;width:10px;height:10px;margin-right:6px}.c3-tooltip td.value{text-align:right}.c3-area{stroke-width:0;opacity:.2}.c3-chart-arcs-title{dominant-baseline:middle;font-size:1.3em}.c3-chart-arcs .c3-chart-arcs-background{fill:#e0e0e0;stroke:none}.c3-chart-arcs .c3-chart-arcs-gauge-unit{fill:#000;font-size:16px}.c3-chart-arcs .c3-chart-arcs-gauge-max,.c3-chart-arcs .c3-chart-arcs-gauge-min{fill:#777}.c3-chart-arc .c3-gauge-value{fill:#000}header,.sidebar,.form-comment,.page-header{display:none}a{color:#36c;border:0}a:focus{outline:0;color:#df5353;text-decoration:none;border:1px dotted #aaa}a:hover{color:#333;text-decoration:none}table{width:100%;border-collapse:collapse;border-spacing:0;margin-bottom:20px;font-size:.95em}th,td{border:1px solid #eee;padding-top:.5em;padding-bottom:.5em;padding-left:3px;padding-right:3px}td{vertical-align:top}th{background:#fbfbfb;text-align:left}td li{margin-left:20px}.table-small{font-size:.8em}th a{text-decoration:none;color:#333}th a:focus,th a:hover{text-decoration:underline}.table-fixed{table-layout:fixed;white-space:nowrap}.table-fixed th{overflow:hidden}.table-fixed td{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.table-stripped tr:nth-child(odd) td{background:#fefefe}.column-3{width:3%}.column-5{width:5%}.column-8{width:7.5%}.column-10{width:10%}.column-12{width:12%}.column-15{width:15%}.column-18{width:18%}.column-20{width:20%}.column-25{width:25%}.column-30{width:30%}.column-35{width:35%}.column-40{width:40%}.column-50{width:50%}.column-60{width:60%}.column-70{width:70%}.public-board{margin-top:5px}.public-task{max-width:800px;margin:0 auto;margin-top:5px}#board-container{overflow-x:scroll}#board{table-layout:fixed}#board th.board-column-header{width:240px}#board td{vertical-align:top}.board-container-compact{overflow-x:initial}@media all and (-ms-high-contrast:active),(-ms-high-contrast:none){.board-container-compact #board{table-layout:auto}}#board th.board-column-header.board-column-compact{width:initial}.board-column-collapsed{display:none}td.board-column-task-collapsed{font-weight:bold;background-color:#fbfbfb}#board th.board-column-header-collapsed{width:28px;min-width:28px;text-align:center;overflow:hidden}.board-rotation-wrapper{position:relative;padding:8px 4px}.board-rotation{min-width:250px;-webkit-backface-visibility:hidden;-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg);-webkit-transform-origin:0 100%;-moz-transform-origin:0 100%;-ms-transform-origin:0 100%;transform-origin:0 100%}.board-add-icon{float:left;padding:0 5px}.board-add-icon a{text-decoration:none;color:#36c;font-size:150%;line-height:70%}.board-add-icon a:focus,.board-add-icon a:hover{text-decoration:none;color:red}.board-column-header-task-count{color:#999;font-weight:normal}th.board-column-header-collapsed .board-column-header-task-count{font-size:.85em}th.board-swimlane-header{width:120px}a.board-swimlane-toggle{font-size:.95em}.board-swimlane-toggle-title{font-size:.85em;display:none}.board-swimlane-title{vertical-align:top}.board-task-list{overflow:auto}.board-task-list-limit{background-color:#df5353}.draggable-item{cursor:pointer;user-select:none}.draggable-placeholder{border:2px dashed #000;background:#fafafa;height:70px;margin-bottom:10px}div.draggable-item-selected{border:1px solid #000}.task-board-sort-handle{float:left;padding-right:5px}.task-board{position:relative;margin-bottom:2px;border:1px solid #000;padding:2px;font-size:.85em;word-wrap:break-word}div.task-board-recent{box-shadow:2px 2px 5px rgba(0,0,0,0.25)}div.task-board-status-closed{user-select:none;border:1px dotted #555}.task-table a,.task-board a{color:#000;text-decoration:none;font-weight:bold}.task-table a:focus,.task-table a:hover,.task-board a:focus,.task-board a:hover{text-decoration:underline}.task-board-collapsed{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}a.task-board-collapsed-title{font-weight:normal}.task-board .dropdown{float:left;margin-right:5px;font-size:1.1em}.task-board-title{margin-top:5px;margin-bottom:5px;font-size:1.1em}.task-board-title a{font-weight:normal}.task-board-user{font-size:.8em}.task-board-current-user a{text-decoration:underline}.task-board-current-user a:focus,.task-board-current-user a:hover{text-decoration:none}a.task-board-nobody{font-weight:normal;font-style:italic;color:#444}.task-board-category-container{text-align:right}.task-board-category{font-weight:bold;font-size:.9em;color:#000;border:1px solid #555;padding:2px;padding-right:5px;padding-left:5px}.task-board-icons{text-align:right;margin-top:8px}.task-board-icons a{opacity:.5}.task-board-icons span{opacity:.5;margin-left:2px}.task-board-icons a:hover,.task-board-icons span:hover{opacity:1.0}.task-board-date{font-weight:bold;color:#000}span.task-board-date-overdue{color:#d90000;opacity:1.0}.task-score{font-weight:bold}.task-board .task-score{font-size:1.1em}.task-show-details .task-score{position:absolute;bottom:5px;right:5px;font-size:2em}.task-board-closed,.task-board-days{position:absolute;right:5px;top:5px;opacity:.5;font-size:.8em}.task-board-days:hover{opacity:1.0}.task-days-age{border:#666 1px solid;padding:1px 4px 1px 2px;border-top-left-radius:3px;border-bottom-left-radius:3px}.task-days-incolumn{border:#666 1px solid;border-left:0;margin-left:-5px;padding:1px 2px 1px 4px;border-top-right-radius:3px;border-bottom-right-radius:3px}.board-container-compact .task-board-days{display:none}.task-show-details{position:relative;border-radius:5px;padding-bottom:10px}.task-show-details h2{font-size:1.8em;margin:0;margin-bottom:25px;padding:0;padding-left:10px;padding-right:10px}.task-show-details li{margin-left:25px;list-style-type:circle}.task-show-section{margin-top:30px;margin-bottom:20px}.task-show-files a{font-weight:bold;text-decoration:none}.task-show-files li{margin-left:25px;list-style-type:square;line-height:25px}.task-show-file-actions{font-size:.75em}.task-show-file-actions:before{content:" ["}.task-show-file-actions:after{content:"]"}.task-show-file-actions a{color:#333}.task-show-description{border-left:4px solid #333;padding-left:20px}.task-show-description-textarea{width:99%;max-width:99%;height:300px}.task-file-viewer{position:relative}.task-file-viewer img{max-width:95%;max-height:85%;margin-top:10px}.task-time-form{margin-top:10px;margin-bottom:25px;padding:3px}.task-link-closed{text-decoration:line-through}.task-show-images{list-style-type:none}.task-show-images li img{width:100%}.task-show-images li .img_container{width:250px;height:100px;overflow:hidden}.task-show-images li{padding:10px;overflow:auto;width:250px;min-height:120px;display:inline-block;vertical-align:top}.task-show-images li p{padding:5px;font-weight:bold}.task-show-images li:hover{background:#eee}.task-show-image-actions{margin-left:5px}.task-show-file-table{width:auto}.task-show-start-link{color:#000}.task-show-start-link:hover,.task-show-start-link:focus{color:red}.flag-milestone{color:green}.comment{margin-bottom:20px}.comment:hover{background:#f7f8e0}.comment-inner{border-left:4px solid #333;padding-bottom:10px;padding-left:20px;margin-left:20px;margin-right:10px}.comment-preview{border:2px solid #000;border-radius:3px;padding:10px}.comment-preview .comment-inner{border:0;padding:0;margin:0}.comment-title{margin-bottom:8px;padding-bottom:3px;border-bottom:1px dotted #aaa}.ui-tooltip .comment-title{font-size:80%}.ui-tooltip .comment-inner{padding-bottom:0}.comment-actions{font-size:.8em;padding:0;text-align:right}.comment-actions li{display:inline;padding-left:5px;padding-right:5px;border-right:1px dotted #000}.comment-actions li:last-child{padding-right:0;border:0}.comment-username{font-weight:bold}.comment-textarea{height:200px;width:80%;max-width:800px}#comments .comment-textarea{height:80px;width:500px}.subtasks-table{font-size:.85em}.subtasks-table td{vertical-align:middle}.markdown{line-height:1.4em;font-size:1.0}.markdown h1{margin-top:5px;margin-bottom:10px;font-size:1.5em;font-weight:bold;text-decoration:underline}.markdown h2{font-size:1.2em;font-weight:bold;text-decoration:underline}.markdown h3{font-size:1.1em;text-decoration:underline}.markdown h4{font-size:1.1em;text-decoration:underline}.markdown p{margin-bottom:10px}.markdown ol,.markdown ul{margin-left:25px;margin-top:10px;margin-bottom:10px}.markdown pre{background:#fbfbfb;padding:10px;border-radius:5px;border:1px solid #ddd;overflow:auto;color:#444}.markdown blockquote{font-style:italic;border-left:3px solid #ddd;padding-left:10px;margin-bottom:10px;margin-left:20px}.markdown img{display:block;max-width:80%;margin-top:10px}.documentation{margin:0 auto;padding:20px;max-width:850px;background:#fefefe;border:1px solid #ccc;border-radius:5px;font-size:1.0;color:#555}.documentation img{border:1px solid #333}.documentation h1{text-decoration:none;font-size:1.8em;margin-bottom:30px}.documentation h2{font-size:1.3em;text-decoration:none;border-bottom:1px solid #ccc;margin-bottom:25px} \ No newline at end of file diff --git a/assets/css/src/markdown.css b/assets/css/src/markdown.css index dfc1fbb4..20729ac4 100644 --- a/assets/css/src/markdown.css +++ b/assets/css/src/markdown.css @@ -40,7 +40,7 @@ } .markdown pre { - background: #fdfdfd; + background: #fbfbfb; padding: 10px; border-radius: 5px; border: 1px solid #ddd; @@ -62,3 +62,30 @@ margin-top: 10px; } +.documentation { + margin: 0 auto; + padding: 20px; + max-width: 850px; + background: #fefefe; + border: 1px solid #ccc; + border-radius: 5px; + font-size: 1.0em; + color: #555; +} + +.documentation img { + border: 1px solid #333; +} + +.documentation h1 { + text-decoration: none; + font-size: 1.8em; + margin-bottom: 30px; +} + +.documentation h2 { + font-size: 1.3em; + text-decoration: none; + border-bottom: 1px solid #ccc; + margin-bottom: 25px; +} diff --git a/composer.json b/composer.json index 3b13dc6d..1eefe1f8 100644 --- a/composer.json +++ b/composer.json @@ -5,7 +5,7 @@ "ext-gd" : "*", "christian-riesen/otp" : "1.4", "eluceo/ical": "0.8.0", - "erusev/parsedown" : "1.5.3", + "erusev/parsedown" : "1.5.4", "fabiang/xmpp" : "0.6.1", "fguillot/json-rpc" : "1.0.1", "fguillot/picodb" : "1.0.1", diff --git a/composer.lock b/composer.lock index 853469e5..2afa4785 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "0478ce343724fb1689fe2778ba5b687e", + "hash": "70930e0b92d7ff0208ed435fd3accd30", "packages": [ { "name": "christian-riesen/base32", @@ -163,16 +163,16 @@ }, { "name": "erusev/parsedown", - "version": "1.5.3", + "version": "1.5.4", "source": { "type": "git", "url": "https://github.com/erusev/parsedown.git", - "reference": "b9e5228e92e5f5c17d7774cfb2de8e5e8362de1a" + "reference": "0e89e3714bda18973184d30646306bb0a482bd96" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/erusev/parsedown/zipball/b9e5228e92e5f5c17d7774cfb2de8e5e8362de1a", - "reference": "b9e5228e92e5f5c17d7774cfb2de8e5e8362de1a", + "url": "https://api.github.com/repos/erusev/parsedown/zipball/0e89e3714bda18973184d30646306bb0a482bd96", + "reference": "0e89e3714bda18973184d30646306bb0a482bd96", "shasum": "" }, "type": "library", @@ -198,7 +198,7 @@ "markdown", "parser" ], - "time": "2015-04-29 20:22:24" + "time": "2015-08-03 09:24:05" }, { "name": "fabiang/xmpp", diff --git a/doc/.htaccess b/doc/.htaccess new file mode 100644 index 00000000..14249c50 --- /dev/null +++ b/doc/.htaccess @@ -0,0 +1 @@ +Deny from all \ No newline at end of file diff --git a/doc/2fa.markdown b/doc/2fa.markdown new file mode 100644 index 00000000..627c636a --- /dev/null +++ b/doc/2fa.markdown @@ -0,0 +1,33 @@ +Two factor authentication +========================= + +Each user can enable the [two factor authentication](http://en.wikipedia.org/wiki/Two_factor_authentication). +After a successful login, a one-time code (6 characters) is asked to the user to allow the access to Kanboard. + +This code have to be provided by a compatible software generally installed on your smartphone. + +Kanboard use the [Time-based One-time Password Algorithm](http://en.wikipedia.org/wiki/Time-based_One-time_Password_Algorithm) defined in the [RFC 6238](http://tools.ietf.org/html/rfc6238). + +There are many software compatible with the standard TOTP system. +By example, you can use these free and open source applications: + +- [Google Authenticator](https://github.com/google/google-authenticator/) (Android, iOS, Blackberry) +- [FreeOTP](https://fedorahosted.org/freeotp/) (Android, iOS) +- [OATH Toolkit](http://www.nongnu.org/oath-toolkit/) (Command line utility on Unix/Linux) + +This system can work offline and you don't necessary need to have a mobile phone. + +Setup +----- + +1. Go to your user profile +2. On the left, click on **Two factor authentication** and check the box +3. A secret key is generated for you + +![2FA](http://kanboard.net/screenshots/documentation/2fa.png) + +- You have to save the secret key in your TOTP software. If you use a smartphone, the easiest solution is to scan the QR code with FreeOTP or Google Authenticator. +- Each time you will open a new session, a new code will be asked +- Don't forget to test your device before closing your session + +A new secret key is generated each time you enable/disable this feature. \ No newline at end of file diff --git a/doc/analytics-tasks.markdown b/doc/analytics-tasks.markdown new file mode 100644 index 00000000..c5acea5f --- /dev/null +++ b/doc/analytics-tasks.markdown @@ -0,0 +1,24 @@ +Analytics for tasks +=================== + +Each task have an analytics section available from the left menu in the task view. + +Lead and cycle time +------------------- + +![Lead and cycle time](http://kanboard.net/screenshots/documentation/task-lead-cycle-time.png) + +- The lead time is the time between the task creation and the date of completion (task closed). +- The cycle time is the time between the start date and the date of completion. +- If the task is not closed the current time is used instead of the date of completion. +- If the start date is not specified, the cycle time is not calculated. + +Note: You can configure an automatic action to define automatically the start date when you move a task to the column of your choice. + +Time spent into each column +--------------------------- + +![Time spent into each column](http://kanboard.net/screenshots/documentation/time-into-each-column.png) + +- This chart show the total time spent into each column for the task. +- The time spent is calculated until the task is closed. diff --git a/doc/analytics.markdown b/doc/analytics.markdown new file mode 100644 index 00000000..4ae9572f --- /dev/null +++ b/doc/analytics.markdown @@ -0,0 +1,70 @@ +Analytics +========= + +Each project have an analytics section. Depending how you are using Kanboard, you can see those reports: + +User repartition +---------------- + +![User repartition](http://kanboard.net/screenshots/documentation/user-repartition.png) + +This pie chart show the number of open tasks assigned per user. + +Task distribution +----------------- + +![Task distribution](http://kanboard.net/screenshots/documentation/task-distribution.png) + +This pie chart gives an overview of the number of open tasks per column. + +Cumulative flow diagram +----------------------- + +![Cumulative flow diagram](http://kanboard.net/screenshots/documentation/cfd.png) + +- This chart show the number of tasks cumulatively for each column over the time. +- Everyday, the total number of tasks is recorded for each column. +- If you would like to exclude closed tasks, change the [global project settings](project-configuration.markdown). + +Note: You need to have at least 2 days of data to see the graph. + +Burndown chart +-------------- + +![Burndown chart](http://kanboard.net/screenshots/documentation/burndown-chart.png) + +The [burn down chart](http://en.wikipedia.org/wiki/Burn_down_chart) is available for each project. + +- This chart is a graphical representation of work left to do versus time. +- Kanboard use the complexity or story point to generate this diagram. +- Everyday, the sum of the story points for each column is calculated. + +Average time spent into each column +----------------------------------- + +![Average time spent into each column](http://kanboard.net/screenshots/documentation/average-time-spent-into-each-column.png) + +This chart show the average time spent into each column for the last 1000 tasks. + +- Kanboard use the task transitions to calculate the data. +- The time spent is calculated until the task is closed. + +Average Lead and Cycle time +--------------------------- + +![Average time spent into each column](http://kanboard.net/screenshots/documentation/average-lead-cycle-time.png) + +This chart show the average lead and cycle time for the last 1000 tasks over the time. + +- The lead time is the time between the task creation and the date of completion. +- The cycle time is time between the specified start date of the task to completion date. +- If the task is not closed, the current time is used instead of the date of completion. + +Those metrics are calculated and recorded everyday for the whole project. + +Don't forget to run the daily job for stats calculation +------------------------------------------------------- + +To generate accurate analytics data, you should run the daily cronjob **project daily statistics**. + +[Read the documentation about Kanboard CLI](cli.markdown) diff --git a/doc/api-json-rpc.markdown b/doc/api-json-rpc.markdown new file mode 100644 index 00000000..61852933 --- /dev/null +++ b/doc/api-json-rpc.markdown @@ -0,0 +1,4366 @@ +Json-RPC API +============ + +User and application API +------------------------ + +There are two types of API access: + +### Application API + +- Access to the API with the user "jsonrpc" and the token available in settings +- Access to all procedures +- No permission checked +- There is no user session on the server +- Example of possible clients: tools to migrate/import data, create tasks from another system, etc... + +### User API + +- Access to the API with the user credentials (username and password) +- Access to a restricted set of procedures +- The project permissions are checked +- A user session is created on the server +- Example of possible clients: mobile/desktop application, command line utility, etc... + +Security +-------- + +- Always use HTTPS with a valid certificate +- If you make a mobile application, it's your job to store securely the user credentials on the device +- After 3 authentication failure on the user api, the end-user have to unlock his account by using the login form +- Two factor authentication is not yet available through the API + +Protocol +-------- + +Kanboard use the protocol Json-RPC to interact with external programs. + +JSON-RPC is a remote procedure call protocol encoded in JSON. +Almost the same thing as XML-RPC but with the JSON format. + +We use the [version 2 of the protocol](http://www.jsonrpc.org/specification). +You must call the API with a `POST` HTTP request. + +Kanboard support batch requests, so you can make multiple API calls in a single HTTP request. It's particularly useful for mobile clients with higher network latency. + +Authentication +-------------- + +### Default method (HTTP Basic) + +The API credentials are available on the settings page. + +- API end-point: `https://YOUR_SERVER/jsonrpc.php` + +If you want to use the "application api": + +- Username: `jsonrpc` +- Password: API token on the settings page + +Otherwise for the "user api", just use the real username/passsword. + +The API use the [HTTP Basic Authentication Scheme described in the RFC2617](http://www.ietf.org/rfc/rfc2617.txt). +If there is an authentication error, you will receive the HTTP status code `401 Not Authorized`. + +### Authorized User API procedures + +- getMe +- getMyDashboard +- getMyActivityStream +- createMyPrivateProject +- getMyProjectsList +- getTimezone +- getVersion +- getDefaultTaskColor +- getDefaultTaskColors +- getColorList +- getProjectById +- getTask +- getTaskByReference +- getAllTasks +- openTask +- closeTask +- moveTaskPosition +- createTask +- updateTask +- getBoard + +### Custom HTTP header + +You can use an alternative HTTP header for the authentication if your server have a very specific configuration. + +- The header name can be anything you want, by example `X-API-Auth`. +- The header value is the `username:password` encoded in Base64. + +Configuration: + +1. Define your custom header in your `config.php`: `define('API_AUTHENTICATION_HEADER', 'X-API-Auth');` +2. Encode the credentials in Base64, example with PHP `base64_encode('jsonrpc:19ffd9709d03ce50675c3a43d1c49c1ac207f4bc45f06c5b2701fbdf8929');` +3. Test with curl: + +```bash +curl \ +-H 'X-API-Auth: anNvbnJwYzoxOWZmZDk3MDlkMDNjZTUwNjc1YzNhNDNkMWM0OWMxYWMyMDdmNGJjNDVmMDZjNWIyNzAxZmJkZjg5Mjk=' \ +-d '{"jsonrpc": "2.0", "method": "getAllProjects", "id": 1}' \ +http://localhost/kanboard/jsonrpc.php +``` + +Examples +-------- + +### Example with cURL + +From the command line: + +```bash +curl \ +-u "jsonrpc:19ffd9709d03ce50675c3a43d1c49c1ac207f4bc45f06c5b2701fbdf8929" \ +-d '{"jsonrpc": "2.0", "method": "getAllProjects", "id": 1}' \ +http://localhost/kanboard/jsonrpc.php +``` + +Response from the server: + +```json +{ + "jsonrpc":"2.0", + "id":1, + "result":[ + { + "id":"1", + "name":"API test", + "is_active":"1", + "token":"6bd0932fe7f4b5e6e4bc3c72800bfdef36a2c5de2f38f756dfb5bd632ebf", + "last_modified":"1403392631" + } + ] +} +``` + +### Example with Python + +Here a basic example written in Python to create a task: + +```python +#!/usr/bin/env python + +import requests +import json + +def main(): + url = "http://demo.kanboard.net/jsonrpc.php" + api_key = "be4271664ca8169d32af49d8e1ec854edb0290bc3588a2e356275eab9505" + headers = {"content-type": "application/json"} + + payload = { + "method": "createTask", + "params": { + "title": "Python API test", + "project_id": 1 + }, + "jsonrpc": "2.0", + "id": 1, + } + + response = requests.post( + url, + data=json.dumps(payload), + headers=headers, + auth=("jsonrpc", api_key) + ) + + if response.status_code == 401: + print "Authentication failed" + else: + result = response.json() + + assert result["result"] == True + assert result["jsonrpc"] + assert result["id"] == 1 + + print "Task created successfully!" + +if __name__ == "__main__": + main() +``` + +Run this script from your terminal: + +```bash +python jsonrpc.py +Task created successfully! +``` + +### Example with a PHP client: + +I wrote a simple [Json-RPC Client/Server library in PHP](https://github.com/fguillot/JsonRPC), here an example: + +```php +authentication('jsonrpc', '19ffd9709d03ce50675c3a43d1c49c1ac207f4bc45f06c5b2701fbdf8929'); + +print_r($client->getAllProjects()); + +``` + +The response: + +``` +Array +( + [0] => Array + ( + [id] => 1 + [name] => API test + [is_active] => 1 + [token] => 6bd0932fe7f4b5e6e4bc3c72800bfdef36a2c5de2f38f756dfb5bd632ebf + [last_modified] => 1403392631 + ) + +) +``` + +### Example with Ruby + +This example can be used with Kanboard configured with Reverse-Proxy authentication and the API configured with a custom authentication header: + +```ruby +require 'faraday' + +conn = Faraday.new(:url => 'https://kanboard.example.com') do |faraday| + faraday.response :logger + faraday.headers['X-API-Auth'] = 'XXX' # base64_encode('jsonrpc:API_KEY') + faraday.basic_auth(ENV['user'], ENV['pw']) # user/pass to get through basic auth + faraday.adapter Faraday.default_adapter # make requests with Net::HTTP +end + +response = conn.post do |req| + req.url '/jsonrpc.php' + req.headers['Content-Type'] = 'application/json' + req.body = '{ "jsonrpc": "2.0", "id": 1, "method": "getAllProjects" }' +end + +puts response.body +``` + +Procedures +---------- + +### getVersion + +- Purpose: **Get the application version** +- Parameters: none +- Result: **version** (Example: 1.0.12, master) + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "getVersion", + "id": 1661138292 +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 1661138292, + "result": "1.0.13" +} +``` + +### getTimezone + +- Purpose: **Get the application timezone** +- Parameters: none +- Result on success: **Timezone** (Example: UTC, Europe/Paris) +- Result on failure: **Default timezone** (UTC) + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "getTimezone", + "id": 1661138292 +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 1661138292, + "result": "Europe\/Paris" +} +``` + +### getDefaultTaskColors + +- Purpose: **Get all default task colors** +- Parameters: None +- Result on success: **Color properties** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "getDefaultTaskColors", + "id": 2108929212 +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 2108929212, + "result": { + "yellow": { + "name": "Yellow", + "background": "rgb(245, 247, 196)", + "border": "rgb(223, 227, 45)" + }, + "blue": { + "name": "Blue", + "background": "rgb(219, 235, 255)", + "border": "rgb(168, 207, 255)" + }, + "green": { + "name": "Green", + "background": "rgb(189, 244, 203)", + "border": "rgb(74, 227, 113)" + }, + "purple": { + "name": "Purple", + "background": "rgb(223, 176, 255)", + "border": "rgb(205, 133, 254)" + }, + "red": { + "name": "Red", + "background": "rgb(255, 187, 187)", + "border": "rgb(255, 151, 151)" + }, + "orange": { + "name": "Orange", + "background": "rgb(255, 215, 179)", + "border": "rgb(255, 172, 98)" + }, + "grey": { + "name": "Grey", + "background": "rgb(238, 238, 238)", + "border": "rgb(204, 204, 204)" + }, + "brown": { + "name": "Brown", + "background": "#d7ccc8", + "border": "#4e342e" + }, + "deep_orange": { + "name": "Deep Orange", + "background": "#ffab91", + "border": "#e64a19" + }, + "dark_grey": { + "name": "Dark Grey", + "background": "#cfd8dc", + "border": "#455a64" + }, + "pink": { + "name": "Pink", + "background": "#f48fb1", + "border": "#d81b60" + }, + "teal": { + "name": "Teal", + "background": "#80cbc4", + "border": "#00695c" + }, + "cyan": { + "name": "Cyan", + "background": "#b2ebf2", + "border": "#00bcd4" + }, + "lime": { + "name": "Lime", + "background": "#e6ee9c", + "border": "#afb42b" + }, + "light_green": { + "name": "Light Green", + "background": "#dcedc8", + "border": "#689f38" + }, + "amber": { + "name": "Amber", + "background": "#ffe082", + "border": "#ffa000" + } + } +} +``` + +### getDefaultTaskColor + +- Purpose: **Get default task color** +- Parameters: None +- Result on success: **color_id** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "getDefaultTaskColor", + "id": 1144775215 +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 1144775215, + "result": "yellow" +} +``` + +### getColorList + +- Purpose: **Get the list of task colors** +- Parameters: none +- Result on success: **Dictionary of color_id => color_name** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "getColorList", + "id": 1677051386 +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 1677051386, + "result": { + "yellow": "Yellow", + "blue": "Blue", + "green": "Green", + "purple": "Purple", + "red": "Red", + "orange": "Orange", + "grey": "Grey", + "brown": "Brown", + "deep_orange": "Deep Orange", + "dark_grey": "Dark Grey", + "pink": "Pink", + "teal": "Teal", + "cyan": "Cyan", + "lime": "Lime", + "light_green": "Light Green", + "amber": "Amber" + } +} +``` + +### createProject + +- Purpose: **Create a new project** +- Parameters: + - **name** (string, required) + - **description** (string, optional) +- Result on success: **project_id** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "createProject", + "id": 1797076613, + "params": { + "name": "PHP client" + } +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 1797076613, + "result": 2 +} +``` + +### getProjectById + +- Purpose: **Get project information** +- Parameters: + - **project_id** (integer, required) +- Result on success: **project properties** +- Result on failure: **null** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "getProjectById", + "id": 226760253, + "params": { + "project_id": 1 + } +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 226760253, + "result": { + "id": "1", + "name": "API test", + "is_active": "1", + "token": "", + "last_modified": "1436119135", + "is_public": "0", + "is_private": "0", + "is_everybody_allowed": "0", + "default_swimlane": "Default swimlane", + "show_default_swimlane": "1", + "description": "test", + "identifier": "", + "url": { + "board": "http:\/\/127.0.0.1:8000\/?controller=board&action=show&project_id=1", + "calendar": "http:\/\/127.0.0.1:8000\/?controller=calendar&action=show&project_id=1", + "list": "http:\/\/127.0.0.1:8000\/?controller=listing&action=show&project_id=1" + } + } +} +``` + +### getProjectByName + +- Purpose: **Get project information** +- Parameters: + - **name** (string, required) +- Result on success: **project properties** +- Result on failure: **null** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "getProjectByName", + "id": 1620253806, + "params": { + "name": "Test" + } +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 1620253806, + "result": { + "id": "1", + "name": "Test", + "is_active": "1", + "token": "", + "last_modified": "1436119135", + "is_public": "0", + "is_private": "0", + "is_everybody_allowed": "0", + "default_swimlane": "Default swimlane", + "show_default_swimlane": "1", + "description": "test", + "identifier": "", + "url": { + "board": "http:\/\/127.0.0.1:8000\/?controller=board&action=show&project_id=1", + "calendar": "http:\/\/127.0.0.1:8000\/?controller=calendar&action=show&project_id=1", + "list": "http:\/\/127.0.0.1:8000\/?controller=listing&action=show&project_id=1" + } + } +} +``` + +### getAllProjects + +- Purpose: **Get all available projects** +- Parameters: + - **none** +- Result on success: **List of projects** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "getAllProjects", + "id": 2134420212 +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 2134420212, + "result": [ + { + "id": "1", + "name": "API test", + "is_active": "1", + "token": "", + "last_modified": "1436119570", + "is_public": "0", + "is_private": "0", + "is_everybody_allowed": "0", + "default_swimlane": "Default swimlane", + "show_default_swimlane": "1", + "description": null, + "identifier": "", + "url": { + "board": "http:\/\/127.0.0.1:8000\/?controller=board&action=show&project_id=1", + "calendar": "http:\/\/127.0.0.1:8000\/?controller=calendar&action=show&project_id=1", + "list": "http:\/\/127.0.0.1:8000\/?controller=listing&action=show&project_id=1" + } + } + ] +} +``` + +### updateProject + +- Purpose: **Update a project** +- Parameters: + - **id** (integer, required) + - **name** (string, required) + - **description** (string, optional) +- Result on success: **true** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "updateProject", + "id": 1853996288, + "params": { + "id": 1, + "name": "PHP client update" + } +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 1853996288, + "result": true +} +``` + +### removeProject + +- Purpose: **Remove a project** +- Parameters: + **project_id** (integer, required) +- Result on success: **true** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "removeProject", + "id": 46285125, + "params": { + "project_id": "2" + } +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 46285125, + "result": true +} +``` + +### enableProject + +- Purpose: **Enable a project** +- Parameters: + - **project_id** (integer, required) +- Result on success: **true** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "enableProject", + "id": 1775494839, + "params": [ + "1" + ] +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 1775494839, + "result": true +} +``` + +### disableProject + +- Purpose: **Disable a project** +- Parameters: + - **project_id** (integer, required) +- Result on success: **true** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "disableProject", + "id": 1734202312, + "params": [ + "1" + ] +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 1734202312, + "result": true +} +``` + +### enableProjectPublicAccess + +- Purpose: **Enable public access for a given project** +- Parameters: + - **project_id** (integer, required) +- Result on success: **true** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "enableProjectPublicAccess", + "id": 103792571, + "params": [ + "1" + ] +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 103792571, + "result": true +} +``` + +### disableProjectPublicAccess + +- Purpose: **Disable public access for a given project** +- Parameters: + - **project_id** (integer, required) +- Result on success: **true** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "disableProjectPublicAccess", + "id": 942472945, + "params": [ + "1" + ] +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 942472945, + "result": true +} +``` + +### getProjectActivity + +- Purpose: **Get activity stream for a project** +- Parameters: + - **project_id** (integer, required) +- Result on success: **List of events** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "getProjectActivity", + "id": 942472945, + "params": [ + "project_id": 1 + ] +} +``` + +### getProjectActivities + +- Purpose: **Get Activityfeed for Project(s)** +- Parameters: + - **project_ids** (integer array, required) +- Result on success: **List of events** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "getProjectActivities", + "id": 942472945, + "params": [ + "project_ids": [1,2] + ] +} +``` + +### getMembers + +- Purpose: **Get members of a project** +- Parameters: + - **project_id** (integer, required) +- Result on success: Key/value pair of user_id and username +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "getMembers", + "id": 1944388643, + "params": [ + 1 + ] +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 1944388643, + "result": { + "1": "user1", + "2": "user2", + "3": "user3" + } +} +``` + +### revokeUser + +- Purpose: **Revoke user access for a given project** +- Parameters: + - **project_id** (integer, required) + - **user_id** (integer, required) +- Result on success: **true** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "revokeUser", + "id": 251218350, + "params": [ + 1, + 2 + ] +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 251218350, + "result": true +} +``` + +### allowUser + +- Purpose: **Grant user access for a given project** +- Parameters: + - **project_id** (integer, required) + - **user_id** (integer, required) +- Result on success: **true** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "allowUser", + "id": 2111451404, + "params": [ + 1, + 2 + ] +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 2111451404, + "result": true +} +``` + + +### getBoard + +- Purpose: **Get all necessary information to display a board** +- Parameters: + - **project_id** (integer, required) +- Result on success: **board properties** +- Result on failure: **empty list** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "getBoard", + "id": 827046470, + "params": [ + 1 + ] +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 827046470, + "result": [ + { + "id": 0, + "name": "Default swimlane", + "columns": [ + { + "id": "1", + "title": "Backlog", + "position": "1", + "project_id": "1", + "task_limit": "0", + "description": "", + "tasks": [], + "nb_tasks": 0, + "score": 0 + }, + { + "id": "2", + "title": "Ready", + "position": "2", + "project_id": "1", + "task_limit": "0", + "description": "", + "tasks": [ + { + "nb_comments":"0", + "nb_files":"0", + "nb_subtasks":"0", + "nb_completed_subtasks":"0", + "nb_links":"0", + "id":"2", + "reference":"", + "title":"Test", + "description":"", + "date_creation":"1430870507", + "date_modification":"1430870507", + "date_completed":null, + "date_due":"0", + "color_id":"yellow", + "project_id":"1", + "column_id":"2", + "swimlane_id":"0", + "owner_id":"0", + "creator_id":"1", + "position":"1", + "is_active":"1", + "score":"0", + "category_id":"0", + "date_moved":"1430870507", + "recurrence_status":"0", + "recurrence_trigger":"0", + "recurrence_factor":"0", + "recurrence_timeframe":"0", + "recurrence_basedate":"0", + "recurrence_parent":null, + "recurrence_child":null, + "assignee_username":null, + "assignee_name":null + } + ], + "nb_tasks": 1, + "score": 0 + }, + { + "id": "3", + "title": "Work in progress", + "position": "3", + "project_id": "1", + "task_limit": "0", + "description": "", + "tasks": [ + { + "nb_comments":"0", + "nb_files":"0", + "nb_subtasks":"1", + "nb_completed_subtasks":"0", + "nb_links":"0", + "id":"1", + "reference":"", + "title":"Task with comment", + "description":"", + "date_creation":"1430783188", + "date_modification":"1430783188", + "date_completed":null, + "date_due":"0", + "color_id":"red", + "project_id":"1", + "column_id":"3", + "swimlane_id":"0", + "owner_id":"1", + "creator_id":"0", + "position":"1", + "is_active":"1", + "score":"0", + "category_id":"0", + "date_moved":"1430783191", + "recurrence_status":"0", + "recurrence_trigger":"0", + "recurrence_factor":"0", + "recurrence_timeframe":"0", + "recurrence_basedate":"0", + "recurrence_parent":null, + "recurrence_child":null, + "assignee_username":"admin", + "assignee_name":null + } + ], + "nb_tasks": 1, + "score": 0 + }, + { + "id": "4", + "title": "Done", + "position": "4", + "project_id": "1", + "task_limit": "0", + "description": "", + "tasks": [], + "nb_tasks": 0, + "score": 0 + } + ], + "nb_columns": 4, + "nb_tasks": 2 + } + ] +} +``` + +### getColumns + +- Purpose: **Get all columns information for a given project** +- Parameters: + - **project_id** (integer, required) +- Result on success: **columns properties** +- Result on failure: **empty list** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "getColumns", + "id": 887036325, + "params": [ + 1 + ] +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 887036325, + "result": [ + { + "id": "1", + "title": "Backlog", + "position": "1", + "project_id": "1", + "task_limit": "0" + }, + { + "id": "2", + "title": "Ready", + "position": "2", + "project_id": "1", + "task_limit": "0" + }, + { + "id": "3", + "title": "Work in progress", + "position": "3", + "project_id": "1", + "task_limit": "0" + } + ] +} +``` + +### getColumn + +- Purpose: **Get a single column** +- Parameters: + - **column_id** (integer, required) +- Result on success: **column properties** +- Result on failure: **null** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "getColumn", + "id": 1242049935, + "params": [ + 2 + ] +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 1242049935, + "result": { + "id": "2", + "title": "Youpi", + "position": "2", + "project_id": "1", + "task_limit": "5" + } +} +``` + +### moveColumnUp + +- Purpose: **Move up the column position** +- Parameters: + - **project_id** (integer, required) + - **column_id** (integer, required) +- Result on success: **true** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "moveColumnUp", + "id": 99275573, + "params": [ + 1, + 2 + ] +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 99275573, + "result": true +} +``` + +### moveColumnDown + +- Purpose: **Move down the column position** +- Parameters: + - **project_id** (integer, required) + - **column_id** (integer, required) +- Result on success: **true** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "moveColumnDown", + "id": 957090649, + "params": { + "project_id": 1, + "column_id": 2 + } +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 957090649, + "result": true +} +``` + +### updateColumn + +- Purpose: **Update column properties** +- Parameters: + - **column_id** (integer, required) + - **title** (string, required) + - **task_limit** (integer, optional) + - **description** (string, optional) +- Result on success: **true** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "updateColumn", + "id": 480740641, + "params": [ + 2, + "Boo", + 5 + ] +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 480740641, + "result": true +} +``` + +### addColumn + +- Purpose: **Add a new column** +- Parameters: + - **project_id** (integer, required) + - **title** (string, required) + - **task_limit** (integer, optional) + - **description** (string, optional) +- Result on success: **column_id** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "addColumn", + "id": 638544704, + "params": [ + 1, + "Boo" + ] +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 638544704, + "result": 5 +} +``` + +### removeColumn + +- Purpose: **Remove a column** +- Parameters: + - **column_id** (integer, required) +- Result on success: **true** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "removeColumn", + "id": 1433237746, + "params": [ + 1 + ] +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 1433237746, + "result": true +} +``` + +### getDefaultSwimlane + +- Purpose: **Get the default swimlane for a project** +- Parameters: + - **project_id** (integer, required) +- Result on success: **true** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "getDefaultSwimlane", + "id": 898774713, + "params": [ + 1 + ] +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 898774713, + "result": { + "id": "1", + "default_swimlane": "Default swimlane", + "show_default_swimlane": "1" + } +} +``` + +### getActiveSwimlanes + +- Purpose: **Get the list of enabled swimlanes of a project (include default swimlane if enabled)** +- Parameters: + - **project_id** (integer, required) +- Result on success: **List of swimlanes** +- Result on failure: **null** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "getActiveSwimlanes", + "id": 934789422, + "params": [ + 1 + ] +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 934789422, + "result": [ + { + "id": 0, + "name": "Default swimlane" + }, + { + "id": "2", + "name": "Swimlane A" + } + ] +} +``` + +### getAllSwimlanes + +- Purpose: **Get the list of all swimlanes of a project (enabled or disabled) and sorted by position** +- Parameters: + - **project_id** (integer, required) +- Result on success: **List of swimlanes** +- Result on failure: **null** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "getAllSwimlanes", + "id": 509791576, + "params": [ + 1 + ] +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 509791576, + "result": [ + { + "id": "1", + "name": "Another swimlane", + "position": "1", + "is_active": "1", + "project_id": "1" + }, + { + "id": "2", + "name": "Swimlane A", + "position": "2", + "is_active": "1", + "project_id": "1" + } + ] +} +``` + +### getSwimlane + +- Purpose: **Get the a swimlane by id** +- Parameters: + - **swimlane_id** (integer, required) +- Result on success: **swimlane properties** +- Result on failure: **null** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "getSwimlane", + "id": 131071870, + "params": [ + 1 + ] +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 131071870, + "result": { + "id": "1", + "name": "Swimlane 1", + "position": "1", + "is_active": "1", + "project_id": "1" + } +} +``` + +### getSwimlaneById + +- Purpose: **Get the a swimlane by id** +- Parameters: + - **swimlane_id** (integer, required) +- Result on success: **swimlane properties** +- Result on failure: **null** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "getSwimlaneById", + "id": 131071870, + "params": [ + 1 + ] +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 131071870, + "result": { + "id": "1", + "name": "Swimlane 1", + "position": "1", + "is_active": "1", + "project_id": "1" + } +} +``` + +### getSwimlaneByName + +- Purpose: **Get the a swimlane by name** +- Parameters: + - **project_id** (integer, required) + - **name** (string, required) +- Result on success: **swimlane properties** +- Result on failure: **null** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "getSwimlaneByName", + "id": 824623567, + "params": [ + 1, + "Swimlane 1" + ] +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 824623567, + "result": { + "id": "1", + "name": "Swimlane 1", + "position": "1", + "is_active": "1", + "project_id": "1" + } +} +``` + +### moveSwimlaneUp + +- Purpose: **Move up the swimlane position** +- Parameters: + - **project_id** (integer, required) + - **swimlane_id** (integer, required) +- Result on success: **true** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "moveSwimlaneUp", + "id": 99275573, + "params": [ + 1, + 2 + ] +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 99275573, + "result": true +} +``` + +### moveSwimlaneDown + +- Purpose: **Move down the swimlane position** +- Parameters: + - **project_id** (integer, required) + - **swimlane_id** (integer, required) +- Result on success: **true** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "moveSwimlaneDown", + "id": 957090649, + "params": { + "project_id": 1, + "swimlane_id": 2 + } +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 957090649, + "result": true +} +``` + +### updateSwimlane + +- Purpose: **Update swimlane properties** +- Parameters: + - **swimlane_id** (integer, required) + - **name** (string, required) +- Result on success: **true** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "updateSwimlane", + "id": 87102426, + "params": [ + "1", + "Another swimlane" + ] +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 87102426, + "result": true +} +``` + +### addSwimlane + +- Purpose: **Add a new swimlane** +- Parameters: + - **project_id** (integer, required) + - **name** (string, required) +- Result on success: **swimlane_id** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "addSwimlane", + "id": 849940086, + "params": [ + 1, + "Swimlane 1" + ] +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 849940086, + "result": 1 +} +``` + +### removeSwimlane + +- Purpose: **Remove a swimlane** +- Parameters: + - **project_id** (integer, required) + - **swimlane_id** (integer, required) +- Result on success: **true** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "removeSwimlane", + "id": 1433237746, + "params": [ + 2, + 1 + ] +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 1433237746, + "result": true +} +``` + +### disableSwimlane + +- Purpose: **Enable a swimlane** +- Parameters: + - **project_id** (integer, required) + - **swimlane_id** (integer, required) +- Result on success: **true** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "disableSwimlane", + "id": 1433237746, + "params": [ + 2, + 1 + ] +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 1433237746, + "result": true +} +``` + +### enableSwimlane + +- Purpose: **Enable a swimlane** +- Parameters: + - **project_id** (integer, required) + - **swimlane_id** (integer, required) +- Result on success: **true** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "enableSwimlane", + "id": 1433237746, + "params": [ + 2, + 1 + ] +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 1433237746, + "result": true +} +``` + +### getAvailableActions + +- Purpose: **Get list of available automatic actions** +- Parameters: none +- Result on success: **list of actions** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "getAvailableActions", + "id": 1217735483 +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 1217735483, + "result": { + "TaskLogMoveAnotherColumn": "Add a comment logging moving the task between columns", + "TaskAssignColorUser": "Assign a color to a specific user", + "TaskAssignColorColumn": "Assign a color when the task is moved to a specific column", + "TaskAssignCategoryColor": "Assign automatically a category based on a color", + "TaskAssignColorCategory": "Assign automatically a color based on a category", + "TaskAssignSpecificUser": "Assign the task to a specific user", + "TaskAssignCurrentUser": "Assign the task to the person who does the action", + "TaskUpdateStartDate": "Automatically update the start date", + "TaskAssignUser": "Change the assignee based on an external username", + "TaskAssignCategoryLabel": "Change the category based on an external label", + "TaskClose": "Close a task", + "CommentCreation": "Create a comment from an external provider", + "TaskCreation": "Create a task from an external provider", + "TaskDuplicateAnotherProject": "Duplicate the task to another project", + "TaskMoveColumnAssigned": "Move the task to another column when assigned to a user", + "TaskMoveColumnUnAssigned": "Move the task to another column when assignee is cleared", + "TaskMoveAnotherProject": "Move the task to another project", + "TaskOpen": "Open a task" + } +} +``` + +### getAvailableActionEvents + +- Purpose: **Get list of available events for actions** +- Parameters: none +- Result on success: **list of events** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "getAvailableActionEvents", + "id": 2116665643 +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 2116665643, + "result": { + "bitbucket.webhook.commit": "Bitbucket commit received", + "task.close": "Closing a task", + "github.webhook.commit": "Github commit received", + "github.webhook.issue.assignee": "Github issue assignee change", + "github.webhook.issue.closed": "Github issue closed", + "github.webhook.issue.commented": "Github issue comment created", + "github.webhook.issue.label": "Github issue label change", + "github.webhook.issue.opened": "Github issue opened", + "github.webhook.issue.reopened": "Github issue reopened", + "gitlab.webhook.commit": "Gitlab commit received", + "gitlab.webhook.issue.closed": "Gitlab issue closed", + "gitlab.webhook.issue.opened": "Gitlab issue opened", + "task.move.column": "Move a task to another column", + "task.open": "Open a closed task", + "task.assignee_change": "Task assignee change", + "task.create": "Task creation", + "task.create_update": "Task creation or modification", + "task.update": "Task modification" + } +} +``` + +### getCompatibleActionEvents + +- Purpose: **Get list of events compatible with an action** +- Parameters: + - **action_name** (string, required) +- Result on success: **list of events** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "getCompatibleActionEvents", + "id": 899370297, + "params": [ + "TaskClose" + ] +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 899370297, + "result": { + "bitbucket.webhook.commit": "Bitbucket commit received", + "github.webhook.commit": "Github commit received", + "github.webhook.issue.closed": "Github issue closed", + "gitlab.webhook.commit": "Gitlab commit received", + "gitlab.webhook.issue.closed": "Gitlab issue closed", + "task.move.column": "Move a task to another column" + } +} +``` + +### getActions + +- Purpose: **Get list of actions for a project** +- Parameters: + - **project_id** (integer, required) +- Result on success: **list of actions properties** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "getActions", + "id": 1433237746, + "params": [ + "1" + ] +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 1433237746, + "result": [ + { + "id" : "13", + "project_id" : "2", + "event_name" : "task.move.column", + "action_name" : "TaskAssignSpecificUser", + "params" : { + "column_id" : "5", + "user_id" : "1" + } + } + ] +} +``` + +### createAction + +- Purpose: **Create an action** +- Parameters: + - **project_id** (integer, required) + - **event_name** (string, required) + - **action_name** (string, required) + - **params** (key/value parameters, required) +- Result on success: **action_id** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "createAction", + "id": 1433237746, + "params": { + "project_id" : "2", + "event_name" : "task.move.column", + "action_name" : "TaskAssignSpecificUser", + "params" : { + "column_id" : "3", + "user_id" : "2" + } + } +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 1433237746, + "result": 14 +} +``` + +### removeAction + +- Purpose: **Remove an action** +- Parameters: + - **action_id** (integer, required) +- Result on success: **true** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "removeAction", + "id": 1510741671, + "params": [ + 1 + ] +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 1510741671, + "result": true +} +``` + +### createTask + +- Purpose: **Create a new task** +- Parameters: + - **title** (string, required) + - **project_id** (integer, required) + - **color_id** (string, optional) + - **column_id** (integer, optional) + - **owner_id** (integer, optional) + - **creator_id** (integer, optional) + - **date_due**: ISO8601 format (string, optional) + - **description** Markdown content (string, optional) + - **category_id** (integer, optional) + - **score** (integer, optional) + - **swimlane_id** (integer, optional) + - **recurrence_status** (integer, optional) + - **recurrence_trigger** (integer, optional) + - **recurrence_factor** (integer, optional) + - **recurrence_timeframe** (integer, optional) + - **recurrence_basedate** (integer, optional) +- Result on success: **task_id** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "createTask", + "id": 1176509098, + "params": { + "owner_id": 1, + "creator_id": 0, + "date_due": "", + "description": "", + "category_id": 0, + "score": 0, + "title": "Test", + "project_id": 1, + "color_id": "green", + "column_id": 2, + "recurrence_status": 0, + "recurrence_trigger": 0, + "recurrence_factor": 0, + "recurrence_timeframe": 0, + "recurrence_basedate": 0 + } +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 1176509098, + "result": 3 +} +``` + +### getTask + +- Purpose: **Get task by the unique id** +- Parameters: + - **task_id** (integer, required) +- Result on success: **task properties** +- Result on failure: **null** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "getTask", + "id": 700738119, + "params": { + "task_id": 1 + } +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 700738119, + "result": { + "id": "1", + "title": "Task #1", + "description": "", + "date_creation": "1409963206", + "color_id": "blue", + "project_id": "1", + "column_id": "2", + "owner_id": "1", + "position": "1", + "is_active": "1", + "date_completed": null, + "score": "0", + "date_due": "0", + "category_id": "0", + "creator_id": "0", + "date_modification": "1409963206", + "reference": "", + "date_started": null, + "time_spent": "0", + "time_estimated": "0", + "swimlane_id": "0", + "date_moved": "1430875287", + "recurrence_status": "0", + "recurrence_trigger": "0", + "recurrence_factor": "0", + "recurrence_timeframe": "0", + "recurrence_basedate": "0", + "recurrence_parent": null, + "recurrence_child": null, + "url": "http:\/\/127.0.0.1:8000\/?controller=task&action=show&task_id=1&project_id=1", + "color": { + "name": "Yellow", + "background": "rgb(245, 247, 196)", + "border": "rgb(223, 227, 45)" + } + } +} +``` + +### getTaskByReference + +- Purpose: **Get task by the external reference** +- Parameters: + - **project_id** (integer, required) + - **reference** (string, required) +- Result on success: **task properties** +- Result on failure: **null** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "getTaskByReference", + "id": 1992081213, + "params": { + "project_id": 1, + "reference": "TICKET-1234" + } +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 1992081213, + "result": { + "id": "5", + "title": "Task with external ticket number", + "description": "[Link to my ticket](http:\/\/my-ticketing-system\/1234)", + "date_creation": "1434227446", + "color_id": "yellow", + "project_id": "1", + "column_id": "1", + "owner_id": "0", + "position": "4", + "is_active": "1", + "date_completed": null, + "score": "0", + "date_due": "0", + "category_id": "0", + "creator_id": "0", + "date_modification": "1434227446", + "reference": "TICKET-1234", + "date_started": null, + "time_spent": "0", + "time_estimated": "0", + "swimlane_id": "0", + "date_moved": "1434227446", + "recurrence_status": "0", + "recurrence_trigger": "0", + "recurrence_factor": "0", + "recurrence_timeframe": "0", + "recurrence_basedate": "0", + "recurrence_parent": null, + "recurrence_child": null, + "url": "http:\/\/127.0.0.1:8000\/?controller=task&action=show&task_id=5&project_id=1" + } +} +``` + +### getAllTasks + +- Purpose: **Get all available tasks** +- Parameters: + - **project_id** (integer, required) + - **status_id**: The value 1 for active tasks and 0 for inactive (integer, required) +- Result on success: **List of tasks** +- Result on failure: **false** + +Request example to fetch all tasks on the board: + +```json +{ + "jsonrpc": "2.0", + "method": "getAllTasks", + "id": 133280317, + "params": { + "project_id": 1, + "status_id": 1 + } +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 133280317, + "result": [ + { + "id": "1", + "title": "Task #1", + "description": "", + "date_creation": "1409961789", + "color_id": "blue", + "project_id": "1", + "column_id": "2", + "owner_id": "1", + "position": "1", + "is_active": "1", + "date_completed": null, + "score": "0", + "date_due": "0", + "category_id": "0", + "creator_id": "0", + "date_modification": "1409961789", + "reference": "", + "date_started": null, + "time_spent": "0", + "time_estimated": "0", + "swimlane_id": "0", + "date_moved": "1430783191", + "recurrence_status": "0", + "recurrence_trigger": "0", + "recurrence_factor": "0", + "recurrence_timeframe": "0", + "recurrence_basedate": "0", + "recurrence_parent": null, + "recurrence_child": null, + "url": "http:\/\/127.0.0.1:8000\/?controller=task&action=show&task_id=1&project_id=1" + }, + { + "id": "2", + "title": "Test", + "description": "", + "date_creation": "1409962115", + "color_id": "green", + "project_id": "1", + "column_id": "2", + "owner_id": "1", + "position": "2", + "is_active": "1", + "date_completed": null, + "score": "0", + "date_due": "0", + "category_id": "0", + "creator_id": "0", + "date_modification": "1409962115", + "reference": "", + "date_started": null, + "time_spent": "0", + "time_estimated": "0", + "swimlane_id": "0", + "date_moved": "1430783191", + "recurrence_status": "0", + "recurrence_trigger": "0", + "recurrence_factor": "0", + "recurrence_timeframe": "0", + "recurrence_basedate": "0", + "recurrence_parent": null, + "recurrence_child": null, + "url": "http:\/\/127.0.0.1:8000\/?controller=task&action=show&task_id=2&project_id=1" + }, + ... + ] +} +``` + +### getOverdueTasks + +- Purpose: **Get all overdue tasks** +- Result on success: **List of tasks** +- Result on failure: **false** + +Request example to fetch all tasks on the board: + +```json +{ + "jsonrpc": "2.0", + "method": "getOverdueTasks", + "id": 133280317 +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 133280317, + "result": [ + { + "id": "1", + "title": "Task #1", + "date_due": "1409961789", + "project_id": "1", + "project_name": "Test", + "assignee_username":"admin", + "assignee_name": null + }, + { + "id": "2", + "title": "Test", + "date_due": "1409962115", + "project_id": "1", + "project_name": "Test", + "assignee_username":"admin", + "assignee_name": null + }, + ... + ] +} +``` + +### updateTask + +- Purpose: **Update a task** +- Parameters: + - **id** (integer, required) + - **title** (string, optional) + - **project_id** (integer, optional) + - **color_id** (string, optional) + - **owner_id** (integer, optional) + - **creator_id** (integer, optional) + - **date_due**: ISO8601 format (string, optional) + - **description** Markdown content (string, optional) + - **category_id** (integer, optional) + - **score** (integer, optional) + - **recurrence_status** (integer, optional) + - **recurrence_trigger** (integer, optional) + - **recurrence_factor** (integer, optional) + - **recurrence_timeframe** (integer, optional) + - **recurrence_basedate** (integer, optional) +- Result on success: **true** +- Result on failure: **false** + +Request example to change the task color: + +```json +{ + "jsonrpc": "2.0", + "method": "updateTask", + "id": 1406803059, + "params": { + "id": 1, + "color_id": "blue" + } +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 1406803059, + "result": true +} +``` + +### openTask + +- Purpose: **Set a task to the status open** +- Parameters: + - **task_id** (integer, required) +- Result on success: **true** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "openTask", + "id": 1888531925, + "params": { + "task_id": 1 + } +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 1888531925, + "result": true +} +``` + +### closeTask + +- Purpose: **Set a task to the status close** +- Parameters: + - **task_id** (integer, required) +- Result on success: **true** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "closeTask", + "id": 1654396960, + "params": { + "task_id": 1 + } +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 1654396960, + "result": true +} +``` + +### removeTask + +- Purpose: **Remove a task** +- Parameters: + - **task_id** (integer, required) +- Result on success: **true** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "removeTask", + "id": 1423501287, + "params": { + "task_id": 1 + } +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 1423501287, + "result": true +} +``` + +### moveTaskPosition + +- Purpose: **Move a task to another column or another position** +- Parameters: + - **project_id** (integer, required) + - **task_id** (integer, required) + - **column_id** (integer, required) + - **position** (integer, required) + - **swimlane_id** (integer, optional, default=0) +- Result on success: **true** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "moveTaskPosition", + "id": 117211800, + "params": { + "project_id": 1, + "task_id": 1, + "column_id": 2, + "position": 1 + } +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 117211800, + "result": true +} +``` + +### createUser + +- Purpose: **Create a new user** +- Parameters: + - **username** Must be unique (string, required) + - **password** Must have at least 6 characters (string, required) + - **name** (string, optional) + - **email** (string, optional) + - **is_admin** Set the value 1 for admins or 0 for regular users (integer, optional) + - **is_project_admin** Set the value 1 for project admins or 0 for regular users (integer, optional) +- Result on success: **user_id** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "createUser", + "id": 1518863034, + "params": { + "username": "biloute", + "password": "123456" + } +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 1518863034, + "result": 22 +} +``` + +### createLdapUser + +- Purpose: **Create a new user authentified by LDAP** +- Parameters: + - **username** (string, optional if email is set) + - **email** (string, optional if username is set) + - **is_admin** Set the value 1 for admins or 0 for regular users (integer, optional) + - **is_project_admin** Set the value 1 for project admins or 0 for regular users (integer, optional) +- Result on success: **user_id** +- Result on failure: **false** + +The user will only be created if a matching is found on the LDAP server. +Username or email (or both) must be provided. + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "createLdapUser", + "id": 1518863034, + "params": { + "username": "biloute", + } +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 1518863034, + "result": 22 +} +``` + +### getUser + +- Purpose: **Get user information** +- Parameters: + - **user_id** (integer, required) +- Result on success: **user properties** +- Result on failure: **null** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "getUser", + "id": 1769674781, + "params": { + "user_id": 1 + } +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 1769674781, + "result": { + "id": "1", + "username": "biloute", + "password": "$2y$10$dRs6pPoBu935RpmsrhmbjevJH5MgZ7Kr9QrnVINwwyZ3.MOwqg.0m", + "is_admin": "0", + "is_ldap_user": "0", + "name": "", + "email": "", + "google_id": null, + "github_id": null, + "notifications_enabled": "0" + } +} +``` + +### getAllUsers + +- Purpose: **Get all available users** +- Parameters: + - **none** +- Result on success: **List of users** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "getAllUsers", + "id": 1438712131 +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 1438712131, + "result": [ + { + "id": "1", + "username": "biloute", + "name": "", + "email": "", + "is_admin": "0", + "is_ldap_user": "0", + "notifications_enabled": "0", + "google_id": null, + "github_id": null + }, + ... + ] +} +``` + +### updateUser + +- Purpose: **Update a user** +- Parameters: + - **id** (integer) + - **username** (string, optional) + - **name** (string, optional) + - **email** (string, optional) + - **is_admin** (integer, optional) + - **is_project_admin** Set the value 1 for project admins or 0 for regular users (integer, optional) +- Result on success: **true** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "updateUser", + "id": 322123657, + "params": { + "id": 1, + "is_admin": 1 + } +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 322123657, + "result": true +} +``` + +### removeUser + +- Purpose: **Remove a user** +- Parameters: + - **user_id** (integer, required) +- Result on success: **true** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "removeUser", + "id": 2094191872, + "params": { + "user_id": 1 + } +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 2094191872, + "result": true +} +``` + + +### createCategory + +- Purpose: **Create a new category** +- Parameters: +- **project_id** (integer, required) + - **name** (string, required, must be unique for the given project) +- Result on success: **category_id** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "createCategory", + "id": 541909890, + "params": { + "name": "Super category", + "project_id": 1 + } +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 541909890, + "result": 4 +} +``` + +### getCategory + +- Purpose: **Get category information** +- Parameters: + - **category_id** (integer, required) +- Result on success: **category properties** +- Result on failure: **null** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "getCategory", + "id": 203539163, + "params": { + "category_id": 1 + } +} +``` + +Response example: + +```json +{ + + "jsonrpc": "2.0", + "id": 203539163, + "result": { + "id": "1", + "name": "Super category", + "project_id": "1" + } +} +``` + +### getAllCategories + +- Purpose: **Get all available categories** +- Parameters: + - **project_id** (integer, required) +- Result on success: **List of categories** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "getAllCategories", + "id": 1261777968, + "params": { + "project_id": 1 + } +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 1261777968, + "result": [ + { + "id": "1", + "name": "Super category", + "project_id": "1" + } + ] +} +``` + +### updateCategory + +- Purpose: **Update a category** +- Parameters: + - **id** (integer, required) + - **name** (string, required) +- Result on success: **true** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "updateCategory", + "id": 570195391, + "params": { + "id": 1, + "name": "Renamed category" + } +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 570195391, + "result": true +} +``` + +### removeCategory + +- Purpose: **Remove a category** +- Parameters: + - **category_id** (integer) +- Result on success: **true** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "removeCategory", + "id": 88225706, + "params": { + "category_id": 1 + } +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 88225706, + "result": true +} +``` + + +### createComment + +- Purpose: **Create a new comment** +- Parameters: + - **task_id** (integer, required) + - **user_id** (integer, required) + - **content** Markdown content (string, required) +- Result on success: **comment_id** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "createComment", + "id": 1580417921, + "params": { + "task_id": 1, + "user_id": 1, + "content": "Comment #1" + } +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 1580417921, + "result": 11 +} +``` + +### getComment + +- Purpose: **Get comment information** +- Parameters: + - **comment_id** (integer, required) +- Result on success: **comment properties** +- Result on failure: **null** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "getComment", + "id": 867839500, + "params": { + "comment_id": 1 + } +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 867839500, + "result": { + "id": "1", + "task_id": "1", + "user_id": "1", + "date_creation": "1410881970", + "comment": "Comment #1", + "username": "admin", + "name": null + } +} +``` + +### getAllComments + +- Purpose: **Get all available comments** +- Parameters: + - **task_id** (integer, required) +- Result on success: **List of comments** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "getAllComments", + "id": 148484683, + "params": { + "task_id": 1 + } +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 148484683, + "result": [ + { + "id": "1", + "date_creation": "1410882272", + "task_id": "1", + "user_id": "1", + "comment": "Comment #1", + "username": "admin", + "name": null + }, + ... + ] +} +``` + +### updateComment + +- Purpose: **Update a comment** +- Parameters: + - **id** (integer, required) + - **content** Markdown content (string, required) +- Result on success: **true** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "updateComment", + "id": 496470023, + "params": { + "id": 1, + "content": "Comment #1 updated" + } +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 1493368950, + "result": true +} +``` + +### removeComment + +- Purpose: **Remove a comment** +- Parameters: + - **comment_id** (integer, required) +- Result on success: **true** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "removeComment", + "id": 328836871, + "params": { + "comment_id": 1 + } +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 328836871, + "result": true +} +``` + +### createSubtask + +- Purpose: **Create a new subtask** +- Parameters: + - **task_id** (integer, required) + - **title** (integer, required) + - **user_id** (int, optional) + - **time_estimated** (int, optional) + - **time_spent** (int, optional) + - **status** (int, optional) +- Result on success: **subtask_id** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "createSubtask", + "id": 2041554661, + "params": { + "task_id": 1, + "title": "Subtask #1" + } +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 2041554661, + "result": 45 +} +``` + +### getSubtask + +- Purpose: **Get subtask information** +- Parameters: + - **subtask_id** (integer) +- Result on success: **subtask properties** +- Result on failure: **null** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "getSubtask", + "id": 133184525, + "params": { + "subtask_id": 1 + } +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 133184525, + "result": { + "id": "1", + "title": "Subtask #1", + "status": "0", + "time_estimated": "0", + "time_spent": "0", + "task_id": "1", + "user_id": "0" + } +} +``` + +### getAllSubtasks + +- Purpose: **Get all available subtasks** +- Parameters: + - **task_id** (integer, required) +- Result on success: **List of subtasks** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "getAllSubtasks", + "id": 2087700490, + "params": { + "task_id": 1 + } +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 2087700490, + "result": [ + { + "id": "1", + "title": "Subtask #1", + "status": "0", + "time_estimated": "0", + "time_spent": "0", + "task_id": "1", + "user_id": "0", + "username": null, + "name": null, + "status_name": "Todo" + }, + ... + ] +} +``` + +### updateSubtask + +- Purpose: **Update a subtask** +- Parameters: + - **id** (integer, required) + - **task_id** (integer, required) + - **title** (integer, optional) + - **user_id** (integer, optional) + - **time_estimated** (integer, optional) + - **time_spent** (integer, optional) + - **status** (integer, optional) +- Result on success: **true** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "updateSubtask", + "id": 191749979, + "params": { + "id": 1, + "task_id": 1, + "status": 1, + "time_spent": 5, + "user_id": 1 + } +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 191749979, + "result": true +} +``` + +### removeSubtask + +- Purpose: **Remove a subtask** +- Parameters: + - **subtask_id** (integer, required) +- Result on success: **true** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "removeSubtask", + "id": 1382487306, + "params": { + "subtask_id": 1 + } +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 1382487306, + "result": true +} +``` + +### getAllLinks + +- Purpose: **Get the list of possible relations between tasks** +- Parameters: none +- Result on success: **List of links** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "getAllLinks", + "id": 113057196 +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 113057196, + "result": [ + { + "id": "1", + "label": "relates to", + "opposite_id": "0" + }, + { + "id": "2", + "label": "blocks", + "opposite_id": "3" + }, + { + "id": "3", + "label": "is blocked by", + "opposite_id": "2" + }, + { + "id": "4", + "label": "duplicates", + "opposite_id": "5" + }, + { + "id": "5", + "label": "is duplicated by", + "opposite_id": "4" + }, + { + "id": "6", + "label": "is a child of", + "opposite_id": "7" + }, + { + "id": "7", + "label": "is a parent of", + "opposite_id": "6" + }, + { + "id": "8", + "label": "targets milestone", + "opposite_id": "9" + }, + { + "id": "9", + "label": "is a milestone of", + "opposite_id": "8" + }, + { + "id": "10", + "label": "fixes", + "opposite_id": "11" + }, + { + "id": "11", + "label": "is fixed by", + "opposite_id": "10" + } + ] +} +``` + +### getOppositeLinkId + +- Purpose: **Get the opposite link id of a task link** +- Parameters: + - **link_id** (integer, required) +- Result on success: **link_id** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "getOppositeLinkId", + "id": 407062448, + "params": [ + 2 + ] +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 407062448, + "result": "3" +} +``` + +### getLinkByLabel + +- Purpose: **Get a link by label** +- Parameters: + - **label** (integer, required) +- Result on success: **link properties** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "getLinkByLabel", + "id": 1796123316, + "params": [ + "blocks" + ] +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 1796123316, + "result": { + "id": "2", + "label": "blocks", + "opposite_id": "3" + } +} +``` + +### getLinkById + +- Purpose: **Get a link by id** +- Parameters: + - **link_id** (integer, required) +- Result on success: **link properties** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "getLinkById", + "id": 1190238402, + "params": [ + 4 + ] +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 1190238402, + "result": { + "id": "4", + "label": "duplicates", + "opposite_id": "5" + } +} +``` + +### createLink + +- Purpose: **Create a new task relation** +- Parameters: + - **label** (integer, required) + - **opposite_label** (integer, optional) +- Result on success: **link_id** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "createLink", + "id": 1040237496, + "params": [ + "foo", + "bar" + ] +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 1040237496, + "result": 13 +} +``` + +### updateLink + +- Purpose: **Update a link** +- Parameters: + - **link_id** (integer, required) + - **opposite_link_id** (integer, required) + - **label** (string, required) +- Result on success: **true** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "updateLink", + "id": 2110446926, + "params": [ + "14", + "12", + "boo" + ] +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 2110446926, + "result": true +} +``` + +### removeLink + +- Purpose: **Remove a link** +- Parameters: + - **link_id** (integer, required) +- Result on success: **true** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "removeLink", + "id": 2136522739, + "params": [ + "14" + ] +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 2136522739, + "result": true +} +``` + +### createTaskLink + +- Purpose: **Create a link between two tasks** +- Parameters: + - **task_id** (integer, required) + - **opposite_task_id** (integer, required) + - **link_id** (integer, required) +- Result on success: **task_link_id** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "createTaskLink", + "id": 509742912, + "params": [ + 2, + 3, + 1 + ] +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 509742912, + "result": 1 +} +``` + +### updateTaskLink + +- Purpose: **Update task link** +- Parameters: + - **task_link_id** (integer, required) + - **task_id** (integer, required) + - **opposite_task_id** (integer, required) + - **link_id** (integer, required) +- Result on success: **true** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "updateTaskLink", + "id": 669037109, + "params": [ + 1, + 2, + 4, + 2 + ] +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 669037109, + "result": true +} +``` + +### getTaskLinkById + +- Purpose: **Get a task link** +- Parameters: + - **task_link_id** (integer, required) +- Result on success: **task link properties** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "getTaskLinkById", + "id": 809885202, + "params": [ + 1 + ] +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 809885202, + "result": { + "id": "1", + "link_id": "1", + "task_id": "2", + "opposite_task_id": "3" + } +} +``` + +### getAllTaskLinks + +- Purpose: **Get all links related to a task** +- Parameters: + - **task_id** (integer, required) +- Result on success: **list of task link** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "getAllTaskLinks", + "id": 810848359, + "params": [ + 2 + ] +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 810848359, + "result": [ + { + "id": "1", + "task_id": "3", + "label": "relates to", + "title": "B", + "is_active": "1", + "project_id": "1", + "task_time_spent": "0", + "task_time_estimated": "0", + "task_assignee_id": "0", + "task_assignee_username": null, + "task_assignee_name": null, + "column_title": "Backlog" + } + ] +} +``` + +### removeTaskLink + +- Purpose: **Remove a link between two tasks** +- Parameters: + - **task_link_id** (integer, required) +- Result on success: **true** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "removeTaskLink", + "id": 473028226, + "params": [ + 1 + ] +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 473028226, + "result": true +} +``` + +### createFile + +- Purpose: **Create and upload a new task attachment** +- Parameters: + - **project_id** (integer, required) + - **task_id** (integer, required) + - **filename** (integer, required) + - **blob** File content encoded in base64 (string, required) +- Result on success: **file_id** +- Result on failure: **false** +- Note: **The maximum file size depends of your PHP configuration, this method should not be used to upload large files** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "createFile", + "id": 94500810, + "params": [ + 1, + 1, + "My file", + "cGxhaW4gdGV4dCBmaWxl" + ] +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 94500810, + "result": 1 +} +``` + +### getAllFiles + +- Purpose: **Get all files attached to task** +- Parameters: + - **task_id** (integer, required) +- Result on success: **list of files** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "getAllFiles", + "id": 1880662820, + "params": { + "task_id": 1 + } +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 1880662820, + "result": [ + { + "id": "1", + "name": "My file", + "path": "1\/1\/0db4d0a897a4c852f6e12f0239d4805f7b4ab596", + "is_image": "0", + "task_id": "1", + "date": "1432509941", + "user_id": "0", + "size": "15", + "username": null, + "user_name": null + } + ] +} +``` + +### getFile + +- Purpose: **Get file information** +- Parameters: + - **file_id** (integer, required) +- Result on success: **file properties** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "getFile", + "id": 318676852, + "params": [ + "1" + ] +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 318676852, + "result": { + "id": "1", + "name": "My file", + "path": "1\/1\/0db4d0a897a4c852f6e12f0239d4805f7b4ab596", + "is_image": "0", + "task_id": "1", + "date": "1432509941", + "user_id": "0", + "size": "15" + } +} +``` + +### downloadFile + +- Purpose: **Download file contents (encoded in base64)** +- Parameters: + - **file_id** (integer, required) +- Result on success: **base64 encoded string** +- Result on failure: **empty string** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "downloadFile", + "id": 235943344, + "params": [ + "1" + ] +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 235943344, + "result": "cGxhaW4gdGV4dCBmaWxl" +} +``` + +### removeFile + +- Purpose: **Remove file** +- Parameters: + - **file_id** (integer, required) +- Result on success: **true** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "removeFile", + "id": 447036524, + "params": [ + "1" + ] +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 447036524, + "result": true +} +``` + +### removeAllFiles + +- Purpose: **Remove all files associated to a task** +- Parameters: + - **task_id** (integer, required) +- Result on success: **true** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "removeAllFiles", + "id": 593312993, + "params": { + "task_id": 1 + } +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 593312993, + "result": true +} +``` + +### getMe + +- Purpose: **Get logged user session** +- Parameters: None +- Result on success: **user session data** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "getMe", + "id": 1718627783 +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 1718627783, + "result": { + "id": 2, + "username": "user", + "is_admin": false, + "is_ldap_user": false, + "name": "", + "email": "", + "google_id": null, + "github_id": null, + "notifications_enabled": "0", + "timezone": null, + "language": null, + "disable_login_form": "0", + "twofactor_activated": false, + "twofactor_secret": null, + "token": "", + "notifications_filter": "4" + } +} +``` + +### getMyDashboard + +- Purpose: **Get the dashboard of the logged user without pagination** +- Parameters: None +- Result on success: **Dashboard information** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "getMyDashboard", + "id": 447898718 +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 1563664593, + "result": { + "projects": [ + { + "id": "2", + "name": "my project", + "is_active": "1", + "token": "", + "last_modified": "1438205337", + "is_public": "0", + "is_private": "1", + "is_everybody_allowed": "0", + "default_swimlane": "Default swimlane", + "show_default_swimlane": "1", + "description": null, + "identifier": "", + "columns": [ + { + "id": "5", + "title": "Backlog", + "position": "1", + "project_id": "2", + "task_limit": "0", + "description": "", + "nb_tasks": 0 + }, + { + "id": "6", + "title": "Ready", + "position": "2", + "project_id": "2", + "task_limit": "0", + "description": "", + "nb_tasks": 0 + }, + { + "id": "7", + "title": "Work in progress", + "position": "3", + "project_id": "2", + "task_limit": "0", + "description": "", + "nb_tasks": 0 + }, + { + "id": "8", + "title": "Done", + "position": "4", + "project_id": "2", + "task_limit": "0", + "description": "", + "nb_tasks": 0 + } + ], + "url": { + "board": "http:\/\/127.0.0.1:8000\/?controller=board&action=show&project_id=2", + "calendar": "http:\/\/127.0.0.1:8000\/?controller=calendar&action=show&project_id=2", + "list": "http:\/\/127.0.0.1:8000\/?controller=listing&action=show&project_id=2" + } + } + ], + "tasks": [ + { + "id": "1", + "title": "new title", + "date_due": "0", + "date_creation": "1438205336", + "project_id": "2", + "color_id": "yellow", + "time_spent": "0", + "time_estimated": "0", + "project_name": "my project", + "url": "http:\/\/127.0.0.1:8000\/?controller=task&action=show&task_id=1&project_id=2" + } + ], + "subtasks": [] + } +} +``` + +### getMyActivityStream + +- Purpose: **Get the last 100 events for the logged user** +- Parameters: None +- Result on success: **List of events** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "getMyActivityStream", + "id": 1132562181 +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 1132562181, + "result": [ + { + "id": "1", + "date_creation": "1438205054", + "event_name": "task.create", + "creator_id": "2", + "project_id": "2", + "task_id": "1", + "author_username": "user", + "author_name": "", + "email": "", + "task": { + "id": "1", + "reference": "", + "title": "my user title", + "description": "", + "date_creation": "1438205054", + "date_completed": null, + "date_modification": "1438205054", + "date_due": "0", + "date_started": null, + "time_estimated": "0", + "time_spent": "0", + "color_id": "yellow", + "project_id": "2", + "column_id": "5", + "owner_id": "0", + "creator_id": "2", + "position": "1", + "is_active": "1", + "score": "0", + "category_id": "0", + "swimlane_id": "0", + "date_moved": "1438205054", + "recurrence_status": "0", + "recurrence_trigger": "0", + "recurrence_factor": "0", + "recurrence_timeframe": "0", + "recurrence_basedate": "0", + "recurrence_parent": null, + "recurrence_child": null, + "category_name": null, + "swimlane_name": null, + "project_name": "my project", + "default_swimlane": "Default swimlane", + "column_title": "Backlog", + "assignee_username": null, + "assignee_name": null, + "creator_username": "user", + "creator_name": "" + }, + "changes": [], + "author": "user", + "event_title": "user created the task #1", + "event_content": "\n

    \n user created the task #1<\/a><\/p>\n

    \n my user title<\/em>\n<\/p>" + } + ] +} +``` + +### createMyPrivateProject + +- Purpose: **Create a private project for the logged user** +- Parameters: + - **name** (string, required) + - **description** (string, optional) +- Result on success: **project_id** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "createMyPrivateProject", + "id": 1271580569, + "params": [ + "my project" + ] +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 1271580569, + "result": 2 +} +``` + +### getMyProjectsList + +- Purpose: **Get projects of the connected user** +- Parameters: None +- Result on success: **dictionary of project_id => project_name** +- Result on failure: **false** + +Request example: + +```json +{ + "jsonrpc": "2.0", + "method": "getMyProjectsList", + "id": 987834805 +} +``` + +Response example: + +```json +{ + "jsonrpc": "2.0", + "id": 987834805, + "result": { + "2": "my project" + } +} +``` diff --git a/doc/application-configuration.markdown b/doc/application-configuration.markdown new file mode 100644 index 00000000..32710a39 --- /dev/null +++ b/doc/application-configuration.markdown @@ -0,0 +1,40 @@ +Application settings +==================== + +Some parameters for the application can be changed on the settings page. +Only administrators can change those settings. + +Go to the menu **Settings**, then choose **Application settings** on the left. + +![Application settings](http://kanboard.net/screenshots/documentation/application-settings.png) + +### Application URL + +This parameter is used for email notifications. +The email footer will contains a link to the Kanboard task. + +### Language + +The application language can be changed at anytime. +The language will be set for all users. + +### Timezone + +By default, Kanboard use UTC as timezone, but you can define your own timezone. +The list contains all supported timezones by your web server. + +### Date format + +Input format used for date fields, by example the due date for tasks. + +Kanboard offer 3 different choices: + +- DD/MM/YYYY +- MM/DD/YYYY (default) +- YYYY/MM/DD + +The [ISO 8601](http://en.wikipedia.org/wiki/ISO_8601) format is always accepted (YYYY-MM-DD or YYYY_MM_DD). + +### Custom Stylesheet + +Write your own CSS to override or improve Kanboard default style. diff --git a/doc/assets.markdown b/doc/assets.markdown new file mode 100644 index 00000000..29bf515b --- /dev/null +++ b/doc/assets.markdown @@ -0,0 +1,25 @@ +How to build assets (Javascript and CSS files) +============================================== + +Stylesheet and Javascript files are merged together and minified. + +- Original CSS files are stored in the folder `assets/css/src/*.css` +- Original Javascript code is stored in the folder `assets/js/src/*.js` + +Requirements +------------ + +- Unix operating system +- make +- yuicompressor in your path (`brew install yuicompressor`) + +Build assets +------------ + +- Build Stylesheet files: `make css` +- Build Javascript files: `make js` +- Build both: `make` + +This script generates the files `assets/css/app.css` and `assets/js/app.js`. + +This tool is only available in the repository (development version). diff --git a/doc/automatic-actions.markdown b/doc/automatic-actions.markdown new file mode 100644 index 00000000..c4e2bc4c --- /dev/null +++ b/doc/automatic-actions.markdown @@ -0,0 +1,138 @@ +Automatic Actions +================= + +To minimize the user interaction, Kanboard support automatic actions. + +Each automatic action is defined like that: + +- An event to listen +- An action linked to this event +- Eventually there is some parameters to define + +Each project can have a different set of automatic actions, the configuration panel is located on the project listing page, just click on the link **Automatic actions**. + +Add a new action +---------------- + +### Choose an action + +![Choose an action](http://kanboard.net/screenshots/documentation/project-automatic-action-step1.png) + +### Choose an event + +![Choose an event](http://kanboard.net/screenshots/documentation/project-automatic-action-step2.png) + +### Define action parameters + +![Define parameters](http://kanboard.net/screenshots/documentation/project-automatic-action-step3.png) + +List of available events +------------------------ + +- Move a task to another column +- Move a task to another position in the same column +- Task modification +- Task creation +- Reopen a task +- Closing a task +- Task creation or modification +- Task assignee change +- Task link created or updated +- Github commit received +- Github issue opened +- Github issue closed +- Github issue reopened +- Github issue assignee change +- Github issue label change +- Github issue comment created +- Gitlab issue opened +- Gitlab issue closed +- Gitlab commit received +- Bitbucket commit received +- Bitbucket issue opened +- Bitbucket issue closed +- Bitbucket issue reopened +- Bitbucket issue assignee change +- Bitbucket issue comment created + +List of available actions +------------------------- + +- Close the task +- Open a task +- Assign the task to a specific user +- Assign the task to the person who does the action +- Duplicate the task to another project +- Move the task to another project +- Move the task to another column when assigned to a user +- Move the task to another column when assignee is cleared +- Assign a color when the task is moved to a specific column +- Assign a color to a specific user +- Assign automatically a color based on a category +- Assign automatically a category based on a color +- Create a comment from an external provider +- Create a task from an external provider +- Add a comment log when moving the task between columns +- Change the assignee based on an external username +- Change the category based on an external label +- Automatically update the start date +- Move the task to another column when the category is changed +- Send a task by email to someone +- Change task color when using a specific task link + +Examples +-------- + +Here are some examples used in the real life: + +### When I move a task to the column "Done", automatically close this task + +- Choose the action: **Close the task** +- Choose the event: **Move a task to another column** +- Define the action parameter: **Column = Done** (this is the destination column) + +### When I move a task to the column "To be validated", assign this task to a specific user + +- Choose the action: **Assign the task to a specific user** +- Choose the event: **Move a task to another column** +- Define the action parameters: **Column = To be validated** and **User = Bob** (Bob is our tester) + +### When I move a task to the column "Work in progress", assign this task to the current user + +- Choose the action: **Assign the task to the person who does the action** +- Choose the event: **Move a task to another column** +- Define the action parameter: **Column = Work in progress** + +### When a task is completed, duplicate this task to another project + +Let's say we have two projects "Customer orders" and "Production", once the order is validated, swap it to the "Production" project. + +- Choose the action: **Duplicate the task to another project** +- Choose the event: **Closing a task** +- Define the action parameters: **Column = Validated** and **Project = Production** + +### When a task is moved to the last column, move the exact same task to another project + +Let's say we have two projects "Ideas" and "Development", once the idea is validated, swap it to the "Development" project. + +- Choose the action: **Move the task to another project** +- Choose the event: **Move a task to another column** +- Define the action parameters: **Column = Validated** and **Project = Development** + +### I want to assign automatically a color to the user Bob + +- Choose the action: **Assign a color to a specific user** +- Choose the event: **Task assignee change** +- Define the action parameters: **Color = Green** and **Assignee = Bob** + +### I want to assign automatically a color to the defined category "Feature Request" + +- Choose the action: **Assign automatically a color based on a category** +- Choose the event: **Task creation or modification** +- Define the action parameters: **Color = Blue** and **Category = Feature Request** + +### I want to set the start date automatically when the task is moved to the column "Work in progress" + +- Choose the action: **Automatically update the start date** +- Choose the event: **Move a task to another column** +- Define the action parameters: **Column = Work in progress** diff --git a/doc/bitbucket-webhooks.markdown b/doc/bitbucket-webhooks.markdown new file mode 100644 index 00000000..7f59aa11 --- /dev/null +++ b/doc/bitbucket-webhooks.markdown @@ -0,0 +1,55 @@ +Bitbucket webhooks +================== + +Bitbucket events can be connected to Kanboard automatic actions. + +List of supported events +------------------------ + +- Bitbucket commit received +- Bitbucket issue opened +- Bitbucket issue closed +- Bitbucket issue reopened +- Bitbucket issue assignee change +- Bitbucket issue comment created + +List of supported actions +------------------------- + +- Create a task from an external provider +- Change the assignee based on an external username +- Create a comment from an external provider +- Close a task +- Open a task + +Configuration +------------- + +![Bitbucket configuration](http://kanboard.net/screenshots/documentation/bitbucket-webhooks.png) + +1. On Kanboard, go to the project settings and choose the section **Integrations** +2. Copy the Bitbucket webhook url +3. On Bitbucket, go to the project settings and go to the section **Webhooks** +4. Choose a title for your webhook and paste the Kanboard url + +Examples +-------- + +### Close a Kanboard task when a commit pushed to Bitbucket + +- Choose the event: **Bitbucket commit received** +- Choose the action: **Close the task** + +When one or more commits are sent to Bitbucket, Kanboard will receive the information, each commit message with a task number included will be closed. + +Example: + +- Commit message: "Fix bug #1234" +- That will close the Kanboard task #1234 + +### Add comment when a commit received + +- Choose the event: **Bitbucket commit received** +- Choose the action: **Create a comment from an external provider** + +The comment will contains the commit message and the url to the commit. diff --git a/doc/board-collapsed-expanded.markdown b/doc/board-collapsed-expanded.markdown new file mode 100644 index 00000000..e094e817 --- /dev/null +++ b/doc/board-collapsed-expanded.markdown @@ -0,0 +1,19 @@ +Collapsed and Expanded mode +=========================== + +Tasks on the board can be displayed in collapsed or in expanded mode. +Switching from one view to another can be done with the keyboard shortcut **"s"** or by using the dropdown menu on the left. + +Collapsed mode +-------------- + +![Tasks collapsed](http://kanboard.net/screenshots/documentation/board-collapsed-mode.png) + +- If the task is assigned to someone, the initials of the person are shown next to the task number +- If the task title is too long, you can put your mouse over the task to show a tooltip with the full title. + +Expanded mode +------------- + +![Tasks expanded](http://kanboard.net/screenshots/documentation/board-expanded-mode.png) + diff --git a/doc/board-configuration.markdown b/doc/board-configuration.markdown new file mode 100644 index 00000000..1c5ff51a --- /dev/null +++ b/doc/board-configuration.markdown @@ -0,0 +1,24 @@ +Board settings +============== + +Go to the menu **Settings**, then choose **Board settings** on the left. + +![Board settings](http://kanboard.net/screenshots/documentation/board-settings.png) + +### Task highlighting + +This feature display a shadow around the task when a task is moved recently. + +Set the value 0 to disable this feature, 2 days by default (172800 seconds). + +Everything moved since 2 days will have shadow around the task. + +### Refresh interval for public board + +When you share a board, the page will refresh automatically every 60 seconds by default. + +### Refresh interval for private board + +When your web browser is open on a board, Kanboard check every 10 seconds if something have been changed by someone else. + +Technically this process is done by Ajax polling. diff --git a/doc/board-horizontal-scrolling-and-compact-view.markdown b/doc/board-horizontal-scrolling-and-compact-view.markdown new file mode 100644 index 00000000..16d1e74c --- /dev/null +++ b/doc/board-horizontal-scrolling-and-compact-view.markdown @@ -0,0 +1,12 @@ +Horizontal scrolling and compact mode +===================================== + +When the board can't fit on your screen, an horizontal scroll bar will appear at the bottom. + +However, it's possible to switch to the compact the view to display all columns in your screen. + +![Board in compact mode](http://kanboard.net/screenshots/documentation/board-compact-mode.png) + +Switching between horizontal scrolling and compact view can be done with the keyboard shortcut **"c"** or by using the dropdown menu on the top left. + +Note: It's possible that text overlaps in compact mode, that will be improved over the next releases. \ No newline at end of file diff --git a/doc/board-show-hide-columns.markdown b/doc/board-show-hide-columns.markdown new file mode 100644 index 00000000..e459f555 --- /dev/null +++ b/doc/board-show-hide-columns.markdown @@ -0,0 +1,11 @@ +Show and hide columns on the board +================================== + +You can hide or display columns very easily on the board: + +![Board with hidden columns](http://kanboard.net/screenshots/documentation/board-hide-show-column.png) + +- To hide a column, just click on the column title +- To show a hidden column, click on the vertical title + +When a column is hidden the number of tasks is displayed at the top. diff --git a/doc/bruteforce-protection.markdown b/doc/bruteforce-protection.markdown new file mode 100644 index 00000000..633cfe87 --- /dev/null +++ b/doc/bruteforce-protection.markdown @@ -0,0 +1,26 @@ +Bruteforce Protection +===================== + +The brute force protection of Kanboard works at the user account level: + +- After 3 authentication failure for the same username, the login form show a captcha image to prevent automated bot tentatives. +- After 6 authentication failure, the user account is locked down for a period of 15 minutes. + +This feature works only for authentication methods that use the login form. + +However, **after 3 authentication failure through the user API**, the account have to be unlocked by using the login form. + +Kanboard doesn't block any IP addresses since bots can use several anonymous proxies. However, you can use external tools like [fail2ban](http://www.fail2ban.org) to avoid massive scans. + +Default settings can be changed with these configuration variables: + +```php +// Enable captcha after 3 authentication failure +define('BRUTEFORCE_CAPTCHA', 3); + +// Lock the account after 6 authentication failure +define('BRUTEFORCE_LOCKDOWN', 6); + +// Lock account duration in minute +define('BRUTEFORCE_LOCKDOWN_DURATION', 15); +``` diff --git a/doc/budget.markdown b/doc/budget.markdown new file mode 100644 index 00000000..63408d46 --- /dev/null +++ b/doc/budget.markdown @@ -0,0 +1,34 @@ +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/calendar-configuration.markdown b/doc/calendar-configuration.markdown new file mode 100644 index 00000000..95e13e52 --- /dev/null +++ b/doc/calendar-configuration.markdown @@ -0,0 +1,42 @@ +Calendar settings +================= + +Go to the menu **Settings**, then choose **Calendar settings** on the left. + +![Calendar settings](http://kanboard.net/screenshots/documentation/calendar-settings.png) + +There are two different calendars in Kanboard: + +- Project calendar +- User calendar (available from the dashboard) + +Project calendar +---------------- + +This calendar show tasks with defined due date and tasks based on the creation date or the start date. + +### Show tasks based on the creation date + +- The start date of the calendar event is the creation date of the task. +- The end date of the event is the date of completion. + +### Show tasks based on the start date + +- The start date of the calendar event is the start date of the task. +- This date can be defined manually. +- The end date of the event is the date of completion. +- If there is no start date the task will not appear on the calendar. + +User calendar +------------- + +This calendar show only tasks assigned to the user and optionally subtasks information. + +### Show subtasks based on the time tracking + +- Display subtasks in the calendar from the information recorded in the time tracking table. +- The intersection with the user timetable is also calculated. + +### Show subtask estimates (forecast of future work) + +- Display the estimate of future work for subtasks in status "todo" and with a defined "estimate" value. diff --git a/doc/calendar.markdown b/doc/calendar.markdown new file mode 100644 index 00000000..7b95baa2 --- /dev/null +++ b/doc/calendar.markdown @@ -0,0 +1,20 @@ +Calendar +======== + +There are two different views for the calendar: + +- The project view with filters (available from the board) +- The user view (available from the dashboard and from the user section) + +At this time the calendar is able to display these information: + +- Tasks with a due date, displayed at the top. **The due date can be changed by moving the task to another day**. +- Tasks based on the creation date or the start date. **These events cannot be modified with the calendar**. +- Subtask time tracking, all recorded time slot will be shown in the calendar. +- Subtask estimates, forecast of work left + +![Calendar](http://kanboard.net/screenshots/documentation/calendar.png) + +The calendar configuration can be changed in the settings page. + +Note: The due date doesn't contains time information. diff --git a/doc/centos-installation.markdown b/doc/centos-installation.markdown new file mode 100644 index 00000000..6cfc31ff --- /dev/null +++ b/doc/centos-installation.markdown @@ -0,0 +1,77 @@ +Centos Installation +=================== + +Centos 7 +-------- + +Install PHP and Apache: + +```bash +yum install -y php php-mbstring php-pdo php-gd unzip wget +``` + +By default Centos 7 use PHP 5.4.16 and Apache 2.4.6. + +Restart Apache: + +```bash +systemctl restart httpd.service +``` + +Install Kanboard: + +```bash +cd /var/www/html +wget http://kanboard.net/kanboard-latest.zip +unzip kanboard-latest.zip +chown -R apache:apache kanboard/data +rm kanboard-latest.zip +``` + +If SELinux is enabled, be sure that the Apache user can write to the directory data: + +```bash +chcon -R -t httpd_sys_content_rw_t /var/www/html/kanboard/data +``` + +Be sure to configure your server to allow Kanboard to send emails and make external network requests, by example with SELinux: + +```bash +setsebool -P httpd_can_network_connect=1 +``` + +Allowing external connections is necessary if you use LDAP, SMTP, Webhooks or any third-party integrations. + +Centos 6.x +---------- + +Install PHP and Apache: + +```bash +yum install -y php php-mbstring php-pdo php-gd unzip wget +``` + +By default Centos 6.5 use PHP 5.3.3 and Apache 2.2.15. + +Enable short tags: + +- Edit the file `/etc/php.ini` +- Change the line `short_open_tag = On` + +Restart Apache: + +```bash +service httpd restart +``` + +Install Kanboard: + +```bash +cd /var/www/html +wget http://kanboard.net/kanboard-latest.zip +unzip kanboard-latest.zip +chown -R apache:apache kanboard/data +rm kanboard-latest.zip +``` + +Go to `http://your_server/kanboard/`. \ No newline at end of file diff --git a/doc/cli.markdown b/doc/cli.markdown new file mode 100644 index 00000000..38cba496 --- /dev/null +++ b/doc/cli.markdown @@ -0,0 +1,144 @@ +Command Line Interface +====================== + +Kanboard provide a simple command line interface that can be used from any Unix terminal. +This tool can be used only on the local machine. + +This feature is useful to run commands outside the web server process by example running a huge report. + +Usage +----- + +- Open a terminal and go to your Kanboard directory (example: `cd /var/www/kanboard`) +- Run the command `./kanboard` + +```bash +Kanboard version master + +Usage: + command [options] [arguments] + +Options: + -h, --help Display this help message + -q, --quiet Do not output any message + -V, --version Display this application version + --ansi Force ANSI output + --no-ansi Disable ANSI output + -n, --no-interaction Do not ask any interactive question + -v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug + +Available commands: + help Displays help for a command + list Lists commands + export + export:daily-project-column-stats Daily project column stats CSV export (number of tasks per column and per day) + export:subtasks Subtasks CSV export + export:tasks Tasks CSV export + export:transitions Task transitions CSV export + locale + locale:compare Compare application translations with the fr_FR locale + locale:sync Synchronize all translations based on the fr_FR locale + notification + notification:overdue-tasks Send notifications for overdue tasks + projects + projects:daily-stats Calculate daily statistics for all projects +``` + +Available commands +------------------ + +### Tasks CSV export + +Usage: + +```bash +./kanboard export:tasks +``` + +Example: + +```bash +./kanboard export:tasks 1 2014-10-01 2014-11-30 > /tmp/my_custom_export.csv +``` + +CSV data are sent to `stdout`. + +### Subtasks CSV export + +Usage: + +```bash +./kanboard export:subtasks +``` + +Example: + +```bash +./kanboard export:subtasks 1 2014-10-01 2014-11-30 > /tmp/my_custom_export.csv +``` + +### Task transitions CSV export + +Usage: + +```bash +./kanboard export:transitions +``` + +Example: + +```bash +./kanboard export:transitions 1 2014-10-01 2014-11-30 > /tmp/my_custom_export.csv +``` + +### Export daily summaries data in CSV + +The exported data will be printed on the standard output: + +```bash +./kanboard export:daily-project-column-stats +``` + +Example: + +```bash +./kanboard export:daily-project-column-stats 1 2014-10-01 2014-11-30 > /tmp/my_custom_export.csv +``` + +### Send notifications for overdue tasks + +Emails will be sent to all users with notifications enabled. + +```bash +./kanboard notification:overdue-tasks +``` + +You can also display the overdue tasks with the flag `--show`: + +```bash +$ ./kanboard notification:overdue-tasks --show ++-----+---------+------------+------------+--------------+----------+ +| Id | Title | Due date | Project Id | Project name | Assignee | ++-----+---------+------------+------------+--------------+----------+ +| 201 | Test | 2014-10-26 | 1 | Project #0 | admin | +| 202 | My task | 2014-10-28 | 1 | Project #0 | | ++-----+---------+------------+------------+--------------+----------+ +``` + +Cronjob example: + +```bash +# Everyday at 8am we check for due tasks +0 8 * * * cd /path/to/kanboard && ./kanboard notification:overdue-tasks >/dev/null 2>&1 +``` + +### Run daily project stats calculation + +You can add a background task to calculate the project statistics everyday: + +```bash +$ ./kanboard projects:daily-stats +Run calculation for Project #0 +Run calculation for Project #1 +Run calculation for Project #10 +``` diff --git a/doc/closing-tasks.markdown b/doc/closing-tasks.markdown new file mode 100644 index 00000000..235387a9 --- /dev/null +++ b/doc/closing-tasks.markdown @@ -0,0 +1,16 @@ +Closing tasks +============= + +When a task is closed, they are hidden from the board. + +However, you can always access to the list of closed tasks by using the query **status:closed** in any search form or simply choose **Closed tasks** from the filter dropdown. + +There are two different way to close a task, from the task dropdown menu on the board: + +![Close a task from dropdown menu](http://kanboard.net/screenshots/documentation/menu-close-task.png) + +Or from the task sidebar menu in the task detail view: + +![Close a task](http://kanboard.net/screenshots/documentation/closing-tasks.png) + +Note: When you close a task, all subtasks not completed will be changed to the status "Done". \ No newline at end of file diff --git a/doc/coding-standards.markdown b/doc/coding-standards.markdown new file mode 100644 index 00000000..e0e762db --- /dev/null +++ b/doc/coding-standards.markdown @@ -0,0 +1,24 @@ +Coding standards +================ + +PHP code +-------- + +- Indentation: 4 spaces +- Line return: Unix => `\n` +- Encoding: UTF-8 +- Use only the opening tags ` `\n` + +CSS code +-------- + +- Indentation: 4 spaces +- Line return: Unix => `\n` diff --git a/doc/config.markdown b/doc/config.markdown new file mode 100644 index 00000000..b5c3ce0d --- /dev/null +++ b/doc/config.markdown @@ -0,0 +1,242 @@ +Config file +=========== + +You can customize the default settings of Kanboard by adding a file `config.php` at the project root. +You can also rename the `config.default.php` and change the desired values. + +Enable/Disable debug mode +------------------------- + +```php +define('DEBUG', false); +``` + +The debug mode logs all SQL queries and the time taken to generate pages. + +Debug file path +--------------- + +```php +define('DEBUG_FILE', __DIR__.'/data/debug.log'); +``` + +All debug information are saved in this file. +If you prefer to send logs to `stdout` or `stderr` replace the value by `php://stdout` or `php://stderr`. + +Folder for uploaded files +------------------------- + +```php +define('FILES_DIR', 'data/files/'); +``` + +Don't forget the trailing slash. + +Enable/disable url rewrite +-------------------------- + +```php +define('ENABLE_URL_REWRITE', false); +``` + +Email configuration +------------------- + +```php +// E-mail address for the "From" header (notifications) +define('MAIL_FROM', 'notifications@kanboard.local'); + +// Mail transport to use: "smtp", "sendmail" or "mail" (PHP mail function) +define('MAIL_TRANSPORT', 'mail'); + +// SMTP configuration to use when the "smtp" transport is chosen +define('MAIL_SMTP_HOSTNAME', ''); +define('MAIL_SMTP_PORT', 25); +define('MAIL_SMTP_USERNAME', ''); +define('MAIL_SMTP_PASSWORD', ''); +define('MAIL_SMTP_ENCRYPTION', null); // Valid values are "null", "ssl" or "tls" + +// Sendmail command to use when the transport is "sendmail" +define('MAIL_SENDMAIL_COMMAND', '/usr/sbin/sendmail -bs'); +``` + +Database settings +----------------- + +```php +// Database driver: sqlite, mysql or postgres (sqlite by default) +define('DB_DRIVER', 'sqlite'); + +// Mysql/Postgres username +define('DB_USERNAME', 'root'); + +// Mysql/Postgres password +define('DB_PASSWORD', ''); + +// Mysql/Postgres hostname +define('DB_HOSTNAME', 'localhost'); + +// Mysql/Postgres database name +define('DB_NAME', 'kanboard'); + +// Mysql/Postgres custom port (null = default port) +define('DB_PORT', null); +``` + +LDAP settings +------------- + +```php +// Enable LDAP authentication (false by default) +define('LDAP_AUTH', false); + +// LDAP server hostname +define('LDAP_SERVER', ''); + +// LDAP server port (389 by default) +define('LDAP_PORT', 389); + +// By default, require certificate to be verified for ldaps:// style URL. Set to false to skip the verification. +define('LDAP_SSL_VERIFY', true); + +// Enable LDAP START_TLS +define('LDAP_START_TLS', false); + +// LDAP bind type: "anonymous", "user" (use the given user/password from the form) and "proxy" (a specific user to browse the LDAP directory) +define('LDAP_BIND_TYPE', 'anonymous'); + +// LDAP username to connect with. null for anonymous bind (by default). +// Or for user bind type, you can use a pattern: %s@kanboard.local +define('LDAP_USERNAME', null); + +// LDAP password to connect with. null for anonymous bind (by default). +define('LDAP_PASSWORD', null); + +// LDAP account base, i.e. root of all user account +// Example: ou=People,dc=example,dc=com +define('LDAP_ACCOUNT_BASE', ''); + +// LDAP query pattern to use when searching for a user account +// Example for ActiveDirectory: '(&(objectClass=user)(sAMAccountName=%s))' +// Example for OpenLDAP: 'uid=%s' +define('LDAP_USER_PATTERN', ''); + +// Name of an attribute of the user account object which should be used as the full name of the user. +define('LDAP_ACCOUNT_FULLNAME', 'displayname'); + +// Name of an attribute of the user account object which should be used as the email of the user. +define('LDAP_ACCOUNT_EMAIL', 'mail'); + +// Name of an attribute of the user account object which should be used as the id of the user. +// Example for ActiveDirectory: 'samaccountname' +// Example for OpenLDAP: 'uid' +define('LDAP_ACCOUNT_ID', 'samaccountname'); + +// By default Kanboard lowercase the ldap username to avoid duplicate users (the database is case sensitive) +// Set to true if you want to preserve the case +define('LDAP_USERNAME_CASE_SENSITIVE', false); + +// Automatically create user account +define('LDAP_ACCOUNT_CREATION', true); +``` + +Google Authentication settings +------------------------------ + +```php +// Enable/disable Google authentication +define('GOOGLE_AUTH', false); + +// Google client id (Get this value from the Google developer console) +define('GOOGLE_CLIENT_ID', ''); + +// Google client secret key (Get this value from the Google developer console) +define('GOOGLE_CLIENT_SECRET', ''); +``` + +Github Authentication settings +------------------------------ + +```php +// Enable/disable GitHub authentication +define('GITHUB_AUTH', false); + +// GitHub client id (Copy it from your settings -> Applications -> Developer applications) +define('GITHUB_CLIENT_ID', ''); + +// GitHub client secret key (Copy it from your settings -> Applications -> Developer applications) +define('GITHUB_CLIENT_SECRET', ''); +``` + +Reverse-Proxy Authentication settings +------------------------------------- + +```php +// Enable/disable the reverse proxy authentication +define('REVERSE_PROXY_AUTH', false); + +// Header name to use for the username +define('REVERSE_PROXY_USER_HEADER', 'REMOTE_USER'); + +// Username of the admin, by default blank +define('REVERSE_PROXY_DEFAULT_ADMIN', ''); + +// Default domain to use for setting the email address +define('REVERSE_PROXY_DEFAULT_DOMAIN', ''); +``` + +RememberMe Authentication settings +---------------------------------- + +```php +// Enable/disable remember me authentication +define('REMEMBER_ME_AUTH', true); +``` + +Secure HTTP headers settings +---------------------------- + +```php +// Enable or disable "Strict-Transport-Security" HTTP header +define('ENABLE_HSTS', true); + +// Enable or disable "X-Frame-Options: DENY" HTTP header +define('ENABLE_XFRAME', true); +``` + +Bruteforce protection +--------------------- + +```php +// Enable captcha after 3 authentication failure +define('BRUTEFORCE_CAPTCHA', 3); + +// Lock the account after 6 authentication failure +define('BRUTEFORCE_LOCKDOWN', 6); + +// Lock account duration in minute +define('BRUTEFORCE_LOCKDOWN_DURATION', 15); +``` + +Session +------- + +```php +// Session duration in second (0 = until the browser is closed) +// See http://php.net/manual/en/session.configuration.php#ini.session.cookie-lifetime +define('SESSION_DURATION', 0); +``` + +Various settings +---------------- + +```php +// Escape html inside markdown text +define('MARKDOWN_ESCAPE_HTML', true); + +// API alternative authentication header, the default is HTTP Basic Authentication defined in RFC2617 +define('API_AUTHENTICATION_HEADER', ''); + +// Hide login form, useful if all your users use Google/Github/ReverseProxy authentication +define('HIDE_LOGIN_FORM', false); +``` diff --git a/doc/contributing.markdown b/doc/contributing.markdown new file mode 100644 index 00000000..955ea5cd --- /dev/null +++ b/doc/contributing.markdown @@ -0,0 +1,69 @@ +Contributor Guidelines +====================== + +How can I help? +--------------- + +Kanboard is not perfect but there is many ways to help: + +- Give feedback +- Report bugs +- Add or update translations +- Improve the documentation +- Writing code +- Tell your friends that Kanboard is awesome :) + +Before doing any large undertaking, open a new issue and explain your proposal. + +I want to give feedback +----------------------- + +- You think something should be improved (user interface, feature request) +- Check if your idea is not already proposed +- Open a new issue +- Describe your idea +- You can also up vote with +1 on existing proposals + +I want to report a bug +---------------------- + +- Check if the issue is not already reported +- Open a new ticket +- Explain what is broken +- Describe how to reproduce the bug +- Describe your environment (Kanboard version, OS, web server, PHP version, database version, hosting type) + +I want to translate Kanboard +---------------------------- + +Kanboard is translated in many languages. +However, translations are not complete, take look at the [translation guide to contribute](http://kanboard.net/documentation/translations). + +I want to improve the documentation +----------------------------------- + +- You think something is not clear, there is grammatical errors, typo errors, anything. +- The documentation is written in Markdown and stored in the folder `docs`. +- Edit the file and send a pull-request. +- The documentation on the official website is synchronized with the repository. + +I want to contribute to the code +-------------------------------- + +Pull-requests are always welcome, however to be accepted you have to follow those directives: + +- **Before doing any large change or design proposal, open a new ticket to start a discussion.** +- If you want to add a new feature, respect the philosophy behind Kanboard. **We focus on simplicity**, we don't want to have a bloated software. +- The same apply for the user interface, **simplicity and efficiency**. +- Send only one pull-request per feature or bug fix, your patch will be merged into one single commit in the master branch. +- Make sure the [unit tests pass](tests.markdown). +- Respect the [coding standards](coding-standards.makrdown). +- Write maintainable code, avoid code duplication, use PHP good practices. + +In any case, if you are not sure about something open a new ticket. + +Tell your friends that Kanboard is awesome :) +--------------------------------------------- + +If you use Kanboard, spread the word around you. +Tell them that free and open source software are cool :) diff --git a/doc/create-tasks-by-email.markdown b/doc/create-tasks-by-email.markdown new file mode 100644 index 00000000..46dae480 --- /dev/null +++ b/doc/create-tasks-by-email.markdown @@ -0,0 +1,44 @@ +Create tasks by email +===================== + +You can create tasks directly by sending an email. + +At the moment, Kanboard is integrated with 3 external services: + +- [Mailgun](http://kanboard.net/documentation/mailgun) +- [Sendgrid](http://kanboard.net/documentation/sendgrid) +- [Postmark](http://kanboard.net/documentation/postmark) + +These services handle incoming emails without having to configure any SMTP server. + +When an email is received, Kanboard receive the message on a specific end-point. +All complicated works are already handled by those services. + +Incoming emails workflow +------------------------ + +1. You send an email to a specific address, by example **something+myproject@inbound.mydomain.tld** +2. Your email is forwarded to the third-party SMTP servers +3. The SMTP provider call the Kanboard webhook with the email in JSON or multipart/form-data formats +4. Kanboard parse the received email and create the task to the right project + +Note: New tasks are automatically created in the first column. + +Email format +------------ + +- The local part of the email address must use the plus separator, by example **kanboard+project123** +- The string defined after the plus sign must match a project identifier, by example **project123** is the identifier of the project **Project 123** +- The email subject becomes the task title +- The email body becomes the task description (Markdown format) + +Incoming emails can be written in text or HTML formats. +**Kanboard is able to convert simple HTML emails to Markdown**. + +Security and requirements +------------------------- + +- The Kanboard webhook is protected by a random token +- The sender email address must match a Kanboard user +- The Kanboard project must have a unique identifier, by example **MYPROJECT** +- The Kanboard user must be member of the project diff --git a/doc/creating-projects.markdown b/doc/creating-projects.markdown new file mode 100644 index 00000000..c4d80eb0 --- /dev/null +++ b/doc/creating-projects.markdown @@ -0,0 +1,31 @@ +Creating projects +================= + +Kanboard can handle multiple projects. There are two kinds of project: + +- Project with mutliple users (you work in team) +- Private project for a single user + +Creating projects for multiple users +------------------------------------- + +- Only administrators can create those projects +- User management is available + +From the dashboard, click on the link **New project**. +Then the form appears: + +![Project creation form](http://kanboard.net/screenshots/documentation/project-creation-form.png) + +It's very easy, you just have to find a name for your project! + +Creating a private project +-------------------------- + +- Everybody can create a private project +- There is **NO** user management +- Only the owner and administrators can access to the project + +From the dashboard, click on the link **New private project**. + +Note: project names must be unique across the application. diff --git a/doc/creating-tasks.markdown b/doc/creating-tasks.markdown new file mode 100644 index 00000000..afcc5ecb --- /dev/null +++ b/doc/creating-tasks.markdown @@ -0,0 +1,27 @@ +Creating tasks +============== + +From the board, click on the plus sign next to the column name: + +![Task creation from the board](http://kanboard.net/screenshots/documentation/task-creation-board.png) + +Then the task creation form appears: + +![Task creation form](http://kanboard.net/screenshots/documentation/task-creation-form.png) + +The only mandatory field is the title. + +Field description: + +- **Title**: The title of your task, that will be displayed on the board. +- **Description**: Allow you to add more information about the task, the content can be written in [Markdown](http://kanboard.net/documentation/syntax-guide). +- **Create another task**: Check this box if you want to create a similar task (fields will be prefilled). +- **Assignee**: The person that will work on the task. +- **Category**: Only one category can be assign to a task. +- **Column**: The column where the task will be created, your task will be positioned at the bottom. +- **Color**: Choose the color of the card. +- **Complexity**: Used in agile project management (Scrum), the complexity or story points is a number that tells the team how hard the story is. Often, people use the fibonacci series. +- **Original Estimate**: Estimation in hours to complete the tasks. +- **Due Date**: Overdue tasks will have a red due date and upcoming due dates will be black on the board. Several date format are accepted in addition to the date picker. + +With the preview link, you can see the task description converted from the Markdown syntax. \ No newline at end of file diff --git a/doc/currency-rate.markdown b/doc/currency-rate.markdown new file mode 100644 index 00000000..b959e4d1 --- /dev/null +++ b/doc/currency-rate.markdown @@ -0,0 +1,11 @@ +Currency Rate +============== + +Since each user can have a predefined hourly rate in different currency. +If you have to handle multiple currencies, you define here the rate according to the reference currency. + +This feature is used for project budget calculation. + +![Currency Rate](http://kanboard.net/screenshots/documentation/currency-rate.png) + +Currency rate settings are located in **Settings > Currency rates**. \ No newline at end of file diff --git a/doc/debian-installation.markdown b/doc/debian-installation.markdown new file mode 100644 index 00000000..147fe452 --- /dev/null +++ b/doc/debian-installation.markdown @@ -0,0 +1,63 @@ +How to install Kanboard on Debian? +================================== + +Debian 8 (Jessie) +----------------- + +Install Apache and PHP: + +```bash +apt-get update +apt-get install -y php5 php5-sqlite php5-gd unzip +service apache2 restart +``` + +Install Kanboard: + +```bash +cd /var/www/html +wget http://kanboard.net/kanboard-latest.zip +unzip kanboard-latest.zip +chown -R www-data:www-data kanboard/data +rm kanboard-latest.zip +``` + +Debian 7 (Wheezy) +----------------- + +Install Apache and PHP: + +```bash +apt-get update +apt-get install -y php5 php5-sqlite php5-gd unzip +``` + +Install Kanboard: + +```bash +cd /var/www +wget http://kanboard.net/kanboard-latest.zip +unzip kanboard-latest.zip +chown -R www-data:www-data kanboard/data +rm kanboard-latest.zip +``` + +Debian 6 (Squeeze) +------------------ + +Install Apache and PHP: + +```bash +apt-get update +apt-get install -y libapache2-mod-php5 php5-sqlite php5-gd unzip +``` + +Install Kanboard: + +```bash +cd /var/www +wget http://kanboard.net/kanboard-latest.zip +unzip kanboard-latest.zip +chown -R www-data:www-data kanboard/data +rm kanboard-latest.zip +``` diff --git a/doc/docker.markdown b/doc/docker.markdown new file mode 100644 index 00000000..44f3b976 --- /dev/null +++ b/doc/docker.markdown @@ -0,0 +1,47 @@ +How to run Kanboard with Docker? +================================ + +Kanboard can run easily with [Docker](https://www.docker.com). +There is a `Dockerfile` in the repository to build your own container. + +Use the automated build +----------------------- + +Every new commit on the repository trigger a new build on [Docker Hub](https://registry.hub.docker.com/u/kanboard/kanboard/). + +```bash +docker pull kanboard/kanboard +docker run -d --name kanboard -p 80:80 -t kanboard/kanboard:latest +``` + +The tag **latest** is the **development version** of Kanboard, use at your own risk. + +Build your own Docker image +--------------------------- + +Clone the Kanboard repository and run the following command: + +```bash +docker build -t youruser/kanboard:master . +``` + +To run your image in background on the port 80: + +```bash +docker run -d --name kanboard -p 80:80 -t youruser/kanboard:master +``` + +Store your data on a volume +--------------------------- + +By default Kanboard will store attachments and the Sqlite database in the directory data. Run this command to use a custom volume path: + +```bash +docker run -d --name kanboard -v /your/local/data/folder:/var/www/html/data -p 80:80 -t kanboard/kanboard:master +``` + +References +---------- + +- [Official Kanboard images](https://registry.hub.docker.com/u/kanboard/kanboard/) +- [Docker documentation](https://docs.docker.com/) diff --git a/doc/duplicate-move-tasks.markdown b/doc/duplicate-move-tasks.markdown new file mode 100644 index 00000000..dcb01df5 --- /dev/null +++ b/doc/duplicate-move-tasks.markdown @@ -0,0 +1,58 @@ +Duplicate and move tasks +======================== + +Duplicate a task into the same project +-------------------------------------- + +Go to the task view and choose **Duplicate** on the left. + +![Task Duplication](http://kanboard.net/screenshots/documentation/task-duplication.png) + +A new task will be created with the same properties as the original. + +Duplicate a task to another project +----------------------------------- + +Go to the task view and choose **Duplicate to another project**. + +![Task Duplication Another Project](http://kanboard.net/screenshots/documentation/task-duplication-another-project.png) + +Only projects where you are member will be shown in the dropdown. + +Before to copy the tasks, Kanboard will ask you the destination properties that are not common between the source and destination project. + +Basically, you need to define: + +- The destination swimlane +- The column +- The category +- The assignee + +Move a task to another project +------------------------------ + +Go to the task view and choose **Move to another project**. + +Moving a task to another project work in the same way as the duplication, you have to choose the new properties of the task. + +List of fields duplicated +------------------------- + +Here are the list of properties duplicated: + +- title +- description +- date_due +- color_id +- project_id +- column_id +- owner_id +- score +- category_id +- time_estimated +- swimlane_id +- recurrence_status +- recurrence_trigger +- recurrence_factor +- recurrence_timeframe +- recurrence_basedate diff --git a/doc/editing-projects.markdown b/doc/editing-projects.markdown new file mode 100644 index 00000000..c615fd53 --- /dev/null +++ b/doc/editing-projects.markdown @@ -0,0 +1,16 @@ +Editing projects +================ + +Projects can be renamed and disabled at any time. + +To rename a project, just click on the link "Edit project" on the left. + +![Project edition](http://kanboard.net/screenshots/documentation/project-edition.png) + +Administrators can convert a private project to a multiple users project by changing the checkbox "Private project". +You can also do the opposite action converting a multiple users project to a private project. + +This checkbox **enable or disable user managements for the project**. + +Note: When you make a project private, all existing users will still have access to the project. +Adjust the list of users according to your needs. diff --git a/doc/email-configuration.markdown b/doc/email-configuration.markdown new file mode 100644 index 00000000..c66996c6 --- /dev/null +++ b/doc/email-configuration.markdown @@ -0,0 +1,173 @@ +Email configuration +=================== + +User settings +------------- + +To receive email notifications, users of Kanboard must have: + +- Activated notifications in their profile +- Have a valid email address in their profile +- Be member of the project that will trigger notifications + +Note: The logged user who performs the action doesn't receive any notifications, only other project members. + +Email transports +---------------- + +There are several email transports available: + +- SMTP +- Sendmail +- PHP native mail function +- Mailgun +- Postmark +- Sendgrid + +Server settings +--------------- + +By default, Kanboard will use the bundled PHP mail function to send emails. +Usually that require no configuration if your server can already send emails. + +However, it's possible to use other methods, the SMTP protocol and Sendmail. + +### SMTP configuration + +Rename the file `config.default.php` to `config.php` and change these values: + +```php +// We choose "smtp" as mail transport +define('MAIL_TRANSPORT', 'smtp'); + +// We define our server settings +define('MAIL_SMTP_HOSTNAME', 'mail.example.com'); +define('MAIL_SMTP_PORT', 25); + +// Credentials for authentication on the SMTP server (not mandatory) +define('MAIL_SMTP_USERNAME', 'username'); +define('MAIL_SMTP_PASSWORD', 'super password'); +``` + +It's also possible to use a secure connection, TLS or SSL: + +```php +define('MAIL_SMTP_ENCRYPTION', 'ssl'); // Valid values are "null", "ssl" or "tls" +``` + +### Sendmail configuration + +By default the sendmail command will be `/usr/sbin/sendmail -bs` but you can customize that in your config file. + +Example: + +```php +// We choose "sendmail" as mail transport +define('MAIL_TRANSPORT', 'sendmail'); + +// If you need to change the sendmail command, replace the value +define('MAIL_SENDMAIL_COMMAND', '/usr/sbin/sendmail -bs'); +``` + +### PHP native mail function + +This is the default configuration: + +```php +define('MAIL_TRANSPORT', 'mail'); +``` + +### Mailgun HTTP API + +You can use the HTTP API of Mailgun to send emails. + +Configuration: + +```php +// We choose "mailgun" as mail transport +define('MAIL_TRANSPORT', 'mailgun'); + +// Mailgun API key +define('MAILGUN_API_TOKEN', 'YOUR_API_KEY'); + +// Mailgun domain name +define('MAILGUN_DOMAIN', 'YOUR_DOMAIN_CONFIGURED_IN_MAILGUN'); + +// Be sure to use the sender email address configured in Mailgun +define('MAIL_FROM', 'sender-address-configured-in-mailgun@example.org'); +``` + +### Postmark HTTP API + +Postmark is a third-party email service. +If you already use the Postmark integration to receive emails in Kanboard you can use the same provider to send email too. + +This system use their HTTP API instead of the SMTP protocol. + +Here are the required settings for this configuration: + +```php +// We choose "postmark" as mail transport +define('MAIL_TRANSPORT', 'postmark'); + +// Copy and paste your Postmark API token +define('POSTMARK_API_TOKEN', 'COPY HERE YOUR POSTMARK API TOKEN'); + +// Be sure to use the Postmark configured sender email address +define('MAIL_FROM', 'sender-address-configured-in-postmark@example.org'); +``` + +### Sendgrid HTTP API + +You can use the HTTP API of Sendgrid to send emails. + +Configuration: + +```php +// We choose "sendgrid" as mail transport +define('MAIL_TRANSPORT', 'sendgrid'); + +// Sendgrid username +define('SENDGRID_API_USER', 'YOUR_SENDGRID_USERNAME'); + +// Sendgrid password +define('SENDGRID_API_KEY', 'YOUR_SENDGRID_PASSWORD'); +``` + +### The sender email address + +By default, emails will use the sender address `notifications@kanboard.local`. +It's not possible to reply to this address. + +You can customize this address by changing the value of the constant `MAIL_FROM` in your config file. + +```php +define('MAIL_FROM', 'kanboard@mydomain.tld'); +``` + +That can be useful if your SMTP server configuration doesn't accept the default address. + +### How to display a link to the task in notifications? + +To do that, you have to specify the URL of your Kanboard installation in your [Application Settings](http://kanboard.net/documentation/application-configuration). +By default, nothing is defined, so no links will be displayed. + +Examples: + +- http://demo.kanboard.net/ +- http://myserver/kanboard/ +- http://kanboard.mydomain.com/ + +Don't forget the ending slash `/`. + +You need to define that manually because Kanboard cannot guess the URL from a command line script and some people have very specific configuration. + +Troubleshooting +--------------- + +If no emails are send and you are sure that everything is configured correctly: + +- Check your spam folder +- Enable the debug mode and check the debug file `data/debug.log`, you should see the exact error +- Be sure that your server or your hosting provider allow you to send emails +- If you use SeLinux, allow PHP to send emails diff --git a/doc/faq.markdown b/doc/faq.markdown new file mode 100644 index 00000000..3d542a30 --- /dev/null +++ b/doc/faq.markdown @@ -0,0 +1,113 @@ +Frequently Asked Questions +========================== + +Can you recommend a web hosting provider for Kanboard? +------------------------------------------------------ + +Kanboard works well with any great VPS hosting provider such as [Digital Ocean](https://www.digitalocean.com/?refcode=4b541f47aae4), +[Linode](https://www.linode.com/?r=4e381ac8a61116f40c60dc7438acc719610d8b11) or [Gandi](https://www.gandi.net/). + +To have the best performances, choose a provider with fast disk I/O because Kanboard use Sqlite by default. +Avoid hosting providers that use a shared NFS mount point. + +I get a blank page after installing or upgrading Kanboard +--------------------------------------------------------- + +- Check if you have installed all requirements on your server +- Check if the files have the correct permissions +- If you use php-fpm and opcode caching, reload the process to be sure to clear the cache +- Enable PHP error logging in your php.ini +- Check the PHP and Apache error logs you should see the exact error + + +Page not found and the url seems wrong (&amp;) +---------------------------------------------- + +- The url looks like `/?controller=auth&action=login&redirect_query=` instead of `?controller=auth&action=login&redirect_query=` +- Kanboard returns a "Page not found" error + +This issue come from your PHP configuration, the value of `arg_separator.output` is not the PHP's default, there is different ways to fix that: + +Change the value directly in your `php.ini` if you have the permission: + +``` +arg_separator.output = "&" +``` + +Override the value with a `.htaccess`: + +``` +php_value arg_separator.output "&" +``` + +Otherwise Kanboard will try to override the value directly in PHP. + + +Known issues with eAccelerator +------------------------------ + +Kanboard doesn't work very well with [eAccelerator](http://eaccelerator.net). +The issue caused can be a blank page or an Apache crash: + +``` +[Wed Mar 05 21:36:56 2014] [notice] child pid 22630 exit signal Segmentation fault (11) +``` + +The best way to avoid this issue is to disable eAccelerator or define manually which files you want to cache with the config parameter `eaccelerator.filter`. + +The project [eAccelerator seems dead and not updated since 2012](https://github.com/eaccelerator/eaccelerator/commits/master). +We recommend to switch to the last version of PHP because it's bundled with [OPcache](http://php.net/manual/en/intro.opcache.php). + + +Why the minimum requirement is PHP 5.3.3? +----------------------------------------- + +Kanboard use the function `password_hash()` to crypt passwords but it's available only for PHP >= 5.5. + +However, there is a backport for [older versions of PHP](https://github.com/ircmaxell/password_compat#requirements). +This library require at least PHP 5.3.7 to work correctly. + +Apparently, Centos and Debian backports security patches so PHP 5.3.3 should be ok. + +Kanboard v1.0.10 and v1.0.11 requires at least PHP 5.3.7 but this change has been reverted to be compatible with PHP 5.3.3 with Kanboard >= v1.0.12 + + +How to test Kanboard with the PHP built-in web server? +------------------------------------------------------ + +If you don't want to install a web server like Apache on localhost. You can test with the [embedded web server of PHP](http://www.php.net/manual/en/features.commandline.webserver.php): + +```bash +unzip kanboard-VERSION.zip +cd kanboard +php -S localhost:8000 +open http://localhost:8000/ +``` + + +How to migrate my tasks from Wunderlist? +---------------------------------------- + +You can use an external tool to import automatically your tasks and lists from Wunderlist to Kanboard. + +This is a command line script made by a contributor of Kanboard. +It's simple, quick and dirty but it works :) + +More information here: + +- [Wunderlist](http://www.wunderlist.com/) +- + + +How to install Kanboard on Yunohost? +------------------------------------ + +[YunoHost](https://yunohost.org/) is a server operating system aiming to make self-hosting accessible to everyone. + +There is a [package to install Kanboard on Yunohost easily](https://github.com/mbugeia/kanboard_ynh). + + +Are there some tutorials about Kanboard in other languages? +----------------------------------------------------------- + +- [German article series about Kanboard](http://demaya.de/wp/2014/07/kanboard-eine-jira-alternative-im-detail-installation/) diff --git a/doc/freebsd-installation.markdown b/doc/freebsd-installation.markdown new file mode 100644 index 00000000..84b35ad8 --- /dev/null +++ b/doc/freebsd-installation.markdown @@ -0,0 +1,127 @@ +FreeBSD 10 Installation +======================= + +Install from packages +--------------------- + +```bash +$ pkg update +$ pkg upgrade +$ pkg install apache24 mod_php56 kanboard +``` + +Enable Apache in your `/etc/rc.conf`: + +```bash +$ echo apache24_enable="YES" >> /etc/rc.conf +``` + +Set up PHP for Apache: + +```bash +$ echo "AddType application/x-httpd-php .php" >> /usr/local/etc/apache24/Includes/php.conf +$ echo "DirectoryIndex index.php index.html" >> /usr/local/etc/apache24/Includes/php.conf +``` + +Then start Apache: + +```bash +$ service apache24 start +``` + +Add symlink to Kanboard folder into your Apache docroot: + +```bash +cd /usr/local/www/apache24/data +ln -s /usr/local/www/kanboard +``` + +Go to http://your.server.domain.tld/kanboard and enjoy! + +*Notes*: +- If you want to use additional features like LDAP integration etc. +please install proper PHP module using pkg. +- You may have to adjust the permissions of the folder data + +Installing from ports +--------------------- + +Generally 3 elements have to be installed: + +- Apache +- mod_php for Apache +- Kanboard + +Fetch and extract ports... + +```bash +$ portsnap fetch +$ portsnap extract +``` + +or update already existing: + +```bash +$ portsnap fetch +$ portsnap update +``` + +More details regarding portsnap can be found in the [FreeBSD Handbook](https://www.freebsd.org/doc/handbook/ports-using.html). + +Install Apache: + +```bash +$ cd /usr/ports/www/apache24 +$ make install clean +``` +Enable Apache in your `/etc/rc.conf`: + +```bash +$ echo apache24_enable="YES" >> /etc/rc.conf +``` + +Install mod_php for Apache: + +```bash +$ cd /usr/ports/www/mod_php5 +$ make install clean +``` + +Install Kanboard form ports: + +```bash +$ cd /usr/ports/www/kanboard +$ make install clean +``` + +Set up PHP for Apache: + +```bash +$ echo "AddType application/x-httpd-php .php" >> /usr/local/etc/apache24/Includes/php.conf +$ echo "DirectoryIndex index.php index.html" >> /usr/local/etc/apache24/Includes/php.conf +``` + +Then start Apache: + +```bash +$ service apache24 start +``` + +Go to http://your.server.domain.tld/kanboard and enjoy! + +*Note*: +If you want to use additional features like LDAP integration etc. +please install proper PHP module from `lang/php5-extensions`. + +Manual installation +------------------- + +As of version 1.0.16 Kanboard can be found in FreeBSD ports +there is no need to install it manually. + +Please note +----------- + +Port is being hosted on [bitbucket](https://bitbucket.org/if0/freebsd-kanboard/). Feel free to comment, +fork and suggest updates! + \ No newline at end of file diff --git a/doc/gantt-chart-projects.markdown b/doc/gantt-chart-projects.markdown new file mode 100644 index 00000000..450b8bfc --- /dev/null +++ b/doc/gantt-chart-projects.markdown @@ -0,0 +1,16 @@ +Gantt chart for all projects +============================ + +The goal of this Gantt chart is to display an overview of all projects based on the start and end dates. + +- This Gantt chart is available in the project management section +- Only project administrators and administrators can access to this section +- Project administrators will see only projects where they are members + +![Gantt Chart for all projects](http://kanboard.net/screenshots/documentation/gantt-chart-all-projects.png) + +- The **start date** and the **end date** of projects are used to draw the chart +- Horizontal bars can be resized and moved horizontally with your mouse +- There is no vertical drag and drop +- Project bars are displayed in black when there is no start or end date defined +- The information tooltip show the list of project managers and standard members diff --git a/doc/gantt-chart-tasks.markdown b/doc/gantt-chart-tasks.markdown new file mode 100644 index 00000000..b84c8046 --- /dev/null +++ b/doc/gantt-chart-tasks.markdown @@ -0,0 +1,20 @@ +Gantt chart for tasks +====================== + +The goal of this Gantt chart is to display a time based overview of the tasks for a given project. + +- The Gantt chart is available from the the action menu +- Only project managers can access to this section + +![Gantt Chart](http://kanboard.net/screenshots/documentation/gantt-chart-project.png) + +- The **start date** and the **due date** of tasks are used to draw the chart +- Tasks can be resized and moved horizontally with your mouse +- There is no vertical drag and drop +- The bar is the same color as the task +- Each bar display a progression status in percentage, this percentage is calculated by using the column position on the board +- To fit with the Kanban model, tasks can be ordered by the board positions or by start date +- New tasks created from this view will be displayed on the board at the position 1 in the first column +- Tasks are displayed in black when there is no start or due date defined + +![Task not defined](http://kanboard.net/screenshots/documentation/gantt-chart-not-defined.png) diff --git a/doc/github-authentication.markdown b/doc/github-authentication.markdown new file mode 100644 index 00000000..ba0f371f --- /dev/null +++ b/doc/github-authentication.markdown @@ -0,0 +1,80 @@ +Github Authentication +===================== + +Requirements +------------ + +OAuth Github API credentials (available in your [Settings > Applications > Developer applications](https://github.com/settings/applications)) + +How does this work? +------------------- + +The Github authentication in Kanboard uses the [OAuth 2.0](http://oauth.net/2/) protocol, so any user of Kanboard can be linked to a Github account. + +That means you can use your Github account to login on Kanboard. + +How to link a Github account +---------------------------- + +1. Go to your user profile +2. Click on **External accounts** +3. Click on the link **Link my Github Account** +4. You are redirected to the **Github Authorize application form** +5. Authorize Kanboard by clicking on the button **Accept** +6. Your account is now linked + +Now, on the login page you can be authenticated in one click with the link **Login with my Github Account**. + +Your name and email are automatically updated from your Github Account if defined. + +Installation instructions +------------------------- + +### Setting up OAuth 2.0 + +- On Github, go to the page [Register a new OAuth application](https://github.com/settings/applications/new) +- Just follow the [official Github documentation](https://developer.github.com/guides/basics-of-authentication/#registering-your-app) +- In Kanboard, you can get the **callback url** in **Settings > Integrations > Github Authentication** + +### Setting up Kanboard + +Either create a new `config.php` file or rename the `config.default.php` file and set the following values: + +```php +// Enable/disable Github authentication +define('GITHUB_AUTH', true); + +// Github client id (Copy it from your settings -> Applications -> Developer applications) +define('GITHUB_CLIENT_ID', 'YOUR_GITHUB_CLIENT_ID'); + +// Github client secret key (Copy it from your settings -> Applications -> Developer applications) +define('GITHUB_CLIENT_SECRET', 'YOUR_GITHUB_CLIENT_SECRET'); +``` + +### Github Entreprise + +To use this authentication method with Github Enterprise you have to change the default urls. + +Replace these values by your self-hosted instance of Github: + +```php +// Github oauth2 authorize url +define('GITHUB_OAUTH_AUTHORIZE_URL', 'https://github.com/login/oauth/authorize'); + +// Github oauth2 token url +define('GITHUB_OAUTH_TOKEN_URL', 'https://github.com/login/oauth/access_token'); + +// Github API url (don't forget the slash at the end) +define('GITHUB_API_URL', 'https://api.github.com/'); +``` + +Notes +----- + +Kanboard uses these information from your public Github profile: + +- Full name +- Public email address +- Github unique id + +The Github unique id is used to link the local user account and the Github account. diff --git a/doc/github-webhooks.markdown b/doc/github-webhooks.markdown new file mode 100644 index 00000000..a20b5a18 --- /dev/null +++ b/doc/github-webhooks.markdown @@ -0,0 +1,99 @@ +Github webhooks integration +=========================== + +Kanboard can be synchronized with Github. +Currently, it's only a one-way synchronization: Github to Kanboard. + +Github webhooks are plugged to Kanboard automatic actions. +When an event occurs on Github, an action can be performed on Kanboard. + +List of available events +------------------------ + +- Github commit received +- Github issue opened +- Github issue closed +- Github issue reopened +- Github issue assignee change +- Github issue label change +- Github issue comment created + +List of available actions +------------------------- + +- Create a task from an external provider +- Change the assignee based on an external username +- Change the category based on an external label +- Create a comment from an external provider +- Close a task +- Open a task + +Configuration on Github +----------------------- + +Go to your project settings page, on the left choose "Webhooks & Services", then click on the button "Add webhook". + +![Github configuration](http://kanboard.net/screenshots/documentation/github-webhooks.png) + +- **Payload url**: Copy and paste the link from the Kanboard project settings (section **Integrations > Github**). +- Select **"Send me everything"** + +![Github webhook](http://kanboard.net/screenshots/documentation/kanboard-github-webhooks.png) + +Each time an event happens, Github will send an event to Kanboard now. +The Kanboard webhook url is protected by a random token. + +Everything else is handled by automatic actions in your Kanboard project settings. + +Examples +-------- + +### Close a Kanboard task when a commit pushed to Github + +- Choose the event: **Github commit received** +- Choose the action: **Close the task** + +When one or more commits are sent to Github, Kanboard will receive the information, each commit message with a task number included will be closed. + +Example: + +- Commit message: "Fix bug #1234" +- That will close the Kanboard task #1234 + +### Create a Kanboard task when a new issue is opened on Github + +- Choose the event: **Github issue opened** +- Choose the action: **Create a task from an external provider** + +When a task is created from a Github issue, the link to the issue is added to the description and the task have a new field named "Reference" (this is the Github ticket number). + +### Close a Kanboard task when an issue is closed on Github + +- Choose the event: **Github issue closed** +- Choose the action: **Close the task** + +### Reopen a Kanboard task when an issue is reopened on Github + +- Choose the event: **Github issue reopened** +- Choose the action: **Open the task** + +### Assign a task to a Kanboard user when an issue is assigned on Github + +- Choose the event: **Github issue assignee change** +- Choose the action: **Change the assignee based on an external username** + +Note: The username must be the same between Github and Kanboard and the user must be member of the project. + +### Assign a category when an issue is tagged on Github + +- Choose the event: **Github issue label change** +- Choose the action: **Change the category based on an external label** +- Define the label and the category + +### Create a comment on Kanboard when an issue is commented on Github + +- Choose the event: **Github issue comment created** +- Choose the action: **Create a comment from an external provider** + +If the username is the same between Github and Kanboard the comment author will be assigned, otherwise there is no author. +The user also have to be member of the project in Kanboard. diff --git a/doc/gitlab-authentication.markdown b/doc/gitlab-authentication.markdown new file mode 100644 index 00000000..3cf6d283 --- /dev/null +++ b/doc/gitlab-authentication.markdown @@ -0,0 +1,78 @@ +Gitlab Authentication +===================== + +Requirements +------------ + +- Account on [Gitlab.com](https://gitlab.com) or you own self-hosted Gitlab instance +- Have Kanboard registered as application in Gitlab + +How does this work? +------------------- + +The Gitlab authentication in Kanboard uses the [OAuth 2.0](http://oauth.net/2/) protocol, so any user of Kanboard can be linked to a Gitlab account. + +That means you can use your Gitlab account to login on Kanboard. + +How to link a Gitlab account +---------------------------- + +1. Go to your user profile +2. Click on **External accounts** +3. Click on the link **Link my Gitlab Account** +4. You are redirected to the **Gitlab authorization form** +5. Authorize Kanboard by clicking on the button **Accept** +6. Your account is now linked + +Now, on the login page you can be authenticated in one click with the link **Login with my Gitlab Account**. + +Your name and email are automatically updated from your Gitlab Account if defined. + +Installation instructions +------------------------- + +### Setting up OAuth 2.0 + +- On Gitlab, register a new application by following the [official documentation](http://doc.gitlab.com/ce/integration/oauth_provider.html) +- In Kanboard, you can get the **callback url** in **Settings > Integrations > Gitlab Authentication**, just copy and paste the url + +### Setting up Kanboard + +Either create a new `config.php` file or rename the `config.default.php` file and set the following values: + +```php +// Enable/disable Gitlab authentication +define('GITLAB_AUTH', true); + +// Gitlab application id +define('GITLAB_CLIENT_ID', 'YOUR_APPLICATION_ID'); + +// Gitlab application secret +define('GITLAB_CLIENT_SECRET', 'YOUR_APPLICATION_SECRET'); +``` + +### Custom endpoints for self-hosted Gitlab + +Change these default values if you use a self-hosted instance of Gitlab: + +```php +// Gitlab oauth2 authorize url +define('GITLAB_OAUTH_AUTHORIZE_URL', 'https://gitlab.com/oauth/authorize'); + +// Gitlab oauth2 token url +define('GITLAB_OAUTH_TOKEN_URL', 'https://gitlab.com/oauth/token'); + +// Gitlab API url endpoint (don't forget the slash at the end) +define('GITLAB_API_URL', 'https://gitlab.com/api/v3/'); +``` + +Notes +----- + +Kanboard uses these information from your Gitlab profile: + +- Full name +- Email address +- Gitlab unique id + +The Gitlab unique id is used to link the local user account and the Gitlab account. diff --git a/doc/gitlab-webhooks.markdown b/doc/gitlab-webhooks.markdown new file mode 100644 index 00000000..9d9ecaf5 --- /dev/null +++ b/doc/gitlab-webhooks.markdown @@ -0,0 +1,65 @@ +Gitlab webhooks +=============== + +Gitlab events can be connected to Kanboard automatic actions. + +List of supported events +------------------------ + +- Gitlab commit received +- Gitlab issue opened +- Gitlab issue closed +- Gitlab issue comment created + +List of supported actions +------------------------- + +- Create a task from an external provider +- Close a task +- Create a comment from an external provider + +Configuration +------------- + +![Gitlab configuration](http://kanboard.net/screenshots/documentation/gitlab-webhooks.png) + +1. On Kanboard, go to the project settings and choose the section **Integrations** +2. Copy the Gitlab webhook url +3. On Gitlab, go to the project settings and go to the section **Webhooks** +4. Check the boxes **Push Events**, **Comments** and **Issues Events** +5. Paste the url and save + +Examples +-------- + +### Close a Kanboard task when a commit pushed to Gitlab + +- Choose the event: **Gitlab commit received** +- Choose the action: **Close the task** + +When one or more commits are sent to Gitlab, Kanboard will receive the information, each commit message with a task number included will be closed. + +Example: + +- Commit message: "Fix bug #1234" +- That will close the Kanboard task #1234 + +### Create a Kanboard task when a new issue is opened on Gitlab + +- Choose the event: **Gitlab issue opened** +- Choose the action: **Create a task from an external provider** + +When a task is created from a Gitlab issue, the link to the issue is added to the description and the task have a new field named "Reference" (this is the Gitlab ticket number). + +### Close a Kanboard task when an issue is closed on Gitlab + +- Choose the event: **Gitlab issue closed** +- Choose the action: **Close the task** + +### Create a comment on Kanboard when an issue is commented on Gitlab + +- Choose the event: **Gitlab issue comment created** +- Choose the action: **Create a comment from an external provider** + +If the username is the same between Gitlab and Kanboard the comment author will be assigned, otherwise there is no author. +The user also have to be member of the project in Kanboard. \ No newline at end of file diff --git a/doc/google-authentication.markdown b/doc/google-authentication.markdown new file mode 100644 index 00000000..0f4f3ec1 --- /dev/null +++ b/doc/google-authentication.markdown @@ -0,0 +1,64 @@ +Google Authentication +===================== + +Requirements +------------ + +OAuth Google API credentials (available in the Google Developer Console) + +How does this work? +------------------- + +- The Google authentication in Kanboard use the OAuth 2.0 protocol +- Any user account in Kanboard can be linked to a Google Account +- When a Kanboard user account is linked to Google, you can login with one click + +Procedure to link a Google Account +---------------------------------- + +1. Go to your user profile +2. Click on **External accounts** +3. Click on the link **Link my Google Account** +4. You are redirected to the **Google Consent screen** +5. Authorize Kanboard by clicking on the button **Accept** +6. Your account is now linked + +Now, on the login page you can be authenticated in one click with the link **Login with my Google Account**. + +Your name and email are automatically updated from your Google Account. + +Installation instructions +------------------------- + +### Setting up OAuth 2.0 in Google Developer Console + +- Follow the [official Google documentation](https://developers.google.com/accounts/docs/OAuth2Login#appsetup) to create a new application +- In Kanboard, you can get the **redirect url** in **Settings > Integrations > Google Authentication** + +### Setting up Kanboad + +Create a custom `config.php` file or copy the `config.default.php` file: + +```php + Integrations > Hipchat** +- To send notifications for only some projects, go to **Project settings > Integrations > Hipchat** + +Each project can send notifications to a separate room. + +Send notifications to a room +----------------------------- + +Example of notifications: + +![Hipchat notification](http://kanboard.net/screenshots/documentation/hipchat-notification.png) + +This feature use the room notification token system of Hipchat. + +### Hipchat configuration + +![Hipchat room token](http://kanboard.net/screenshots/documentation/hipchat-room-token.png) + +1. Go to to **My account** +2. Click on the tab **Rooms** and select the room you want to send the notifications +3. On the left, choose **Tokens** +4. Enter a label, by example "Kanboard" and save + +### Kanboard configuration + +![Hipchat settings](http://kanboard.net/screenshots/documentation/hipchat-settings.png) + +1. Go to **Settings > Integrations > Hipchat** or **Project settings > Integrations > Hipchat** +2. Replace the API url if you use the self-hosted version of Hipchat +3. Set the room name or the room API ID +4. Copy and paste the token generated previously + +Now, Kanboard events will be sent to the Hipchat room. diff --git a/doc/hourly-rate.markdown b/doc/hourly-rate.markdown new file mode 100644 index 00000000..172f2f47 --- /dev/null +++ b/doc/hourly-rate.markdown @@ -0,0 +1,11 @@ +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/ical.markdown b/doc/ical.markdown new file mode 100644 index 00000000..5c52bf82 --- /dev/null +++ b/doc/ical.markdown @@ -0,0 +1,78 @@ +Syncing your calendars +====================== + +Kanboard supports iCal feeds for projects and users. +This feature allow you to import Kanboard tasks in almost any calendar program (by example Microsoft Outlook, Apple Calendar, Mozilla Thunderbird and Google Calendar). + +Calendar subscriptions are **read-only** access, you cannot create tasks from an external calendar software. +The Calendar feed export follow the iCal standard. + +Note: Only tasks within the date range of -2 months to +6 months are exported to the iCalendar feed. + +Project calendars +----------------- + +- Each project have its own calendar. +- The subscription link is unique per project, the link is activated when you enable the public access of your project: **Project settings > Public access**. +- This calendar show only tasks for the selected project. + +User calendars +-------------- + +- Each user have its own calendar. +- The subscription link is unique per user, the link is activated when you enable the public access of your user: **User profile > Public access**. +- This calendar show tasks assigned to the user for all projects. + +Adding your Kanboard calendar to Apple Calendar +----------------------------------------------- + +- Open Calendar +- Select **File > New Calendar Subscription** +- Copy and paste the iCal feed url from Kanboard + +![Add iCal subscription](http://kanboard.net/screenshots/documentation/apple-calendar-add-subscription.png) + +- You can choose to synchronize the calendar with iCloud to be available across all your devices +- Don't forget to select the refresh frequency + +![Edit iCal subscription](http://kanboard.net/screenshots/documentation/apple-calendar-edit-subscription.png) + +Adding your Kanboard calendar to Microsoft Outlook +-------------------------------------------------- + +![Outlook Add Internet Calendar](http://kanboard.net/screenshots/documentation/outlook-add-subscription.png) + +- Open Outlook +- Select **Open Calendar > From Internet** +- Copy and paste the iCal feed url from Kanboard + +![Outlook Edit Internet Calendar](http://kanboard.net/screenshots/documentation/outlook-edit-subscription.png) + +Adding your Kanboard calendar to Mozilla Thunderbird +---------------------------------------------------- + +- Install the Add-on **Lightning** to add the calendar support to Thunderbird +- Click on **File > New Calendar** +- In the dialog box, choose **On the Network** + +![Thunderbird Step 1](http://kanboard.net/screenshots/documentation/thunderbird-new-calendar-step1.png) + +- Choose the format iCalendar +- Copy and paste the iCal feed url from Kanboard + +![Thunderbird Step 2](http://kanboard.net/screenshots/documentation/thunderbird-new-calendar-step2.png) + +- Choose the colors and other settings and finally save + +Adding your Kanboard calendar to Google Calendar +------------------------------------------------ + +- Click the down-arrow next to **Other calendars**. +- Select **Add by URL** from the menu. +- Copy and paste the iCal feed url from Kanboard + +![Google Calendar](http://kanboard.net/screenshots/documentation/google-calendar-add-subscription.png) + +Your Kanboard calendar can also be available from your Android device if you enable the synchronization. + +Note: According to the Google Support, external calendars are not refreshed very often, [read the documentation](https://support.google.com/calendar/answer/37100?hl=en&ref_topic=1672445). diff --git a/doc/index.markdown b/doc/index.markdown new file mode 100644 index 00000000..10db316a --- /dev/null +++ b/doc/index.markdown @@ -0,0 +1,138 @@ +Documentation +============= + +Using Kanboard +-------------- + +### Introduction + +- [What is Kanban?](what-is-kanban.markdown) +- [Kanban vs Todo Lists and Scrum](kanban-vs-todo-and-scrum.markdown) +- [Usage examples](usage-examples.markdown) + +### Using the board + +- [Board, Calendar and List views](project-views.markdown) +- [Collapsed and expanded mode](board-collapsed-expanded.markdown) +- [Horizontal scrolling and compact mode](board-horizontal-scrolling-and-compact-view.markdown) +- [Show and hide columns](board-show-hide-columns.markdown) + +### Working with projects + +- [Creating projects](creating-projects.markdown) +- [Editing projects](editing-projects.markdown) +- [Sharing boards and tasks](sharing-projects.markdown) +- [Automatic actions](automatic-actions.markdown) +- [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) + +### Working with tasks + +- [Creating tasks](creating-tasks.markdown) +- [Closing tasks](closing-tasks.markdown) +- [Duplicate and move tasks](duplicate-move-tasks.markdown) +- [Adding screenshots](screenshots.markdown) +- [Task links](task-links.markdown) +- [Transitions](transitions.markdown) +- [Time tracking](time-tracking.markdown) +- [Recurring tasks](recurring-tasks.markdown) +- [Create tasks by email](create-tasks-by-email.markdown) +- [Subtasks](subtasks.markdown) +- [Analytics for tasks](analytics-tasks.markdown) + +### Working with users + +- [User management](user-management.markdown) +- [Notifications](notifications.markdown) +- [Hourly rate](hourly-rate.markdown) +- [Timetable](timetable.markdown) +- [Two factor authentication](2fa.markdown) + +### Settings + +- [Keyboard shortcuts](keyboard-shortcuts.markdown) +- [Application settings](application-configuration.markdown) +- [Project settings](project-configuration.markdown) +- [Board settings](board-configuration.markdown) +- [Calendar settings](calendar-configuration.markdown) +- [Link settings](link-labels.markdown) +- [Currency rate](currency-rate.markdown) + +### Integrations + +- [Bitbucket webhooks](bitbucket-webhooks.markdown) +- [Github webhooks](github-webhooks.markdown) +- [Gitlab webhooks](gitlab-webhooks.markdown) +- [Hipchat](hipchat.markdown) +- [Jabber](jabber.markdown) +- [Mailgun](mailgun.markdown) +- [Sendgrid](sendgrid.markdown) +- [Slack](slack.markdown) +- [Postmark](postmark.markdown) +- [iCalendar subscriptions](ical.markdown) +- [RSS/Atom subscriptions](rss.markdown) +- [Json-RPC API](api-json-rpc.markdown) +- [Webhooks](webhooks.markdown) + +### More + +- [Advanced Search Syntax](search.markdown) +- [Command line interface](cli.markdown) +- [Syntax guide](syntax-guide.markdown) +- [Bruteforce protection](bruteforce-protection.markdown) +- [Frequently asked questions](faq.markdown) + +Technical details +----------------- + +### Installation + +- [Recommended configuration](recommended-configuration.markdown) +- [Installation instructions](installation.markdown) +- [Upgrade Kanboard to a new version](update.markdown) +- [Installation on Ubuntu](ubuntu-installation.markdown) +- [Installation on Debian](debian-installation.markdown) +- [Installation on Centos](centos-installation.markdown) +- [Installation on FreeBSD](freebsd-installation.markdown) +- [Installation on Windows Server with IIS](windows-iis-installation.markdown) +- [Installation on Windows Server with Apache](windows-apache-installation.markdown) +- [Installation on Heroku](heroku.markdown) +- [Example with Nginx + HTTPS + SPDY + PHP-FPM](nginx-ssl-php-fpm.markdown) +- [Run Kanboard with Docker](docker.markdown) + +### Configuration + +- [Config file](config.markdown) +- [Email configuration](email-configuration.markdown) +- [URL rewriting](nice-urls.markdown) + +### Database + +- [Sqlite database management](sqlite-database.markdown) +- [How to use Mysql](mysql-configuration.markdown) +- [How to use Postgresql](postgresql-configuration.markdown) + +### Authentication + +- [LDAP authentication](ldap-authentication.markdown) +- [Google authentication](google-authentication.markdown) +- [Github authentication](github-authentication.markdown) +- [Gitlab authentication](gitlab-authentication.markdown) +- [Reverse proxy authentication](reverse-proxy-authentication.markdown) + +### Contributors + +- [Contributor guide](contributing.markdown) +- [Translations](translations.markdown) +- [Coding standards](coding-standards.markdown) +- [Running tests](tests.markdown) +- [Build assets](assets.markdown) +- [Run Kanboard with Vagrant](vagrant.markdown) + +The documentation is written in [Markdown](http://en.wikipedia.org/wiki/Markdown). +If you want to improve the documentation, just send a pull-request. diff --git a/doc/installation.markdown b/doc/installation.markdown new file mode 100644 index 00000000..53e7095b --- /dev/null +++ b/doc/installation.markdown @@ -0,0 +1,40 @@ +Installation +============ + +Requirements +------------ + +- Apache or Nginx +- PHP >= 5.3.3 (Kanboard is compatible with PHP 5.3, 5.4, 5.5, 5.6 and 7.0) +- PHP extensions required: mbstring, gd and pdo_sqlite +- A modern web browser + +From the archive (stable version) +--------------------------------- + +1. You must have a web server with PHP installed +2. Download the source code and copy the directory `kanboard` where you want +3. Check if the directory `data` is writeable +4. With your browser go to +5. The default login and password is **admin/admin** +6. Start to use the software +7. Don't forget to change your password! + +Note: The folder data is the location where Kanboard stores uploaded files as well as the Sqlite database. + +From the repository (development version) +----------------------------------------- + +You must install [composer](https://getcomposer.org/) to use this method. + +1. `git clone https://github.com/fguillot/kanboard.git` +2. `composer install` +3. Go to the third step just above + +Note: This method will install the **current development version**, use at your own risk. + +Security +-------- + +- Don't forget to change the default user/password +- Don't allow everybody to access to the directory `data` from the URL. There is already a `.htaccess` for Apache but nothing for Nginx. diff --git a/doc/jabber.markdown b/doc/jabber.markdown new file mode 100644 index 00000000..fe365168 --- /dev/null +++ b/doc/jabber.markdown @@ -0,0 +1,34 @@ +Jabber/XMPP integration +======================= + +You can send notifications to a Jabber room for all projects or only for specific projects. + +- To send notifications for all projects, go to **Settings > Integrations > Jabber** +- To send notifications for only some projects, go to **Project settings > Integrations > Jabber** + +Each project can send notifications to a separate room. + +## Example of notification + +Here an example with the Jabber client Adium: + +![Jabber notification](http://kanboard.net/screenshots/documentation/jabber-notification.png) + +## Configuration + +![Jabber settings](http://kanboard.net/screenshots/documentation/jabber-settings.png) + +1. Go to **Settings > Integrations > Jabber** or **Project settings > Integrations > Jabber** +2. **XMPP server address**: URL of the XMPP server, example: **tcp://172.28.128.3:5222** +3. **Jabber domain**: The **"to"** attribute of the XMPP protocol, example: **example.com** +4. **Username**: The Jabber username used by Kanboard, example: **kanboard** +5. **Password**: The Jabber password +6. **Jabber nickname**: The nickname used to connect to the room +7. **Multi-user chat room**: The address of the room, example: **demo@conference.example.com** + +Now, Kanboard events will be sent to the Jabber conference room. + +## Troubleshooting + +- Enable the debug mode +- All connection errors with the XMPP server are recorded in the log files `data/debug.log` or syslog diff --git a/doc/kanban-vs-todo-and-scrum.markdown b/doc/kanban-vs-todo-and-scrum.markdown new file mode 100644 index 00000000..3d53023a --- /dev/null +++ b/doc/kanban-vs-todo-and-scrum.markdown @@ -0,0 +1,37 @@ +Kanban vs Todo lists and Scrum +============================== + +Kanban vs Todo lists +-------------------- + +### Todo lists: + +- Single phase (just a list of items) +- Multitasking possible (not efficient) + +### Kanban: + +- Multiple phases, each column represent a step +- Bring focus and avoid multitasking because you can set a work in progress limit per column + +Kanban vs Scrum +--------------- + +### Scrum: + +- Sprints are time-boxed, usually 2 or 4 weeks +- Do not allow changes during the iteration +- Estimation is required +- Uses velocity as default metric +- Scrum board is cleared between each sprint +- Scrum has predefined roles like scrum master, product owner and the team +- A lot of meetings: planning, backlog grooming, daily stand-up, retrospective + +### Kanban: + +- Continuous flow +- Changes can be made at anytime +- Estimation is optional +- Use lead and cycle time to measure performance +- Kanban board is persistent +- Kanban doesn't impose strict constraints or meetings, process is more flexible diff --git a/doc/keyboard-shortcuts.markdown b/doc/keyboard-shortcuts.markdown new file mode 100644 index 00000000..959b1522 --- /dev/null +++ b/doc/keyboard-shortcuts.markdown @@ -0,0 +1,24 @@ +Keyboard shortcuts +================== + +Board/Calendar/List view +------------------------ + +- Switch to the board view = **v b** +- Switch to the calendar view = **v c** +- Switch to the list view = **v l** + +Board view +---------- + +- New task = **n** +- Expand/collapse tasks = **s** +- Compact/wide view = **c** + +Application +----------- + +- Open board switcher = **b** +- Go to the search/filter box = **f** +- Close dialog box = **ESC** +- Submit a form = **CTRL+ENTER** or **⌘+ENTER** \ No newline at end of file diff --git a/doc/ldap-authentication.markdown b/doc/ldap-authentication.markdown new file mode 100644 index 00000000..53b3d012 --- /dev/null +++ b/doc/ldap-authentication.markdown @@ -0,0 +1,234 @@ +LDAP authentication +=================== + +Requirements +------------ + +- LDAP extension for PHP +- LDAP server: + - OpenLDAP + - Microsoft Active Directory + - Novell eDirectory + +Workflow +-------- + +When the LDAP authentication is activated, the login process work like that: + +1. Try first to authenticate the user by using the database +2. If the user is not found inside the database, a LDAP authentication is performed +3. If the LDAP authentication is successful, by default a local user is created automatically with no password and marked as LDAP user. + +### Differences between a local user and a LDAP user are the following: + +- LDAP users have no local passwords +- LDAP users can't modify their password with the user interface +- By default, all LDAP users have no admin privileges +- To become administrator, a LDAP user must be promoted by another administrator + +The full name and the email address are automatically fetched from the LDAP server. + +Configuration +------------- + +You have to create a custom config file named `config.php` (you can also use the template `config.default.php`). +This file must be stored in the root directory of Kanboard. + +### LDAP bind type + +There is 3 possible ways to browse the LDAP directory: + +#### Anonymous browsing + +```php +define('LDAP_BIND_TYPE', 'anonymous'); +define('LDAP_USERNAME', null); +define('LDAP_PASSWORD', null); +``` + +This is the default value but some LDAP servers don't allow that. + +#### Proxy user + +A specific user is used to browse the LDAP directory. +By example, Novell eDirectory use that method. + +```php +define('LDAP_BIND_TYPE', 'proxy'); +define('LDAP_USERNAME', 'my proxy user'); +define('LDAP_PASSWORD', 'my proxy password'); +``` + +#### User credentials + +This method use the credentials provided by the end-user. +By example, Microsoft Active Directory doesn't allow anonymous browsing by default and if you don't want to use a proxy user you can use this method. + +```php +define('LDAP_BIND_TYPE', 'user'); +define('LDAP_USERNAME', '%s@mydomain.local'); +define('LDAP_PASSWORD', null); +``` + +Here, the `LDAP_USERNAME` is use to define a replacement pattern: + +```php +define('LDAP_USERNAME', '%s@mydomain.local'); + +// Another way to do the same: + +define('LDAP_USERNAME', 'MYDOMAIN\\%s'); +``` + +### Example for Microsoft Active Directory + +Let's say we have a domain `KANBOARD` (kanboard.local) and the primary controller is `myserver.kanboard.local`. +Microsoft Active Directory doesn't allow anonymous binding by default. + +First example with a proxy user: + +```php + Link settings**) + +![Link Labels](http://kanboard.net/screenshots/documentation/link-labels.png) + +Each label may have an opposite label defined. +If there is no opposite, the label is considered bi-directionnal. + +![Link Label Creation](http://kanboard.net/screenshots/documentation/link-label-creation.png) diff --git a/doc/mailgun.markdown b/doc/mailgun.markdown new file mode 100644 index 00000000..6465903a --- /dev/null +++ b/doc/mailgun.markdown @@ -0,0 +1,28 @@ +Mailgun +======= + +You can use the service [Mailgun](http://www.mailgun.com/) to create tasks directly by email. + +This integration works with the inbound email service of Mailgun (routes). +Kanboard use a webhook to handle incoming emails. + +The [incoming email workflow is described here](create-tasks-by-email.markdown). + +Mailgun configuration +--------------------- + +Create a new route in the web interface or via the API ([official documentation](https://documentation.mailgun.com/user_manual.html#routes)), here an example: + +``` +match_recipient("^kanboard\+(.*)@mydomain.tld$") +forward("https://mykanboard/?controller=webhook&action=mailgun&token=mytoken") +``` + +The Kanboard webhook url is displayed in **Settings > Integrations > Mailgun** + +Kanboard configuration +---------------------- + +1. Be sure that your users have an email address in their profiles +2. Assign a project identifier to the desired projects: **Project settings > Edit** +3. Try to send an email to your project diff --git a/doc/mysql-configuration.markdown b/doc/mysql-configuration.markdown new file mode 100644 index 00000000..eef1e125 --- /dev/null +++ b/doc/mysql-configuration.markdown @@ -0,0 +1,44 @@ +How to use Mysql or MariaDB instead of Sqlite +============================================= + +By default Kanboard use Sqlite to stores its data. +However it's possible to use Mysql or MariaDB instead of Sqlite. + +Requirements +------------ + +- Mysql server +- The PHP extension `pdo_mysql` installed (Debian/Ubuntu: `apt-get install php5-mysql`) + +Note: Kanboard is tested with **Mysql >= 5.5 and MariaDB >= 10.0** + +Mysql configuration +------------------- + +### Create a database + +The first step is to create a database on your Mysql server. +By example, you can do that with the command line mysql client: + +```sql +CREATE DATABASE kanboard; +``` + +### Create a config file + +The file `config.php` should contains those values: + +```php + kanboard.pem +``` + +Copy the certificates in a new directory: + +```bash +mkdir /etc/nginx/ssl +cp kanboard.pem /etc/nginx/ssl +cp kanboard.key.nopass /etc/nginx/ssl +chmod 400 /etc/nginx/ssl/* +``` + +Configure Nginx +--------------- + +Now, we can customize our installation, start to modify the main configuration file `/etc/nginx/nginx.conf`: + +```nginx +user www-data; +worker_processes auto; +pid /run/nginx.pid; + +events { + worker_connections 1024; +} + +http { + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 65; + types_hash_max_size 2048; + server_tokens off; + + # SSL shared cache between workers + ssl_session_cache shared:SSL:10m; + ssl_session_timeout 10m; + + # We disable weak protocols and ciphers + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + ssl_prefer_server_ciphers on; + ssl_ciphers HIGH:!SSLv2:!MEDIUM:!LOW:!EXP:!RC4:!DSS:!aNULL:@STRENGTH; + + include /etc/nginx/mime.types; + default_type application/octet-stream; + + access_log /var/log/nginx/access.log; + error_log /var/log/nginx/error.log; + + # We enable the Gzip compression for some mime types + gzip on; + gzip_disable "msie6"; + gzip_vary on; + gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; + + include /etc/nginx/conf.d/*.conf; + include /etc/nginx/sites-enabled/*; +} +``` + +Create a new virtual host for Kanboard `/etc/nginx/sites-available/kanboard` + + +```nginx +server { + # We also enable the SPDY protocol + listen 443 ssl spdy; + + # Our SSL certificate + ssl on; + ssl_certificate /etc/nginx/ssl/kanboard.pem; + ssl_certificate_key /etc/nginx/ssl/kanboard.key.nopass; + + # You can change the default root directory here + root /usr/share/nginx/html; + + index index.php; + + # Your domain name + server_name localhost; + + # The maximum body size, useful for file uploads + client_max_body_size 10M; + + location / { + try_files $uri $uri/ =404; + } + + error_page 404 /404.html; + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /usr/share/nginx/html; + } + + # PHP-FPM configuration + location ~ \.php$ { + try_files $uri =404; + fastcgi_split_path_info ^(.+\.php)(/.+)$; + fastcgi_pass unix:/var/run/php5-fpm.sock; + fastcgi_index index.php; + include fastcgi.conf; + } + + # Deny access to the directory data + location ~* /data { + deny all; + return 404; + } + + # Deny access to .htaccess + location ~ /\.ht { + deny all; + return 404; + } +} +``` + +Now it's time to test our setup + +```bash +# Disable the default virtual host +sudo unlink /etc/nginx/sites-enabled/default + +# Add our default virtual host +sudo ln -s /etc/nginx/sites-available/kanboard /etc/nginx/sites-enabled/kanboard + +# Check the config file +sudo nginx -t +nginx: the configuration file /etc/nginx/nginx.conf syntax is ok +nginx: configuration file /etc/nginx/nginx.conf test is successful + +# Restart nginx +sudo service nginx restart +``` + +Kanboard Installation +--------------------- + +You can install Kanboard in a subdirectory or not, it's up to you. + +```bash +cd /usr/share/nginx/html +sudo wget http://kanboard.net/kanboard-latest.zip +sudo unzip kanboard-latest.zip +sudo chown -R www-data:www-data kanboard/data +sudo rm kanboard-latest.zip +``` + +Now, you should be able to use Kanboard with your web browser. diff --git a/doc/nice-urls.markdown b/doc/nice-urls.markdown new file mode 100644 index 00000000..38f7c41d --- /dev/null +++ b/doc/nice-urls.markdown @@ -0,0 +1,36 @@ +URL rewriting +============= + +Kanboard is able to work indifferently with url rewriting enabled or not. + +- Example of URL rewritten: `/board/123` +- Otherwise: `?controller=board&action=show&project_id=123` + +If you use Kanboard with Apache and with the mode rewrite enabled, nice urls will be used automatically. + +URL Shortcuts +------------- + +- Go to the task #123: **/t/123** +- Go to the board of the project #2: **/b/2** +- Go to the project calendar #5: **/c/5** +- Go to the list view of the project #8: **/l/8** +- Go to the project settings for the project id #42: **/p/42** + +Configuration +------------- + +By default, Kanboard will check if the Apache mode rewrite is enabled. + +To avoid the automatic detection of url rewriting from the web server, you can enable this feature in your config file: + +``` +define('ENABLE_URL_REWRITE', true); +``` + +When this constant is at `true`: + +- URLs generated from command line tools will be also converted +- If you use another web server than Apache, by example Nginx or Microsoft IIS, you have to configure yourself the url rewriting + +Note: Kanboard always fallback to old school urls when it's not configured, this configuration is optional. diff --git a/doc/notifications.markdown b/doc/notifications.markdown new file mode 100644 index 00000000..f42c66cb --- /dev/null +++ b/doc/notifications.markdown @@ -0,0 +1,30 @@ +Notifications +============= + +Kanboard is able to send notifications through several channels: + +- Email +- Jabber/XMPP +- Hipchat +- Slack + +Actually, Jabber/Hipchat/Slack notifications are sent to a room or group channel because they are configured at the project level. +However, email notifications are sent to an individual. + +User notifications +------------------ + +Each user must enable the notifications in their profile: **User Profile > Email notifications**. It's disabled by default. + +You need of course a valid email address in you profile and the application must be configured to send emails. + +![Notifications](http://kanboard.net/screenshots/documentation/notifications.png) + +For each project your are member, you can choose to receive notifications for: + +- All tasks +- Only for tasks assigned to you +- Only for tasks created by you +- Only for tasks created by you and assigned to you + +You can also select only some projects, by default it's all projects where you are member. diff --git a/doc/postgresql-configuration.markdown b/doc/postgresql-configuration.markdown new file mode 100644 index 00000000..3c07ff16 --- /dev/null +++ b/doc/postgresql-configuration.markdown @@ -0,0 +1,40 @@ +Postgresql configuration +======================== + +By default, Kanboard use Sqlite to store its data but it's also possible to use Postgresql. + +Requirements +------------ + +- A Postgresql server already installed and configured +- The PHP extension `pdo_pgsql` installed (Debian/Ubuntu: `apt-get install php5-pgsql`) + +Note: Kanboard is tested with **Postgresql 9.3 and 9.4** + +Configuration +------------- + +### Create an empty database with the command `pgsql`: + +```sql +CREATE DATABASE kanboard; +``` + +### Create a config file + +The file `config.php` should contains those values: + +```php + Integrations > Postmark** + +Kanboard configuration +---------------------- + +1. Be sure that your users have an email address in their profiles +2. Assign a project identifier to the desired projects: **Project settings > Edit** +3. Try to send an email to your project + +Troubleshootings +---------------- + +- Test the webhook url from the Postmark console, you should have a status code `200 OK` diff --git a/doc/project-configuration.markdown b/doc/project-configuration.markdown new file mode 100644 index 00000000..252ace67 --- /dev/null +++ b/doc/project-configuration.markdown @@ -0,0 +1,42 @@ +Project settings +================ + +Go to the menu **Settings**, then choose **Project settings** on the left. + +![Project settings](http://kanboard.net/screenshots/documentation/project-settings.png) + +### Default columns for new projects + +You can change the default column names here. +It's useful if you always create projects with the same columns. + +Each column name must be separated by a comma. + +By default, Kanboard use those column names: Backlog, Ready, Work in progress and Done. + +### Default categories for new projects + +Categories are not global to the application but attached to a project. +Each project can have different categories. + +However, if you always create the same categories for all your projects, you can define here the list of categories to create automatically. + +### Allow only one subtask in progress at the same time for a user + +When this option is enabled, a user can work with only one subtask at the time. + +If another subtask have the status "in progress", the user will see this dialog box: + +![Subtask user restriction](http://kanboard.net/screenshots/documentation/subtask-user-restriction.png) + +### Trigger automatically subtask time tracking + +- If enabled, when a subtask status is changed to "in progress", the timer will start automatically. +- Disable this option if you don't use time tracking. + +### Include closed tasks in the cumulative flow diagram + +- If enabled, closed tasks will be included in the cumulative flow diagram. +- If disabled, only open tasks will be included. +- This option affect the column "total" of the table "project_daily_column_stats" + diff --git a/doc/project-permissions.markdown b/doc/project-permissions.markdown new file mode 100644 index 00000000..d4aa88e3 --- /dev/null +++ b/doc/project-permissions.markdown @@ -0,0 +1,49 @@ +Project permissions +=================== + +A project can have two kinds of people: **project managers** and **project members**. + +- Project managers can manage the configuration of the project and access to the reports. +- Project members can only do basic operations (create or move tasks). + +When you create a new project, you are automatically assigned as a project manager. + +Kanboard administrators can access to everything but they are not necessary project members or managers. Those permissions are defined at the project level. + +Permissions for each role +------------------------- + +### Project members + +- Use the board (create, move and edit tasks) +- Remove only tasks created by themselves + +### Project managers + +- Use the board +- Configure the project + - Share, rename, duplicate and disable the project + - Manage swimlanes, categories, columns and users + - Edit automatic actions +- CSV Exports +- Remove tasks of any project members +- Access to the analytics section + +They **cannot remove the project**. + +Manage users and permissions +---------------------------- + +To define project roles, go to the **project configuration page** then click on **User management**. + +### User management + +![Project permissions](http://kanboard.net/screenshots/documentation/project-permissions.png) + +From there, you can choose to add new members, change the role or revoke user access. + +### Allow everybody + +If you choose to allow everybody (all Kanboard users), the project is considered public. + +That means there is no role management anymore. Permissions per user cannot be applied. diff --git a/doc/project-views.markdown b/doc/project-views.markdown new file mode 100644 index 00000000..a5e9e1f9 --- /dev/null +++ b/doc/project-views.markdown @@ -0,0 +1,37 @@ +Board, Calendar and List views +============================== + +For each project, tasks can be visualized with several views: **Board, Calendar and List**. Each view show the result of the filter box at the top. The search engine use the [advanced syntax](search.markdown). + +Board view +---------- + +![Board view](http://kanboard.net/screenshots/documentation/board-view.png) + +- With this view you can drag and drop tasks between columns easily. +- You can also use the keyboard shortcut **"v b"** to switch to the board view. +- Tasks with a shadow are recently modified. + +![Board Task Limit](http://kanboard.net/screenshots/documentation/board-task-limit.png) + +When the task limit is reached for a column, the background becomes red. That means there are too many tasks in progress at the same time. + +[Learn more about board configuration](board-configuration.markdown) + +Calendar view +-------------- + +![Calendar view](http://kanboard.net/screenshots/documentation/calendar-view.png) + +- With this view you can visualize tasks with a due date. +- Depending of the settings, you can also see tasks in progress. +- You can also use the keyboard shortcut **"v c"** to switch to the calendar view. +- [Learn more about calendar configuration](calendar-configuration.markdown) + +List view +-------------- + +![List view](http://kanboard.net/screenshots/documentation/list-view.png) + +- With this view all results of your search are displayed in a table. +- You can also use the keyboard shortcut **"v l"** to switch to the list view. diff --git a/doc/recommended-configuration.markdown b/doc/recommended-configuration.markdown new file mode 100644 index 00000000..35ed652d --- /dev/null +++ b/doc/recommended-configuration.markdown @@ -0,0 +1,36 @@ +Recommended Configuration +========================= + +Server side +----------- + +- Modern Linux/Unix operating system: **Ubuntu/Debian or FreeBSD** +- Most recent version of PHP and Apache (Kanboard is compatible with PHP 5.3, 5.4, 5.5, 5.6 and 7.0) +- Use the Sqlite database only when you have a disk with fast I/O (SSD disks) otherwise use Mysql or Postgresql + +Client side +----------- + +- Use a modern browser: **Mozilla Firefox or Google Chrome or Safari** + +Tested configurations +--------------------- + +The following configurations are tested with Kanboard but that doesn't mean all features are available: + +### Server + +- Ubuntu 14.04 LTS +- Debian 6, 7 and 8 +- Centos 6.x and 7.0 +- Windows 2012 Server +- Windows 2008 Server + +### Desktops + +- Last version of Mozilla Firefox, Safari and Google Chrome +- Microsoft Internet Explorer 11 + +### Tablets + +- iPad mini 3 diff --git a/doc/recurring-tasks.markdown b/doc/recurring-tasks.markdown new file mode 100644 index 00000000..b1de8d05 --- /dev/null +++ b/doc/recurring-tasks.markdown @@ -0,0 +1,24 @@ +Recurring tasks +=============== + +To fit with the Kanban methodology, the recurring tasks are not based on a date but on board events. + +- Recurring tasks are duplicated to the first column of the board when the selected events occurs +- The due date can be recalculated automatically +- Each task records the task id of the parent task that created it and the child task created + +Configuration +------------- + +Go to the task view page or use the dropdown menu on the board, then select **Edit recurrence**. + +![Recurring task](http://kanboard.net/screenshots/documentation/recurring-tasks.png) + +There are 3 triggers that currently create a new recurring task: + +- Moving a task from the first column +- Moving a task to the last column +- Closing the task + +Due dates, if set on the current task, can be recalculated by a given factor of days, months or years. +The base date for the calculation of the new due date can be either the existing due date, or the action date. diff --git a/doc/reverse-proxy-authentication.markdown b/doc/reverse-proxy-authentication.markdown new file mode 100644 index 00000000..7c001f3d --- /dev/null +++ b/doc/reverse-proxy-authentication.markdown @@ -0,0 +1,64 @@ +Reverse Proxy Authentication +============================ + +This authentication method is often used for [SSO](http://en.wikipedia.org/wiki/Single_sign-on) (Single Sign-On) especially for large organizations. + +The authentication is done by another system, Kanboard doesn't know your password and suppose you are already authenticated. + +Requirements +------------ + +- A well configured reverse proxy + +or + +- Apache auth on the same server + + +How does this work? +------------------- + +1. Your reverse proxy authenticates the user and send the username through a HTTP header. +2. Kanboard retreive the username from the request + - The user is created automatically if necessary + - Open a new Kanboard session without any prompt assuming it's valid + +Installation instructions +------------------------- + +### Setting up your reverse proxy + +This is not in the scope of this documentation. +You should check the user login is sent by the reverse proxy using a HTTP header, and find which one. + +### Setting up Kanboard + +Create a custom `config.php` file or copy the `config.default.php` file: + +```php + Public access**. + +![Disable public access](http://kanboard.net/screenshots/documentation/project-disable-sharing.png) + +Enable/disable user RSS feeds +-------------------------------- + +Go to **User profile > Public access**. + +The RSS link is protected by a random token, only people who knows the url can access to the feed. \ No newline at end of file diff --git a/doc/screenshots.markdown b/doc/screenshots.markdown new file mode 100644 index 00000000..3ec6bc7a --- /dev/null +++ b/doc/screenshots.markdown @@ -0,0 +1,25 @@ +Adding screenshots +================== + +You can copy and paste images directly in Kanboard to save time. +These images are uploaded as attachments to the task. + +This is especially useful for taking screenshots to describe an issue by example. + +You can add screenshots directly from the board by clicking on the dropdown menu or in the task view page. + +![Dropdown screenshot menu](http://kanboard.net/screenshots/documentation/dropdown-screenshot.png) + +To add a new image, take your screenshot and paste with CTRL+V or Command+V: + +![Screenshot page](http://kanboard.net/screenshots/documentation/task-screenshot.png) + +On Mac OS X, you can use those shortcuts to take screenshots: + +- Command-Control-Shift-3: Take a screenshot of the screen, and save it to the clipboard +- Command-Control-Shift-4, then select an area: Take a screenshot of an area and save it to the clipboard +- Command-Control-Shift-4, then space, then click a window: Take a screenshot of a window and save it to the clipboard + +There are also several third-party applications that can be used to take screenshots with annotations and shapes. + +**Note: This feature doesn't works with all browsers.** diff --git a/doc/search.markdown b/doc/search.markdown new file mode 100644 index 00000000..34a20bc6 --- /dev/null +++ b/doc/search.markdown @@ -0,0 +1,138 @@ +Advanced Search Syntax +====================== + +Kanboard use a simple query language for advanced search. + +Example of query +---------------- + +This example will returns all tasks assigned to me with a due date for tomorrow and a title that contains "my title": + +``` +assigne:me due:tomorrow my title +``` + +Search by task id or title +-------------------------- + +- Search by task id: `#123` +- Search by task id and task title: `123` +- Search by task title: anything that don't match any search attributes + +Search by status +---------------- + +Attribute: **status** + +- Query to find open tasks: `status:open` +- Query to find closed tasks: `status:closed` + +Search by assignee +------------------ + +Attribute: **assignee** + +- Query with the full name: `assignee:"Frederic Guillot"` +- Query with the username: `assignee:fguillot` +- Multiple assignee lookup: `assignee:user1 assignee:"John Doe"` +- Query for unassigned tasks: `assignee:nobody` +- Query for my assigned tasks: `assignee:me` + +Note: Kanboard will also search in assigned subtasks with the status todo and in progress. + +Search by color +--------------- + +Attribute: **color** + +- Query to search by color id: `color:blue` +- Query to search by color name: `color:"Deep Orange"` + +Search by due date +------------------ + +Attribute: **due** + +- Search tasks due today: `due:today` +- Search tasks due tomorrow: `due:tomorrow` +- Search tasks due yesterday: `due:yesterday` +- Search tasks due with the exact date: `due:2015-06-29` + +The date must use the ISO8601 format: **YYYY-MM-DD**. + +All string formats supported by the `strtotime()` function are supported, by example `next Thursday`, `-2 days`, `+2 months`, `tomorrow`, etc... + +Operators supported with a date: + +- Greater than: **due:>2015-06-29** +- Lower than: **due:<2015-06-29** +- Greater than or equal: **due:>=2015-06-29** +- Lower than or equal: **due:<=2015-06-29** + +Search by modification date +--------------------------- + +Attribute: **modified** or **updated** + +The date formats are the same as the due date. + +There is also a filter by recently modified tasks: `modified:recently`. + +This query will use the same value as the board highlight period configured in settings. + +Search by creation date +----------------------- + +Attribute: **created** + +Works in the same way as the modification date queries. + +Search by description +--------------------- + +Attribute: **description** + +Example: `description:"text search"` + +Search by external reference +---------------------------- + +The task reference is an external id of your task, by example a ticket number from another software. + +- Find tasks with a reference: `ref:1234` or `reference:TICKET-1234` + +Search by category +------------------ + +Attribute: **category** + +- Find tasks with a specific category: `category:"Feature Request"` +- Find all tasks that have those categories: `category:"Bug" category:"Improvements"` +- Find tasks with no category assigned: `category:none` + +Search by project +----------------- + +Attribute: **project** + +- Find tasks by project name: `project:"My project name"` +- Find tasks by project id: `project:23` +- Find tasks for several projects: `project:"My project A" project:"My project B"` + +Search by column +---------------- + +Attribute: **column** + +- Find tasks by column name: `column:"Work in progress"` +- Find tasks for several columns: `column:"Backlog" column:ready` + +Search by swimlane +------------------ + +Attribute: **swimlane** + +- Find tasks by swimlane: `swimlane:"Version 42"` +- Find tasks in the default swimlane: `swimlane:default` +- Find tasks into several swimlanes: `swimlane:"Version 1.2" swimlane:"Version 1.3"` + diff --git a/doc/sendgrid.markdown b/doc/sendgrid.markdown new file mode 100644 index 00000000..0f307dac --- /dev/null +++ b/doc/sendgrid.markdown @@ -0,0 +1,24 @@ +Sendgrid +======== + +You can use the service [Sendgrid](https://sendgrid.com/) to create tasks directly by email. + +This integration works with the [Parse API of Sendgrid](https://sendgrid.com/docs/API_Reference/Webhooks/parse.html). +Kanboard use a webhook to handle incoming emails. + +The [incoming email workflow is described here](create-tasks-by-email.markdown). + +Sendgrid configuration +---------------------- + +1. Create a new domain or subdomain (by example **inbound.mydomain.tld**) with a MX record that point to **mx.sendgrid.net** +2. Add your domain and the Kanboard webhook url to [the configuration page in Sendgrid](https://sendgrid.com/developer/reply) + +The Kanboard webhook url is displayed in **Settings > Integrations > Sendgrid** + +Kanboard configuration +---------------------- + +1. Be sure that your users have an email address in their profiles +2. Assign a project identifier to the desired projects: **Project settings > Edit** +3. Try to send an email to your project diff --git a/doc/sharing-projects.markdown b/doc/sharing-projects.markdown new file mode 100644 index 00000000..3e72071b --- /dev/null +++ b/doc/sharing-projects.markdown @@ -0,0 +1,35 @@ +Sharing boards and tasks +======================== + +By default, boards are private but it's possible to make a board public. + +A public board can't be modified, it's a **read-only access**. +This access is protected by a random token, only people who have the right token can see the board. + +Public boards are automatically refreshed every 60 seconds. +Task details are also available in read-only. + +Usage examples: + +- Share your board with someone outside of your organization +- Display the board on a large screen in your office + +Enable public access +------------------- + +Select your project, then click on "Public access" and finally click on the button "Enable public access". + +![Enable public access](http://kanboard.net/screenshots/documentation/project-enable-sharing.png) + +When the public access is enabled, a couple of links are generated: + +- Public board view +- RSS feed subscription link +- iCalendar subscription link + +![Disable public access](http://kanboard.net/screenshots/documentation/project-disable-sharing.png) + +You can also disable the public access whenever you want. + +Each time, you enable or disable the public access a new random token is generated. +The previous links will not work anymore. diff --git a/doc/slack.markdown b/doc/slack.markdown new file mode 100644 index 00000000..f90464e8 --- /dev/null +++ b/doc/slack.markdown @@ -0,0 +1,38 @@ +Slack integration +================= + +You can send notifications to Slack for all projects or only for specific projects. + +- To send notifications for all projects, go to **Settings > Integrations > Slack** +- To send notifications for only some projects, go to **Project settings > Integrations > Slack** + +Each project can send notifications to a separate channel. + +Send notifications to a channel +------------------------------- + +Example of notifications: + +![Slack notification](http://kanboard.net/screenshots/documentation/slack-notification.png) + +This feature use the [Incoming webhook](https://api.slack.com/incoming-webhooks) system of Slack. + +### Slack configuration + +![Slack webhook creation](http://kanboard.net/screenshots/documentation/slack-add-incoming-webhook.png) + +1. Click on the Team dropdown and choose **Configure Integrations** +2. On the list of services, scroll-down and choose **DIY Integrations & Customizations > Incoming WebHooks** +3. Copy the webhook url to the Kanboard settings page: **Settings > Integrations > Slack** or **Project settings > Integrations > Slack** + +Now, Kanboard events will be sent to the Slack channel. + +### Overriding Channel (Optional) + +Optionally you can override the channel, private group or send direct messages by filling up **Channel/Group/User** text box. Leaving it empty will post to the channel configured during webhook configuration. + +Examples: + +- Send messages to another channel: **#mychannel1** +- Send messages to a private group: **#myprivategroup1** +- Send messages directly to someone: **@anotheruser1** diff --git a/doc/sqlite-database.markdown b/doc/sqlite-database.markdown new file mode 100644 index 00000000..0a6a0ab6 --- /dev/null +++ b/doc/sqlite-database.markdown @@ -0,0 +1,50 @@ +Sqlite database management +========================== + +Kanboard uses Sqlite by default to store its data. +All tasks, projects and users are stored inside this database. + +Technically, the database is just a single file located inside the directory `data` and named `db.sqlite`. + +Export/Backup +------------- + +### Command line + +Doing a backup is very easy, just copy the file `data/db.sqlite` somewhere else when nobody use the software. + +### User interface + +You can also download at any time the database directly from the **settings** menu. + +The downloaded database is compressed with Gzip, the filename becomes `db.sqlite.gz`. + +Import/Restoration +------------------ + +There is actually no way to restore the database from the user interface. +The restoration must be done manually when no body use the software. + +- To restore an old backup, just replace and overwrite the actual file `data/db.sqlite`. +- To uncompress a gzipped database, execute this command from a terminal `gunzip db.sqlite.gz`. + +Optimization +------------ + +Occasionally, it's possible to optimize the database file by running the command `VACUUM`. +This command rebuild the entire database and can be used for several reasons: + +- Reduce the file size, deleting data produce empty space but doesn't change the file size. +- The database is fragmented due to frequent inserts or updates. + +### From the command line + +``` +sqlite3 data/db.sqlite 'VACUUM' +``` + +### From the user interface + +Go to the menu **settings** and click on the link **Optimize the database**. + +For more information, read the [Sqlite documentation](https://sqlite.org/lang_vacuum.html). diff --git a/doc/subtasks.markdown b/doc/subtasks.markdown new file mode 100644 index 00000000..6ea67284 --- /dev/null +++ b/doc/subtasks.markdown @@ -0,0 +1,47 @@ +Subtasks +======== + +Subtasks are useful to split the work of a task. + +Each subtask: + +- Can be assigned to a project member +- Have 3 different statuses: **Todo**, **In progress**, **Done** +- Have time tracking information: **time spent** and **time estimated** +- Be ordered by position + +Creating subtasks +----------------- + +From the task view, on left sidebar click on **Add a subtask**: + +![Add a subtask](http://kanboard.net/screenshots/documentation/add-subtask.png) + +You can also add quickly a subtask by entering only the title: + +![Add a subtask from the task view](http://kanboard.net/screenshots/documentation/add-subtask-shortcut.png) + +Change subtask status +--------------------- + +When you click on the subtask title the status change: + +![Subtask in progress](http://kanboard.net/screenshots/documentation/subtask-status-inprogress.png) + +The icon before the title is updated according to the status. + +![Subtask done](http://kanboard.net/screenshots/documentation/subtask-status-done.png) + +Note: When the task is closed, all subtasks are changed to the status **Done**. + +Subtask timer +------------- + +Each time a subtask is in progress, the timer is also started. The timer can be started and stopped at any time. + +The timer records the time spent on the subtask automatically. You can also change manually the value of the time spent field when you edit a subtask. + +The time calculated is rounded to the nearest quarter. This information is recorded in a separate table. + +The task time spent is updated automatically according to the sum of all subtasks time spent. + diff --git a/doc/swimlanes.markdown b/doc/swimlanes.markdown new file mode 100644 index 00000000..25e8b6b9 --- /dev/null +++ b/doc/swimlanes.markdown @@ -0,0 +1,29 @@ +Swimlanes +========= + +Swimlanes are horizontal separations in your board. +By example, it's useful to separate software releases, divide your tasks in different products, teams or what ever you want. + +Board with swimlanes +-------------------- + +![Swimlanes Configuration](http://kanboard.net/screenshots/documentation/swimlanes.png) + +Managing swimlanes +------------------ + +- All projects have a default swimlane. +- If there is more than one swimlane, the board will show all swimlanes. +- You can drag and drop tasks between swimlanes. + +To configure swimlanes go to the **project configuration page** and choose the section **Swimlanes**. + +![Swimlanes Configuration](http://kanboard.net/screenshots/documentation/swimlanes-configuration.png) + +From there, you can add a new swimlane or rename the default one. +You can also disable and change the position of the different swimlanes. + +- The default swimlane is always on the top but you can hide it. +- Inactive swimlanes are not shown on the board. +- **Removing a swimlane doesn't remove tasks assigned to it**, those tasks will be moved to the default swimlane. + diff --git a/doc/syntax-guide.markdown b/doc/syntax-guide.markdown new file mode 100644 index 00000000..8b1324f0 --- /dev/null +++ b/doc/syntax-guide.markdown @@ -0,0 +1,139 @@ +Syntax Guide +============ + +Kanboard use the [Markdown syntax](http://en.wikipedia.org/wiki/Markdown) for comments or task descriptions. +Here are some examples: + +Bold and italic +---------------- + +- Bold text: Use 2 asterisks or 2 underscores +- Italic text: Use 1 asterisk or 1 underscore + +### Source +``` +This **word** is very __important__. + +And here, an *italic* word with one _underscore_. +``` + +### Result + +This **word** is very __important__. + +And here, an *italic* word with one _underscore_. + +Unordered Lists +--------------- + +Unordered list can use asterisks, minuses or pluses. + +### Source + +``` +- Item 1 +- Item 2 +- Item 3 + +or + +* Item 1 +* Item 2 +* Item 3 +``` + +### Result + +- Item 1 +- Item 2 +- Item 3 + +Ordered lists +------------- + +Ordered lists are prefixed by a number like that: + +### Source + +``` +1. Do that first +2. Do this +3. And that +``` + +### Result + +1. Do that first +2. Do this +3. And that + +Links +----- + +### Source + +``` +[My link title](http://kanboard.net/) + + + +``` + +### Result + +[My link title](http://kanboard.net/) + + + +Source code +----------- + +### Inline code + +Use a backtick. + +``` +Execute this command: `tail -f /var/log/messages`. +``` + +### Result + +Execute this command: `tail -f /var/log/messages`. + +### Code blocks + +Use 3 backticks with eventually the language name. + +

    +```php
    +<?php
    +
    +phpinfo();
    +
    +?>
    +```
    +
    +
    + +### Result + +``` + +``` + +Titles +------ + +### Source + +``` +# Title level 1 + +## Title level 2 + +### Title level 3 +``` diff --git a/doc/task-links.markdown b/doc/task-links.markdown new file mode 100644 index 00000000..1eab51fd --- /dev/null +++ b/doc/task-links.markdown @@ -0,0 +1,22 @@ +Task Links +========== + +Tasks can be linked together with predefined relationships: + +![Task Links](http://kanboard.net/screenshots/documentation/task-links.png) + +The default relationships are: + +- **relates to** +- **blocks** | is blocked by +- **is blocked by** | blocks +- **duplicates** | is duplicated by +- **is duplicated by** | duplicates +- **is a child of** | is a parent of +- **is a parent of** | is a child of +- **targets milestone** | is a milestone of +- **is a milestone of** | targets milestone +- **fixes** | is fixed by +- **is fixed by** | fixes + +Those labels can be changed in the application settings. diff --git a/doc/tests.markdown b/doc/tests.markdown new file mode 100644 index 00000000..31937f33 --- /dev/null +++ b/doc/tests.markdown @@ -0,0 +1,176 @@ +How to run units and functionals tests? +======================================= + +[PHPUnit](https://phpunit.de/) is used to run automatic tests on Kanboard. + +You can run tests across different databases (Sqlite, Mysql and Postgresql) to be sure that the result is the same everywhere. + +Requirements +------------ + +- Linux/Unix machine +- PHP command line +- PHPUnit installed +- Mysql and Postgresql (optional) + +Install the latest version of PHPUnit +------------------------------------- + +Simply download the PHPUnit PHAR et copy the file somewhere in your `$PATH`: + +```bash +wget https://phar.phpunit.de/phpunit.phar +chmod +x phpunit.phar +sudo mv phpunit.phar /usr/local/bin/phpunit +phpunit --version +PHPUnit 4.2.6 by Sebastian Bergmann. +``` + +Running unit tests +------------------ + +### Testing with Sqlite + +Sqlite tests use a in-memory database, nothing is written on the filesystem. + +The config file is `tests/units.sqlite.xml`. +From your Kanboard directory, run the command `phpunit -c tests/units.sqlite.xml`. + +Example: + +```bash +phpunit -c tests/units.sqlite.xml + +PHPUnit 4.2.6 by Sebastian Bergmann. + +Configuration read from /Volumes/Devel/apps/kanboard/tests/units.sqlite.xml + +................................................................. 65 / 74 ( 87%) +......... + +Time: 9.05 seconds, Memory: 17.75Mb + +OK (74 tests, 6145 assertions) +``` + +**NOTE:** PHPUnit is already included in the Vagrant environment + +### Testing with Mysql + +You must have Mysql or MariaDb installed on localhost. + +By default, those credentials are used: + +- Hostname: **localhost** +- Username: **root** +- Password: none +- Database: **kanboard_unit_test** + +For each execution the database is dropped and created again. + +The config file is `tests/units.mysql.xml`. +From your Kanboard directory, run the command `phpunit -c tests/units.mysql.xml`. + +Example: + +```bash +phpunit -c tests/units.mysql.xml + +PHPUnit 4.2.6 by Sebastian Bergmann. + +Configuration read from /Volumes/Devel/apps/kanboard/tests/units.mysql.xml + +................................................................. 65 / 74 ( 87%) +......... + +Time: 49.77 seconds, Memory: 17.50Mb + +OK (74 tests, 6145 assertions) +``` + +### Testing with Postgresql + +You must have Postgresql installed on localhost. + +By default, those credentials are used: + +- Hostname: **localhost** +- Username: **postgres** +- Password: none +- Database: **kanboard_unit_test** + +Be sure to allow the user `postgres` to create and drop databases. +For each execution the database is dropped and created again. + +The config file is `tests/units.postgres.xml`. +From your Kanboard directory, run the command `phpunit -c tests/units.postgres.xml`. + +Example: + +```bash +phpunit -c tests/units.postgres.xml + +PHPUnit 4.2.6 by Sebastian Bergmann. + +Configuration read from /Volumes/Devel/apps/kanboard/tests/units.postgres.xml + +................................................................. 65 / 74 ( 87%) +......... + +Time: 52.66 seconds, Memory: 17.50Mb + +OK (74 tests, 6145 assertions) +``` + +Running functionals tests +------------------------- + +Actually only the API calls are tested. + +Real HTTP calls are made with those tests. +So a local instance of Kanboard is necessary and must listen on `http://localhost:8000`. + +Don't forget that all data will be removed/altered by the test suite. +Moreover the script will reset and set a new API key. + +1. Start a local instance of Kanboard `php -S 127.0.0.1:8000` +2. Run the test suite from another terminal + +The same method as above is used to run tests across different databases: + +- Sqlite: `phpunit -c tests/functionals.sqlite.xml` +- Mysql: `phpunit -c tests/functionals.mysql.xml` +- Postgresql: `phpunit -c tests/functionals.postgres.xml` + +Example: + +```bash +phpunit -c tests/functionals.sqlite.xml + +PHPUnit 4.2.6 by Sebastian Bergmann. + +Configuration read from /Volumes/Devel/apps/kanboard/tests/functionals.sqlite.xml + +.......................................... + +Time: 1.72 seconds, Memory: 4.25Mb + +OK (42 tests, 160 assertions) +``` + +Continuous Integration with Travis-ci +------------------------------------- + +After each commit pushed on the main repository, unit tests are executed across 5 different versions of PHP: + +- PHP 7.0 +- PHP 5.6 +- PHP 5.5 +- PHP 5.4 +- PHP 5.3 + +Each version of PHP is tested against the 3 supported database: Sqlite, Mysql and Postgresql. + +That mean we run 15 jobs each time the repository is updated. The execution time is around 25 minutes. + +The Travis config file `.travis.yml` is located on the root directory of Kanboard. diff --git a/doc/time-tracking.markdown b/doc/time-tracking.markdown new file mode 100644 index 00000000..8c65b16a --- /dev/null +++ b/doc/time-tracking.markdown @@ -0,0 +1,43 @@ +Time Tracking +============= + +Time tracking information can be defined at the task level or at the subtask level. + +Task time tracking +------------------ + +![Task time tracking](http://kanboard.net/screenshots/documentation/task-time-tracking.png) + +Tasks have two fields: + +- Time estimated +- Time spent + +These values represents hours of work and have to be set manually. + +Subtask time tracking +--------------------- + +![Subtask time tracking](http://kanboard.net/screenshots/documentation/subtask-time-tracking.png) + +Subtasks also have the fields "time spent" and "time estimated". + +When you change the value of these fields, **the task time tracking values are updated automatically and becomes the sum of all subtask values**. + +Kanboard records the time between each subtask status change in a separate table. + +- Changing subtask status from **todo** to **in pogress** logs the start time +- Changing subtask status from **in progress** to **done** logs the end time but also update the time spent of the subtask and the task + +The breakdown of all records is visible in the task view page: + +![Task timesheet](http://kanboard.net/screenshots/documentation/task-timesheet.png) + +For each subtask, the timer can be stopped/started at any time: + +![Subtask timer](http://kanboard.net/screenshots/documentation/subtask-timer.png) + +- The timer doesn't depends of the subtask status +- Each time you start the timer a new record is created in the time tracking table +- Each time you stop the clock the end date is recorded in the time tracking table +- The calculated time spent is rounded to the nearest quarter diff --git a/doc/timetable.markdown b/doc/timetable.markdown new file mode 100644 index 00000000..5d2f4c86 --- /dev/null +++ b/doc/timetable.markdown @@ -0,0 +1,46 @@ +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/doc/transitions.markdown b/doc/transitions.markdown new file mode 100644 index 00000000..c32f696a --- /dev/null +++ b/doc/transitions.markdown @@ -0,0 +1,20 @@ +Task transitions +================ + +Transitions record each movement of the tasks between columns. + +![Transitions](http://kanboard.net/screenshots/documentation/transitions.png) + +Available from the task view, you can see those information: + +- Date of the action +- Source column +- Destination column +- Executer (user that move the task) +- Time spent in the origin column + +Task transition data can also be exported from the project settings page. + +![Transitions Export](http://kanboard.net/screenshots/documentation/transitions-export.png) + +For the specified time range you will generate a CSV file that you can use with any spreadsheet software. diff --git a/doc/translations.markdown b/doc/translations.markdown new file mode 100644 index 00000000..7a4e325b --- /dev/null +++ b/doc/translations.markdown @@ -0,0 +1,79 @@ +Translations +============ + +How to translate Kanboard to a new language? +-------------------------------------------- + +- Translations are stored inside the directory `app/Locale` +- There is sub-directory for each language, by example for the French we have `fr_FR`, Italian `it_IT` etc... +- A translation is a PHP file that returns an Array with a key-value pairs +- The key is the original text in english and the value is the translation for the corresponding language +- **French translations are always up to date** +- Always use the last version (branch master) + +### Create a new translation: + +1. Make a new directory: `app/Locale/xx_XX` by example `app/Locale/fr_CA` for French Canadian +2. Create a new file for the translation: `app/Locale/xx_XX/translations.php` +3. Use the content of the French locales and replace the values +4. Inside the file `app/Model/Config.php`, add a new entry for your translation inside the function `getLanguages()` +5. Check with your local installation of Kanboard if everything is ok +6. Send a [pull-request with Github](https://help.github.com/articles/using-pull-requests/) + +How to update an existing translation? +-------------------------------------- + +1. Open the translation file `app/Locale/xx_XX/translations.php` +2. Missing translations are commented with `//` and the values are empty, just fill blank and remove the comment +3. Check with your local installation of Kanboard and send a [pull-request](https://help.github.com/articles/using-pull-requests/) + +How to add new translated text in the application? +-------------------------------------------------- + +Translations are displayed with the following functions in the source code: + +- `t()`: dispaly text with HTML escaping +- `e()`: display text without HTML escaping +- `dt()`: display date and time using the `strftime()` function formats + +Always use the english version in the source code. + +### Date and time translation + +Date strings use the function `strftime()` to format the date. + +By example, the original English version can be defined like that `Created on %B %e, %Y at %k:%M %p` and that will output something like that `Created on January 11, 2015 at 15:19 PM`. The French version can be modified to display a different format, `Créé le %d/%m/%Y à %H:%M` and the result will be `Créé le 11/01/2015 à 15:19`. + +All formats are available in the [PHP documentation](http://php.net/strftime). + +### Placeholders + +Text strings use the function `sprintf()` to replace elements: + +- `%s` is used to replace a string +- `%d` is used to replace an integer + +All formats are available in the [PHP documentation](http://php.net/sprintf). + +How to find missing translations in the applications? +----------------------------------------------------- + +From a terminal, run the following command: + +```bash +./kanboard locale:compare +``` + +All missing and unused translations are displayed on the screen. +Put that in the French locale and sync other locales (see below). + +How to synchronize translation files? +------------------------------------- + +From a Unix shell run this command: + +```bash +./kanboard locale:sync +``` + +The French translation is used a reference for other locales. diff --git a/doc/ubuntu-installation.markdown b/doc/ubuntu-installation.markdown new file mode 100644 index 00000000..5f9ee65b --- /dev/null +++ b/doc/ubuntu-installation.markdown @@ -0,0 +1,28 @@ +How to install Kanboard on Ubuntu? +================================== + +Ubuntu 14.04 LTS +---------------- + +Install Apache and PHP: + +```bash +sudo apt-get update +sudo apt-get install -y php5 php5-sqlite unzip +``` + +In case your webserver was running restart to make sure the php modules are reloaded + +```bash +service apache2 restart +``` + +Install Kanboard: + +```bash +cd /var/www/html +sudo wget http://kanboard.net/kanboard-latest.zip +sudo unzip kanboard-latest.zip +sudo chown -R www-data:www-data kanboard/data +sudo rm kanboard-latest.zip +``` diff --git a/doc/update.markdown b/doc/update.markdown new file mode 100644 index 00000000..d502f794 --- /dev/null +++ b/doc/update.markdown @@ -0,0 +1,26 @@ +Update +====== + +**Always make a backup of your database before upgrading!** + +From the archive (stable version) +--------------------------------- + +1. Close your session (logout) +2. Rename your actual Kanboard directory (to keep a backup) +3. Uncompress the new archive and copy your `data` directory to the newly uncompressed directory. +4. Copy your custom `config.php` (if you created one) to the root of the newly uncompressed directory. +5. Make the directory `data` writeable by the web server user +6. Login and check if everything is ok +7. Remove the old Kanboard directory + + +From the repository (development version) +----------------------------------------- + +1. Close your session (logout) +2. `git pull` +3. `composer install` +3. Login and check if everything is ok + +Note: This method will install the **current development version**, use at your own risk. diff --git a/doc/usage-examples.markdown b/doc/usage-examples.markdown new file mode 100644 index 00000000..f2d457a6 --- /dev/null +++ b/doc/usage-examples.markdown @@ -0,0 +1,67 @@ +Usage examples +============== + +You can customize your boards according to your business activities: + +Software development +-------------------- + +- Backlog +- Ready +- Work in progress +- To be validated +- Validated +- Deployed in production + +Bug tracking +------------ + +- Reported +- Confirmed +- Work in progress +- Tested +- Fixed + +Sales +----- + +- Leads +- Meeting +- Proposal +- Purchase + +Lean business management +------------------------ + +- Ideas +- Development +- Measure +- Analysis +- Done + +Recruiting process +------------------ + +- Job offers +- Candidates +- Phone screens +- Interviews +- Hires + +Online shops +------------ + +- Orders +- Packaging +- Ready to send +- Shipped + +Manufactory +----------- + +- Customer Orders +- Assembly +- Tests +- Packaging +- Ready to ship +- Shipped diff --git a/doc/user-management.markdown b/doc/user-management.markdown new file mode 100644 index 00000000..25cc8539 --- /dev/null +++ b/doc/user-management.markdown @@ -0,0 +1,81 @@ +User management +=============== + +Roles at the application level +------------------------------ + +Kanboard use a basic permission system, there are 3 type of users: + +### Administrators + +- Access to everything + +### Project Administrators + +- Can create multi-users and private projects +- Can convert multi-users and private projects +- Can see only their own projects +- Cannot change application settings +- Cannot manage users + +### Standard Users + +- Can create only private projects +- Can see only their own projects +- Cannot remove projects + +Roles at the project level +-------------------------- + +These role are related to the project permission. + +### Project Managers + +- Can manage only their own projects +- Can access to reports and budget section + +### Project Members + +- Can do any daily operations in their projects (create and move tasks...) +- Cannot configure projects + +Note: Any "Standard User" can be promotted "Project Manager" for a given project, they don't necessary need to be "Project Administrator". + +Local and remote users +---------------------- + +- A local user is an account that use the database to store credentials. Local users use the login form for the authentication. +- A remote user is an account that use an external system to store credentials. By example, it can be LDAP, Github or Google accounts. Authentication of these users can be done through the login form or not. + +Add a new user +-------------- + +To add a new user, you must be administrator. + +1. From the dashboard, go to the menu **User Management** +2. On the top, you have a link **New local user** or **New remote user** +3. Fill the form and save + +![New user](http://kanboard.net/screenshots/documentation/new-user.png) + +When you create a **local user**, you have to specify at least those values: + +- **username**: This is the unique identifier of your user (login) +- **password**: The password of your user must have at least 6 characters + +For **remote users**, only the username is mandatory. You can also pre-link Github or Google accounts if you already know their unique id. + +Edit users +---------- + +When you go to the **users** menu, you have the list of users, to modify a user click on the **edit link**. + +- If you are a regular user, you can change only your own profile +- You have to be administrator to be able to edit any users + +Remove users +------------ + +From the **users** menu, click on the link **remove**. This link is visible only if you are administrator. + +If you remove a specific user, **tasks assigned to this person will be unassigned** after the operation. diff --git a/doc/vagrant.markdown b/doc/vagrant.markdown new file mode 100644 index 00000000..beebb323 --- /dev/null +++ b/doc/vagrant.markdown @@ -0,0 +1,64 @@ +Run Kanboard with Vagrant +========================= + +Vagrant is used to test Kanboard in different environments. + +Several configurations are available: + +- Ubuntu 14.04 LTS with Sqlite +- Ubuntu 14.04 LTS with Mysql +- Ubuntu 14.04 LTS with Postgresql +- Debian 8 with sqlite +- Debian 7.6 with Sqlite +- Debian 6 with Sqlite +- Centos 7 with Sqlite +- Centos 6.5 with Sqlite +- Freebsd 10 with Sqlite + +The installation process is not fully automated for all VM, manual configuration can be required. + +To use those configurations, you have to install the **last version of Virtualbox and Vagrant**. + +Standard boxes can be downloaded from Vagrant: + +```bash +vagrant box add ubuntu/trusty64 +vagrant box add debian/jessie64 +vagrant box add chef/debian-7.6 +vagrant box add chef/debian-6.0.10 +vagrant box add chef/centos-7.0 +vagrant box add chef/centos-6.5 +vagrant box add freebsd/FreeBSD-10.2-STABLE +``` + +### Example with Ubuntu and Sqlite + +If you want to test Kanboard on Ubuntu with Sqlite: + +```bash +vagrant up sqlite +``` + +Run composer: + +```bash +vagrant ssh sqlite +cd /var/www/html # change the path according to the chosen distribution +sudo composer install +``` + +After the initialization, go to **http://localhost:8001/**. + +If you want to use Postgresql or Mysql, you have to configure Kanboard manually (`config.php`) and configure the database inside the virtual machine. + +Available boxes are: + +- `vagrant up sqlite` +- `vagrant up mysql` +- `vagrant up postgres` +- `vagrant up debian8` +- `vagrant up debian7` +- `vagrant up debian6` +- `vagrant up centos7` +- `vagrant up centos65` +- `vagrant up freebsd10` diff --git a/doc/webhooks.markdown b/doc/webhooks.markdown new file mode 100644 index 00000000..f7925350 --- /dev/null +++ b/doc/webhooks.markdown @@ -0,0 +1,306 @@ +Webhooks +======== + +Webhooks are useful to perform actions with external applications. + +- Webhooks can be used to create a task by calling a simple URL (You can also do that with the API) +- An external URL can be called automatically when an event occurs in Kanboard (task creation, comment updated, etc) + +How to write a webhook receiver? +-------------------------------- + +All internal events of Kanboard can be sent to an external URL. + +- The webhook url have to be defined in **Settings > Webhooks > Webhook URL**. +- When an event is triggered Kanboard call automatically the predefined URL +- The data are encoded in JSON format and sent with a POST HTTP request +- The webhook token is also sent as a query string parameter, so you can check if the request really come from Kanboard. +- **Your custom URL must answer in less than 1 second**, those requests are synchronous (PHP limitation) and that can slow down the user interface if your script is too slow! + +### List of supported events + +- comment.create +- comment.update +- file.create +- task.move.project +- task.move.column +- task.move.position +- task.move.swimlane +- task.update +- task.create +- task.close +- task.open +- task.assignee_change +- subtask.update +- subtask.create + +### Example of HTTP request + +``` +POST https://your_webhook_url/?token=WEBHOOK_TOKEN_HERE +User-Agent: Kanboard Webhook +Content-Type: application/json +Connection: close + +{ + "event_name": "task.move.column", + "event_data": { + "task_id": "1", + "project_id": "1", + "position": 1, + "column_id": "1", + "swimlane_id": "0", + "src_column_id": "2", + "dst_column_id": "1", + "date_moved": "1431991532", + "recurrence_status": "0", + "recurrence_trigger": "0" + } +} +``` + +All event payloads are in the following format: + +```json +{ + "event_name": "model.event_name", + "event_data": { + "key1": "value1", + "key2": "value2", + ... + } +} +``` + +The `event_data` values are not necessary normalized across events. + +### Examples of event payloads + +Task creation: + +```json +{ + "event_name": "task.create", + "event_data": { + "title": "Demo", + "description": "", + "project_id": "1", + "owner_id": "1", + "category_id": 0, + "swimlane_id": 0, + "column_id": "2", + "color_id": "yellow", + "score": 0, + "time_estimated": 0, + "date_due": 0, + "creator_id": 1, + "date_creation": 1431991532, + "date_modification": 1431991532, + "date_moved": 1431991532, + "position": 1, + "task_id": 1 + } +} +``` + +Task modification: + +```json +{ + "event_name": "task.update", + "event_data": { + "id": "1", + "title": "Demo", + "description": "", + "date_creation": "1431991532", + "color_id": "yellow", + "project_id": "1", + "column_id": "1", + "owner_id": "1", + "position": "1", + "is_active": "1", + "date_completed": null, + "score": "0", + "date_due": "0", + "category_id": "2", + "creator_id": "1", + "date_modification": 1431991603, + "reference": "", + "date_started": 1431993600, + "time_spent": 0, + "time_estimated": 0, + "swimlane_id": "0", + "date_moved": "1431991572", + "recurrence_status": "0", + "recurrence_trigger": "0", + "recurrence_factor": "0", + "recurrence_timeframe": "0", + "recurrence_basedate": "0", + "recurrence_parent": null, + "recurrence_child": null, + "task_id": "1", + "changes": { + "category_id": "2" + } + } +} +``` + +Task update events have a field called `changes` that contains updated values. + +Move a task to another column: + +```json +{ + "event_name": "task.move.column", + "event_data": { + "task_id": "1", + "project_id": "1", + "position": 1, + "column_id": "1", + "swimlane_id": "0", + "src_column_id": "2", + "dst_column_id": "1", + "date_moved": "1431991532", + "recurrence_status": "0", + "recurrence_trigger": "0" + } +} +``` + +Move a task to another position: + +```json +{ + "event_name": "task.move.position", + "event_data": { + "task_id": "2", + "project_id": "1", + "position": 1, + "column_id": "1", + "swimlane_id": "0", + "src_column_id": "1", + "dst_column_id": "1", + "date_moved": "1431996905", + "recurrence_status": "0", + "recurrence_trigger": "0" + } +} +``` + +Comment creation: + +```json +{ + "event_name": "comment.create", + "event_data": { + "id": 1, + "task_id": "1", + "user_id": "1", + "comment": "test", + "date_creation": 1431991615 + } +} +``` + +Comment modification: + +``` +{ + "event_name": "comment.update", + "event_data": { + "id": "1", + "task_id": "1", + "user_id": "1", + "comment": "test edit" + } +} +``` + +Subtask creation: + +```json +{ + "event_name": "subtask.create", + "event_data": { + "id": 3, + "task_id": "1", + "title": "Test", + "user_id": "1", + "time_estimated": "2", + "position": 3 + } +} +``` + +Subtask modification: + +```json +{ + "event_name": "subtask.update", + "event_data": { + "id": "1", + "status": 1, + "task_id": "1" + } +} +``` + +File upload: + +```json +{ + "event_name": "file.create", + "event_data": { + "task_id": "1", + "name": "test.png" + } +} +``` + +Screenshot created: + +```json +{ + "event_name": "file.create", + "event_data": { + "task_id": "2", + "name": "Screenshot taken May 19, 2015 at 10:56 AM" + } +} +``` + +Note: Webhooks configuration and payload have changed since Kanboard >= 1.0.15 + +How to create a task with a webhook? +------------------------------------ + +Firstly, you have to get the token from the settings page. After that, just call this url from anywhere: + +```bash +# Create a task for the default project inside the first column +curl "http://myserver/?controller=webhook&action=task&token=superSecretToken&title=mySuperTask" + +# Create a task to another project inside a specific column with the color red +curl "http://myserver/?controller=webhook&action=task&token=superSecretToken&title=task123&project_id=3&column_id=7&color_id=red" +``` + +### Available responses + +- When a task is created successfully, Kanboard return the message "OK" in plain text. +- However if the task creation fail, you will got a "FAILED" message. +- If the token is wrong, you got a "Not Authorized" message and a HTTP status code 401. + +### Available parameters + +Base URL: `http://YOUR_SERVER_HOSTNAME/?controller=webhook&action=task` + +- `token`: Token displayed on the settings page (required) +- `title`: Task title (required) +- `description`: Task description +- `color_id`: Supported colors are yellow, blue, green, purple, red, orange and grey +- `project_id`: Project id (Get the id from the project page) +- `owner_id`: Assignee (Get the user id from the users page) +- `column_id`: Column on the board (Get the column id from the projects page, mouse over on the column name) + +Only the token and the title parameters are mandatory. The different id can also be found in the database. diff --git a/doc/what-is-kanban.markdown b/doc/what-is-kanban.markdown new file mode 100644 index 00000000..3a37bb7a --- /dev/null +++ b/doc/what-is-kanban.markdown @@ -0,0 +1,32 @@ +What is Kanban? +=============== + +Kanban is a methodology originally developed by Toyota to be more efficient. + +There is only two constraints imposed by Kanban: + +- Visualize your workflow +- Limit your work in progress + +Visualize your workflow +----------------------- + +- Your work is displayed on a board, you have a clear overview of your project +- Each column represent a step in your workflow + +Bring focus and avoid multitasking +---------------------------------- + +- Each phase can have a work in progress limit +- Limits are great to identify bottlenecks +- Limits avoid working on too many tasks in the same time + +Measure performance and improvement +----------------------------------- + +Kanban uses lead and cycle times to measure performance: + +- **Lead time**: Time between the task is created and completed +- **Cycle time**: Time between the task is started and completed + +By example, you may have a lead time of 100 days and only have to work 1 hour to complete the task. diff --git a/doc/windows-apache-installation.markdown b/doc/windows-apache-installation.markdown new file mode 100644 index 00000000..25d39373 --- /dev/null +++ b/doc/windows-apache-installation.markdown @@ -0,0 +1,126 @@ +Installation on Windows Server and Apache +========================================= + +This guide will help you to setup step by step Kanboard on a Windows Server with Apache and PHP. + +Note: If you have a 64 bits platform choose "x64" otherwise choose "x86" for 32 bits systems. + +Visual C++ Redistributable Installation +--------------------------------------- + +PHP and Apache are compiled with Visual Studio so you need to install this library if it's not already done. + +1. Download the library from the [official Microsoft website](http://www.microsoft.com/en-us/download/details.aspx?id=30679) +2. Run the installer `vcredist_x64.exe` or `vcredist_x86.exe` according to your platform + +Apache installation +------------------- + +1. Download Apache binary from [Apache Lounge](http://www.apachelounge.com/download/) +2. Unzip the Apache24 folder to `C:\Apache24` + +### Define the server name + +Open the file `C:\Apache24\conf\httpd.conf` and add the directive: + +``` +ServerName localhost +``` + +### Install the Apache service + +Open a command prompt (`cmd.exe`) and go to the directory `C:\Apache24\bin`: + +```bash +cd C:\Apache24\bin + +# Install the windows service +httpd.exe -k install +``` + +### Install ApacheMonitor + +- Double click on `C:\Apache24\bin\ApacheMonitor.exe`, or put it in your startup folder. +- Right click on the icon and start Apache + +### Check the Apache installation + +Go to http://localhost/ you should see a blank page with the text "It works!". + +PHP installation +---------------- + +1. Download the last stable version of PHP from the [official PHP website](http://windows.php.net/download/), choose the **Thread Safe** version and use the exact same build type as Apache: x86 or x64 +2. Unzip the files to `C:\php` +3. Navigate to the PHP folder and rename the file `php.ini-production` to `php.ini` + +Edit the `php.ini`: + +Uncomment extension directory: + +```ini +extension_dir = "C:/php/ext" +``` + +Uncomment these PHP modules: + +```ini +extension=php_curl.dll +extension=php_gd2.dll +extension=php_ldap.dll +extension=php_mbstring.dll +extension=php_openssl.dll +extension=php_pdo_sqlite.dll +``` + +Set the timezone: + +```ini +date.timezone = America/Montreal +``` + +The list of supported timezones can be found in the [PHP documentation](http://php.net/manual/en/timezones.america.php). + +Load the PHP module for Apache: + +Add this configuration in the file `C:\Apache24\conf\httpd.conf`: + +``` +LoadModule php5_module "c:/php/php5apache2_4.dll" +AddHandler application/x-httpd-php .php + +# configure the path to php.ini +PHPIniDir "C:/php" + +# change this directive +DirectoryIndex index.php index.html +``` + +Restart Apache. + +Test your PHP installation: + +Create a file named `phpinfo.php` in the folder `C:\Apache24\htdocs`: + +```php + +``` + +Go to http://localhost/phpinfo.php and should see all information about your PHP installation. + +Kanboard installation +--------------------- + +- Download the zip file +- Uncompress the archive in `C:\Apache24\htdocs\kanboard` by example +- Open your web browser to use Kanboard http://localhost/kanboard/ +- The default credentials are **admin/admin** + +Tested configuration +-------------------- + +- Windows 2008 R2 / Apache 2.4.12 / PHP 5.6.8 diff --git a/doc/windows-iis-installation.markdown b/doc/windows-iis-installation.markdown new file mode 100644 index 00000000..84a2e53c --- /dev/null +++ b/doc/windows-iis-installation.markdown @@ -0,0 +1,68 @@ +Installation on Windows 2008/2012 with IIS +========================================== + +This guide will help you to setup step by step Kanboard on a Windows Server with IIS and PHP. + +PHP installation +---------------- + +- Install IIS on your server (Add a new role and don't forget to enable CGI/FastCGI) +- Install PHP by following the official documentation: + - [Microsoft IIS 5.1 and IIS 6.0](http://php.net/manual/en/install.windows.iis6.php) + - [Microsoft IIS 7.0 and later](http://php.net/manual/en/install.windows.iis7.php) + - [PHP for Windows is available here](http://windows.php.net/download/) + +Edit the `php.ini`, uncomment these PHP modules: + +```ini +extension=php_curl.dll +extension=php_gd2.dll +extension=php_ldap.dll +extension=php_mbstring.dll +extension=php_openssl.dll +extension=php_pdo_sqlite.dll +``` + +Set the timezone: + +```ini +date.timezone = America/Montreal +``` + +The list of supported timezones can be found in the [PHP documentation](http://php.net/manual/en/timezones.america.php). + +Check if PHP runs correctly: + +Go the IIS document root `C:\inetpub\wwwroot` and create a file `phpinfo.php`: + +```php + +``` + +Open a browser at `http://localhost/phpinfo.php` and you should see the current PHP settings. +If you got an error 500, something is not correctly done in your installation. + +Notes: + +- If you use PHP < 5.4, you have to enable the short tags in your php.ini +- Don't forget to enable the required php extensions mentioned above +- If you got an error about "the library MSVCP110.dll is missing", you probably need to download the Visual C++ Redistributable for Visual Studio from the Microsoft website. + +Kanboard installation +--------------------- + +- Download the zip file +- Uncompress the archive in `C:\inetpub\wwwroot\kanboard` by example +- Make sure the directory `data` is writable by the IIS user +- Open your web browser to use Kanboard http://localhost/kanboard/ +- The default credentials are **admin/admin** + +Tested configurations +--------------------- + +- Windows 2008 R2 Standard Edition / IIS 7.5 / PHP 5.5.16 +- Windows 2012 Standard Edition / IIS 8.5 / PHP 5.3.29 diff --git a/docs/.htaccess b/docs/.htaccess deleted file mode 100644 index 14249c50..00000000 --- a/docs/.htaccess +++ /dev/null @@ -1 +0,0 @@ -Deny from all \ No newline at end of file diff --git a/docs/2fa.markdown b/docs/2fa.markdown deleted file mode 100644 index 627c636a..00000000 --- a/docs/2fa.markdown +++ /dev/null @@ -1,33 +0,0 @@ -Two factor authentication -========================= - -Each user can enable the [two factor authentication](http://en.wikipedia.org/wiki/Two_factor_authentication). -After a successful login, a one-time code (6 characters) is asked to the user to allow the access to Kanboard. - -This code have to be provided by a compatible software generally installed on your smartphone. - -Kanboard use the [Time-based One-time Password Algorithm](http://en.wikipedia.org/wiki/Time-based_One-time_Password_Algorithm) defined in the [RFC 6238](http://tools.ietf.org/html/rfc6238). - -There are many software compatible with the standard TOTP system. -By example, you can use these free and open source applications: - -- [Google Authenticator](https://github.com/google/google-authenticator/) (Android, iOS, Blackberry) -- [FreeOTP](https://fedorahosted.org/freeotp/) (Android, iOS) -- [OATH Toolkit](http://www.nongnu.org/oath-toolkit/) (Command line utility on Unix/Linux) - -This system can work offline and you don't necessary need to have a mobile phone. - -Setup ------ - -1. Go to your user profile -2. On the left, click on **Two factor authentication** and check the box -3. A secret key is generated for you - -![2FA](http://kanboard.net/screenshots/documentation/2fa.png) - -- You have to save the secret key in your TOTP software. If you use a smartphone, the easiest solution is to scan the QR code with FreeOTP or Google Authenticator. -- Each time you will open a new session, a new code will be asked -- Don't forget to test your device before closing your session - -A new secret key is generated each time you enable/disable this feature. \ No newline at end of file diff --git a/docs/analytics-tasks.markdown b/docs/analytics-tasks.markdown deleted file mode 100644 index c5acea5f..00000000 --- a/docs/analytics-tasks.markdown +++ /dev/null @@ -1,24 +0,0 @@ -Analytics for tasks -=================== - -Each task have an analytics section available from the left menu in the task view. - -Lead and cycle time -------------------- - -![Lead and cycle time](http://kanboard.net/screenshots/documentation/task-lead-cycle-time.png) - -- The lead time is the time between the task creation and the date of completion (task closed). -- The cycle time is the time between the start date and the date of completion. -- If the task is not closed the current time is used instead of the date of completion. -- If the start date is not specified, the cycle time is not calculated. - -Note: You can configure an automatic action to define automatically the start date when you move a task to the column of your choice. - -Time spent into each column ---------------------------- - -![Time spent into each column](http://kanboard.net/screenshots/documentation/time-into-each-column.png) - -- This chart show the total time spent into each column for the task. -- The time spent is calculated until the task is closed. diff --git a/docs/analytics.markdown b/docs/analytics.markdown deleted file mode 100644 index 4ae9572f..00000000 --- a/docs/analytics.markdown +++ /dev/null @@ -1,70 +0,0 @@ -Analytics -========= - -Each project have an analytics section. Depending how you are using Kanboard, you can see those reports: - -User repartition ----------------- - -![User repartition](http://kanboard.net/screenshots/documentation/user-repartition.png) - -This pie chart show the number of open tasks assigned per user. - -Task distribution ------------------ - -![Task distribution](http://kanboard.net/screenshots/documentation/task-distribution.png) - -This pie chart gives an overview of the number of open tasks per column. - -Cumulative flow diagram ------------------------ - -![Cumulative flow diagram](http://kanboard.net/screenshots/documentation/cfd.png) - -- This chart show the number of tasks cumulatively for each column over the time. -- Everyday, the total number of tasks is recorded for each column. -- If you would like to exclude closed tasks, change the [global project settings](project-configuration.markdown). - -Note: You need to have at least 2 days of data to see the graph. - -Burndown chart --------------- - -![Burndown chart](http://kanboard.net/screenshots/documentation/burndown-chart.png) - -The [burn down chart](http://en.wikipedia.org/wiki/Burn_down_chart) is available for each project. - -- This chart is a graphical representation of work left to do versus time. -- Kanboard use the complexity or story point to generate this diagram. -- Everyday, the sum of the story points for each column is calculated. - -Average time spent into each column ------------------------------------ - -![Average time spent into each column](http://kanboard.net/screenshots/documentation/average-time-spent-into-each-column.png) - -This chart show the average time spent into each column for the last 1000 tasks. - -- Kanboard use the task transitions to calculate the data. -- The time spent is calculated until the task is closed. - -Average Lead and Cycle time ---------------------------- - -![Average time spent into each column](http://kanboard.net/screenshots/documentation/average-lead-cycle-time.png) - -This chart show the average lead and cycle time for the last 1000 tasks over the time. - -- The lead time is the time between the task creation and the date of completion. -- The cycle time is time between the specified start date of the task to completion date. -- If the task is not closed, the current time is used instead of the date of completion. - -Those metrics are calculated and recorded everyday for the whole project. - -Don't forget to run the daily job for stats calculation -------------------------------------------------------- - -To generate accurate analytics data, you should run the daily cronjob **project daily statistics**. - -[Read the documentation about Kanboard CLI](cli.markdown) diff --git a/docs/api-json-rpc.markdown b/docs/api-json-rpc.markdown deleted file mode 100644 index 61852933..00000000 --- a/docs/api-json-rpc.markdown +++ /dev/null @@ -1,4366 +0,0 @@ -Json-RPC API -============ - -User and application API ------------------------- - -There are two types of API access: - -### Application API - -- Access to the API with the user "jsonrpc" and the token available in settings -- Access to all procedures -- No permission checked -- There is no user session on the server -- Example of possible clients: tools to migrate/import data, create tasks from another system, etc... - -### User API - -- Access to the API with the user credentials (username and password) -- Access to a restricted set of procedures -- The project permissions are checked -- A user session is created on the server -- Example of possible clients: mobile/desktop application, command line utility, etc... - -Security --------- - -- Always use HTTPS with a valid certificate -- If you make a mobile application, it's your job to store securely the user credentials on the device -- After 3 authentication failure on the user api, the end-user have to unlock his account by using the login form -- Two factor authentication is not yet available through the API - -Protocol --------- - -Kanboard use the protocol Json-RPC to interact with external programs. - -JSON-RPC is a remote procedure call protocol encoded in JSON. -Almost the same thing as XML-RPC but with the JSON format. - -We use the [version 2 of the protocol](http://www.jsonrpc.org/specification). -You must call the API with a `POST` HTTP request. - -Kanboard support batch requests, so you can make multiple API calls in a single HTTP request. It's particularly useful for mobile clients with higher network latency. - -Authentication --------------- - -### Default method (HTTP Basic) - -The API credentials are available on the settings page. - -- API end-point: `https://YOUR_SERVER/jsonrpc.php` - -If you want to use the "application api": - -- Username: `jsonrpc` -- Password: API token on the settings page - -Otherwise for the "user api", just use the real username/passsword. - -The API use the [HTTP Basic Authentication Scheme described in the RFC2617](http://www.ietf.org/rfc/rfc2617.txt). -If there is an authentication error, you will receive the HTTP status code `401 Not Authorized`. - -### Authorized User API procedures - -- getMe -- getMyDashboard -- getMyActivityStream -- createMyPrivateProject -- getMyProjectsList -- getTimezone -- getVersion -- getDefaultTaskColor -- getDefaultTaskColors -- getColorList -- getProjectById -- getTask -- getTaskByReference -- getAllTasks -- openTask -- closeTask -- moveTaskPosition -- createTask -- updateTask -- getBoard - -### Custom HTTP header - -You can use an alternative HTTP header for the authentication if your server have a very specific configuration. - -- The header name can be anything you want, by example `X-API-Auth`. -- The header value is the `username:password` encoded in Base64. - -Configuration: - -1. Define your custom header in your `config.php`: `define('API_AUTHENTICATION_HEADER', 'X-API-Auth');` -2. Encode the credentials in Base64, example with PHP `base64_encode('jsonrpc:19ffd9709d03ce50675c3a43d1c49c1ac207f4bc45f06c5b2701fbdf8929');` -3. Test with curl: - -```bash -curl \ --H 'X-API-Auth: anNvbnJwYzoxOWZmZDk3MDlkMDNjZTUwNjc1YzNhNDNkMWM0OWMxYWMyMDdmNGJjNDVmMDZjNWIyNzAxZmJkZjg5Mjk=' \ --d '{"jsonrpc": "2.0", "method": "getAllProjects", "id": 1}' \ -http://localhost/kanboard/jsonrpc.php -``` - -Examples --------- - -### Example with cURL - -From the command line: - -```bash -curl \ --u "jsonrpc:19ffd9709d03ce50675c3a43d1c49c1ac207f4bc45f06c5b2701fbdf8929" \ --d '{"jsonrpc": "2.0", "method": "getAllProjects", "id": 1}' \ -http://localhost/kanboard/jsonrpc.php -``` - -Response from the server: - -```json -{ - "jsonrpc":"2.0", - "id":1, - "result":[ - { - "id":"1", - "name":"API test", - "is_active":"1", - "token":"6bd0932fe7f4b5e6e4bc3c72800bfdef36a2c5de2f38f756dfb5bd632ebf", - "last_modified":"1403392631" - } - ] -} -``` - -### Example with Python - -Here a basic example written in Python to create a task: - -```python -#!/usr/bin/env python - -import requests -import json - -def main(): - url = "http://demo.kanboard.net/jsonrpc.php" - api_key = "be4271664ca8169d32af49d8e1ec854edb0290bc3588a2e356275eab9505" - headers = {"content-type": "application/json"} - - payload = { - "method": "createTask", - "params": { - "title": "Python API test", - "project_id": 1 - }, - "jsonrpc": "2.0", - "id": 1, - } - - response = requests.post( - url, - data=json.dumps(payload), - headers=headers, - auth=("jsonrpc", api_key) - ) - - if response.status_code == 401: - print "Authentication failed" - else: - result = response.json() - - assert result["result"] == True - assert result["jsonrpc"] - assert result["id"] == 1 - - print "Task created successfully!" - -if __name__ == "__main__": - main() -``` - -Run this script from your terminal: - -```bash -python jsonrpc.py -Task created successfully! -``` - -### Example with a PHP client: - -I wrote a simple [Json-RPC Client/Server library in PHP](https://github.com/fguillot/JsonRPC), here an example: - -```php -authentication('jsonrpc', '19ffd9709d03ce50675c3a43d1c49c1ac207f4bc45f06c5b2701fbdf8929'); - -print_r($client->getAllProjects()); - -``` - -The response: - -``` -Array -( - [0] => Array - ( - [id] => 1 - [name] => API test - [is_active] => 1 - [token] => 6bd0932fe7f4b5e6e4bc3c72800bfdef36a2c5de2f38f756dfb5bd632ebf - [last_modified] => 1403392631 - ) - -) -``` - -### Example with Ruby - -This example can be used with Kanboard configured with Reverse-Proxy authentication and the API configured with a custom authentication header: - -```ruby -require 'faraday' - -conn = Faraday.new(:url => 'https://kanboard.example.com') do |faraday| - faraday.response :logger - faraday.headers['X-API-Auth'] = 'XXX' # base64_encode('jsonrpc:API_KEY') - faraday.basic_auth(ENV['user'], ENV['pw']) # user/pass to get through basic auth - faraday.adapter Faraday.default_adapter # make requests with Net::HTTP -end - -response = conn.post do |req| - req.url '/jsonrpc.php' - req.headers['Content-Type'] = 'application/json' - req.body = '{ "jsonrpc": "2.0", "id": 1, "method": "getAllProjects" }' -end - -puts response.body -``` - -Procedures ----------- - -### getVersion - -- Purpose: **Get the application version** -- Parameters: none -- Result: **version** (Example: 1.0.12, master) - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "getVersion", - "id": 1661138292 -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 1661138292, - "result": "1.0.13" -} -``` - -### getTimezone - -- Purpose: **Get the application timezone** -- Parameters: none -- Result on success: **Timezone** (Example: UTC, Europe/Paris) -- Result on failure: **Default timezone** (UTC) - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "getTimezone", - "id": 1661138292 -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 1661138292, - "result": "Europe\/Paris" -} -``` - -### getDefaultTaskColors - -- Purpose: **Get all default task colors** -- Parameters: None -- Result on success: **Color properties** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "getDefaultTaskColors", - "id": 2108929212 -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 2108929212, - "result": { - "yellow": { - "name": "Yellow", - "background": "rgb(245, 247, 196)", - "border": "rgb(223, 227, 45)" - }, - "blue": { - "name": "Blue", - "background": "rgb(219, 235, 255)", - "border": "rgb(168, 207, 255)" - }, - "green": { - "name": "Green", - "background": "rgb(189, 244, 203)", - "border": "rgb(74, 227, 113)" - }, - "purple": { - "name": "Purple", - "background": "rgb(223, 176, 255)", - "border": "rgb(205, 133, 254)" - }, - "red": { - "name": "Red", - "background": "rgb(255, 187, 187)", - "border": "rgb(255, 151, 151)" - }, - "orange": { - "name": "Orange", - "background": "rgb(255, 215, 179)", - "border": "rgb(255, 172, 98)" - }, - "grey": { - "name": "Grey", - "background": "rgb(238, 238, 238)", - "border": "rgb(204, 204, 204)" - }, - "brown": { - "name": "Brown", - "background": "#d7ccc8", - "border": "#4e342e" - }, - "deep_orange": { - "name": "Deep Orange", - "background": "#ffab91", - "border": "#e64a19" - }, - "dark_grey": { - "name": "Dark Grey", - "background": "#cfd8dc", - "border": "#455a64" - }, - "pink": { - "name": "Pink", - "background": "#f48fb1", - "border": "#d81b60" - }, - "teal": { - "name": "Teal", - "background": "#80cbc4", - "border": "#00695c" - }, - "cyan": { - "name": "Cyan", - "background": "#b2ebf2", - "border": "#00bcd4" - }, - "lime": { - "name": "Lime", - "background": "#e6ee9c", - "border": "#afb42b" - }, - "light_green": { - "name": "Light Green", - "background": "#dcedc8", - "border": "#689f38" - }, - "amber": { - "name": "Amber", - "background": "#ffe082", - "border": "#ffa000" - } - } -} -``` - -### getDefaultTaskColor - -- Purpose: **Get default task color** -- Parameters: None -- Result on success: **color_id** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "getDefaultTaskColor", - "id": 1144775215 -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 1144775215, - "result": "yellow" -} -``` - -### getColorList - -- Purpose: **Get the list of task colors** -- Parameters: none -- Result on success: **Dictionary of color_id => color_name** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "getColorList", - "id": 1677051386 -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 1677051386, - "result": { - "yellow": "Yellow", - "blue": "Blue", - "green": "Green", - "purple": "Purple", - "red": "Red", - "orange": "Orange", - "grey": "Grey", - "brown": "Brown", - "deep_orange": "Deep Orange", - "dark_grey": "Dark Grey", - "pink": "Pink", - "teal": "Teal", - "cyan": "Cyan", - "lime": "Lime", - "light_green": "Light Green", - "amber": "Amber" - } -} -``` - -### createProject - -- Purpose: **Create a new project** -- Parameters: - - **name** (string, required) - - **description** (string, optional) -- Result on success: **project_id** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "createProject", - "id": 1797076613, - "params": { - "name": "PHP client" - } -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 1797076613, - "result": 2 -} -``` - -### getProjectById - -- Purpose: **Get project information** -- Parameters: - - **project_id** (integer, required) -- Result on success: **project properties** -- Result on failure: **null** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "getProjectById", - "id": 226760253, - "params": { - "project_id": 1 - } -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 226760253, - "result": { - "id": "1", - "name": "API test", - "is_active": "1", - "token": "", - "last_modified": "1436119135", - "is_public": "0", - "is_private": "0", - "is_everybody_allowed": "0", - "default_swimlane": "Default swimlane", - "show_default_swimlane": "1", - "description": "test", - "identifier": "", - "url": { - "board": "http:\/\/127.0.0.1:8000\/?controller=board&action=show&project_id=1", - "calendar": "http:\/\/127.0.0.1:8000\/?controller=calendar&action=show&project_id=1", - "list": "http:\/\/127.0.0.1:8000\/?controller=listing&action=show&project_id=1" - } - } -} -``` - -### getProjectByName - -- Purpose: **Get project information** -- Parameters: - - **name** (string, required) -- Result on success: **project properties** -- Result on failure: **null** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "getProjectByName", - "id": 1620253806, - "params": { - "name": "Test" - } -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 1620253806, - "result": { - "id": "1", - "name": "Test", - "is_active": "1", - "token": "", - "last_modified": "1436119135", - "is_public": "0", - "is_private": "0", - "is_everybody_allowed": "0", - "default_swimlane": "Default swimlane", - "show_default_swimlane": "1", - "description": "test", - "identifier": "", - "url": { - "board": "http:\/\/127.0.0.1:8000\/?controller=board&action=show&project_id=1", - "calendar": "http:\/\/127.0.0.1:8000\/?controller=calendar&action=show&project_id=1", - "list": "http:\/\/127.0.0.1:8000\/?controller=listing&action=show&project_id=1" - } - } -} -``` - -### getAllProjects - -- Purpose: **Get all available projects** -- Parameters: - - **none** -- Result on success: **List of projects** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "getAllProjects", - "id": 2134420212 -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 2134420212, - "result": [ - { - "id": "1", - "name": "API test", - "is_active": "1", - "token": "", - "last_modified": "1436119570", - "is_public": "0", - "is_private": "0", - "is_everybody_allowed": "0", - "default_swimlane": "Default swimlane", - "show_default_swimlane": "1", - "description": null, - "identifier": "", - "url": { - "board": "http:\/\/127.0.0.1:8000\/?controller=board&action=show&project_id=1", - "calendar": "http:\/\/127.0.0.1:8000\/?controller=calendar&action=show&project_id=1", - "list": "http:\/\/127.0.0.1:8000\/?controller=listing&action=show&project_id=1" - } - } - ] -} -``` - -### updateProject - -- Purpose: **Update a project** -- Parameters: - - **id** (integer, required) - - **name** (string, required) - - **description** (string, optional) -- Result on success: **true** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "updateProject", - "id": 1853996288, - "params": { - "id": 1, - "name": "PHP client update" - } -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 1853996288, - "result": true -} -``` - -### removeProject - -- Purpose: **Remove a project** -- Parameters: - **project_id** (integer, required) -- Result on success: **true** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "removeProject", - "id": 46285125, - "params": { - "project_id": "2" - } -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 46285125, - "result": true -} -``` - -### enableProject - -- Purpose: **Enable a project** -- Parameters: - - **project_id** (integer, required) -- Result on success: **true** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "enableProject", - "id": 1775494839, - "params": [ - "1" - ] -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 1775494839, - "result": true -} -``` - -### disableProject - -- Purpose: **Disable a project** -- Parameters: - - **project_id** (integer, required) -- Result on success: **true** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "disableProject", - "id": 1734202312, - "params": [ - "1" - ] -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 1734202312, - "result": true -} -``` - -### enableProjectPublicAccess - -- Purpose: **Enable public access for a given project** -- Parameters: - - **project_id** (integer, required) -- Result on success: **true** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "enableProjectPublicAccess", - "id": 103792571, - "params": [ - "1" - ] -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 103792571, - "result": true -} -``` - -### disableProjectPublicAccess - -- Purpose: **Disable public access for a given project** -- Parameters: - - **project_id** (integer, required) -- Result on success: **true** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "disableProjectPublicAccess", - "id": 942472945, - "params": [ - "1" - ] -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 942472945, - "result": true -} -``` - -### getProjectActivity - -- Purpose: **Get activity stream for a project** -- Parameters: - - **project_id** (integer, required) -- Result on success: **List of events** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "getProjectActivity", - "id": 942472945, - "params": [ - "project_id": 1 - ] -} -``` - -### getProjectActivities - -- Purpose: **Get Activityfeed for Project(s)** -- Parameters: - - **project_ids** (integer array, required) -- Result on success: **List of events** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "getProjectActivities", - "id": 942472945, - "params": [ - "project_ids": [1,2] - ] -} -``` - -### getMembers - -- Purpose: **Get members of a project** -- Parameters: - - **project_id** (integer, required) -- Result on success: Key/value pair of user_id and username -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "getMembers", - "id": 1944388643, - "params": [ - 1 - ] -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 1944388643, - "result": { - "1": "user1", - "2": "user2", - "3": "user3" - } -} -``` - -### revokeUser - -- Purpose: **Revoke user access for a given project** -- Parameters: - - **project_id** (integer, required) - - **user_id** (integer, required) -- Result on success: **true** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "revokeUser", - "id": 251218350, - "params": [ - 1, - 2 - ] -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 251218350, - "result": true -} -``` - -### allowUser - -- Purpose: **Grant user access for a given project** -- Parameters: - - **project_id** (integer, required) - - **user_id** (integer, required) -- Result on success: **true** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "allowUser", - "id": 2111451404, - "params": [ - 1, - 2 - ] -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 2111451404, - "result": true -} -``` - - -### getBoard - -- Purpose: **Get all necessary information to display a board** -- Parameters: - - **project_id** (integer, required) -- Result on success: **board properties** -- Result on failure: **empty list** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "getBoard", - "id": 827046470, - "params": [ - 1 - ] -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 827046470, - "result": [ - { - "id": 0, - "name": "Default swimlane", - "columns": [ - { - "id": "1", - "title": "Backlog", - "position": "1", - "project_id": "1", - "task_limit": "0", - "description": "", - "tasks": [], - "nb_tasks": 0, - "score": 0 - }, - { - "id": "2", - "title": "Ready", - "position": "2", - "project_id": "1", - "task_limit": "0", - "description": "", - "tasks": [ - { - "nb_comments":"0", - "nb_files":"0", - "nb_subtasks":"0", - "nb_completed_subtasks":"0", - "nb_links":"0", - "id":"2", - "reference":"", - "title":"Test", - "description":"", - "date_creation":"1430870507", - "date_modification":"1430870507", - "date_completed":null, - "date_due":"0", - "color_id":"yellow", - "project_id":"1", - "column_id":"2", - "swimlane_id":"0", - "owner_id":"0", - "creator_id":"1", - "position":"1", - "is_active":"1", - "score":"0", - "category_id":"0", - "date_moved":"1430870507", - "recurrence_status":"0", - "recurrence_trigger":"0", - "recurrence_factor":"0", - "recurrence_timeframe":"0", - "recurrence_basedate":"0", - "recurrence_parent":null, - "recurrence_child":null, - "assignee_username":null, - "assignee_name":null - } - ], - "nb_tasks": 1, - "score": 0 - }, - { - "id": "3", - "title": "Work in progress", - "position": "3", - "project_id": "1", - "task_limit": "0", - "description": "", - "tasks": [ - { - "nb_comments":"0", - "nb_files":"0", - "nb_subtasks":"1", - "nb_completed_subtasks":"0", - "nb_links":"0", - "id":"1", - "reference":"", - "title":"Task with comment", - "description":"", - "date_creation":"1430783188", - "date_modification":"1430783188", - "date_completed":null, - "date_due":"0", - "color_id":"red", - "project_id":"1", - "column_id":"3", - "swimlane_id":"0", - "owner_id":"1", - "creator_id":"0", - "position":"1", - "is_active":"1", - "score":"0", - "category_id":"0", - "date_moved":"1430783191", - "recurrence_status":"0", - "recurrence_trigger":"0", - "recurrence_factor":"0", - "recurrence_timeframe":"0", - "recurrence_basedate":"0", - "recurrence_parent":null, - "recurrence_child":null, - "assignee_username":"admin", - "assignee_name":null - } - ], - "nb_tasks": 1, - "score": 0 - }, - { - "id": "4", - "title": "Done", - "position": "4", - "project_id": "1", - "task_limit": "0", - "description": "", - "tasks": [], - "nb_tasks": 0, - "score": 0 - } - ], - "nb_columns": 4, - "nb_tasks": 2 - } - ] -} -``` - -### getColumns - -- Purpose: **Get all columns information for a given project** -- Parameters: - - **project_id** (integer, required) -- Result on success: **columns properties** -- Result on failure: **empty list** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "getColumns", - "id": 887036325, - "params": [ - 1 - ] -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 887036325, - "result": [ - { - "id": "1", - "title": "Backlog", - "position": "1", - "project_id": "1", - "task_limit": "0" - }, - { - "id": "2", - "title": "Ready", - "position": "2", - "project_id": "1", - "task_limit": "0" - }, - { - "id": "3", - "title": "Work in progress", - "position": "3", - "project_id": "1", - "task_limit": "0" - } - ] -} -``` - -### getColumn - -- Purpose: **Get a single column** -- Parameters: - - **column_id** (integer, required) -- Result on success: **column properties** -- Result on failure: **null** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "getColumn", - "id": 1242049935, - "params": [ - 2 - ] -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 1242049935, - "result": { - "id": "2", - "title": "Youpi", - "position": "2", - "project_id": "1", - "task_limit": "5" - } -} -``` - -### moveColumnUp - -- Purpose: **Move up the column position** -- Parameters: - - **project_id** (integer, required) - - **column_id** (integer, required) -- Result on success: **true** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "moveColumnUp", - "id": 99275573, - "params": [ - 1, - 2 - ] -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 99275573, - "result": true -} -``` - -### moveColumnDown - -- Purpose: **Move down the column position** -- Parameters: - - **project_id** (integer, required) - - **column_id** (integer, required) -- Result on success: **true** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "moveColumnDown", - "id": 957090649, - "params": { - "project_id": 1, - "column_id": 2 - } -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 957090649, - "result": true -} -``` - -### updateColumn - -- Purpose: **Update column properties** -- Parameters: - - **column_id** (integer, required) - - **title** (string, required) - - **task_limit** (integer, optional) - - **description** (string, optional) -- Result on success: **true** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "updateColumn", - "id": 480740641, - "params": [ - 2, - "Boo", - 5 - ] -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 480740641, - "result": true -} -``` - -### addColumn - -- Purpose: **Add a new column** -- Parameters: - - **project_id** (integer, required) - - **title** (string, required) - - **task_limit** (integer, optional) - - **description** (string, optional) -- Result on success: **column_id** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "addColumn", - "id": 638544704, - "params": [ - 1, - "Boo" - ] -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 638544704, - "result": 5 -} -``` - -### removeColumn - -- Purpose: **Remove a column** -- Parameters: - - **column_id** (integer, required) -- Result on success: **true** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "removeColumn", - "id": 1433237746, - "params": [ - 1 - ] -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 1433237746, - "result": true -} -``` - -### getDefaultSwimlane - -- Purpose: **Get the default swimlane for a project** -- Parameters: - - **project_id** (integer, required) -- Result on success: **true** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "getDefaultSwimlane", - "id": 898774713, - "params": [ - 1 - ] -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 898774713, - "result": { - "id": "1", - "default_swimlane": "Default swimlane", - "show_default_swimlane": "1" - } -} -``` - -### getActiveSwimlanes - -- Purpose: **Get the list of enabled swimlanes of a project (include default swimlane if enabled)** -- Parameters: - - **project_id** (integer, required) -- Result on success: **List of swimlanes** -- Result on failure: **null** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "getActiveSwimlanes", - "id": 934789422, - "params": [ - 1 - ] -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 934789422, - "result": [ - { - "id": 0, - "name": "Default swimlane" - }, - { - "id": "2", - "name": "Swimlane A" - } - ] -} -``` - -### getAllSwimlanes - -- Purpose: **Get the list of all swimlanes of a project (enabled or disabled) and sorted by position** -- Parameters: - - **project_id** (integer, required) -- Result on success: **List of swimlanes** -- Result on failure: **null** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "getAllSwimlanes", - "id": 509791576, - "params": [ - 1 - ] -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 509791576, - "result": [ - { - "id": "1", - "name": "Another swimlane", - "position": "1", - "is_active": "1", - "project_id": "1" - }, - { - "id": "2", - "name": "Swimlane A", - "position": "2", - "is_active": "1", - "project_id": "1" - } - ] -} -``` - -### getSwimlane - -- Purpose: **Get the a swimlane by id** -- Parameters: - - **swimlane_id** (integer, required) -- Result on success: **swimlane properties** -- Result on failure: **null** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "getSwimlane", - "id": 131071870, - "params": [ - 1 - ] -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 131071870, - "result": { - "id": "1", - "name": "Swimlane 1", - "position": "1", - "is_active": "1", - "project_id": "1" - } -} -``` - -### getSwimlaneById - -- Purpose: **Get the a swimlane by id** -- Parameters: - - **swimlane_id** (integer, required) -- Result on success: **swimlane properties** -- Result on failure: **null** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "getSwimlaneById", - "id": 131071870, - "params": [ - 1 - ] -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 131071870, - "result": { - "id": "1", - "name": "Swimlane 1", - "position": "1", - "is_active": "1", - "project_id": "1" - } -} -``` - -### getSwimlaneByName - -- Purpose: **Get the a swimlane by name** -- Parameters: - - **project_id** (integer, required) - - **name** (string, required) -- Result on success: **swimlane properties** -- Result on failure: **null** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "getSwimlaneByName", - "id": 824623567, - "params": [ - 1, - "Swimlane 1" - ] -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 824623567, - "result": { - "id": "1", - "name": "Swimlane 1", - "position": "1", - "is_active": "1", - "project_id": "1" - } -} -``` - -### moveSwimlaneUp - -- Purpose: **Move up the swimlane position** -- Parameters: - - **project_id** (integer, required) - - **swimlane_id** (integer, required) -- Result on success: **true** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "moveSwimlaneUp", - "id": 99275573, - "params": [ - 1, - 2 - ] -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 99275573, - "result": true -} -``` - -### moveSwimlaneDown - -- Purpose: **Move down the swimlane position** -- Parameters: - - **project_id** (integer, required) - - **swimlane_id** (integer, required) -- Result on success: **true** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "moveSwimlaneDown", - "id": 957090649, - "params": { - "project_id": 1, - "swimlane_id": 2 - } -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 957090649, - "result": true -} -``` - -### updateSwimlane - -- Purpose: **Update swimlane properties** -- Parameters: - - **swimlane_id** (integer, required) - - **name** (string, required) -- Result on success: **true** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "updateSwimlane", - "id": 87102426, - "params": [ - "1", - "Another swimlane" - ] -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 87102426, - "result": true -} -``` - -### addSwimlane - -- Purpose: **Add a new swimlane** -- Parameters: - - **project_id** (integer, required) - - **name** (string, required) -- Result on success: **swimlane_id** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "addSwimlane", - "id": 849940086, - "params": [ - 1, - "Swimlane 1" - ] -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 849940086, - "result": 1 -} -``` - -### removeSwimlane - -- Purpose: **Remove a swimlane** -- Parameters: - - **project_id** (integer, required) - - **swimlane_id** (integer, required) -- Result on success: **true** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "removeSwimlane", - "id": 1433237746, - "params": [ - 2, - 1 - ] -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 1433237746, - "result": true -} -``` - -### disableSwimlane - -- Purpose: **Enable a swimlane** -- Parameters: - - **project_id** (integer, required) - - **swimlane_id** (integer, required) -- Result on success: **true** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "disableSwimlane", - "id": 1433237746, - "params": [ - 2, - 1 - ] -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 1433237746, - "result": true -} -``` - -### enableSwimlane - -- Purpose: **Enable a swimlane** -- Parameters: - - **project_id** (integer, required) - - **swimlane_id** (integer, required) -- Result on success: **true** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "enableSwimlane", - "id": 1433237746, - "params": [ - 2, - 1 - ] -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 1433237746, - "result": true -} -``` - -### getAvailableActions - -- Purpose: **Get list of available automatic actions** -- Parameters: none -- Result on success: **list of actions** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "getAvailableActions", - "id": 1217735483 -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 1217735483, - "result": { - "TaskLogMoveAnotherColumn": "Add a comment logging moving the task between columns", - "TaskAssignColorUser": "Assign a color to a specific user", - "TaskAssignColorColumn": "Assign a color when the task is moved to a specific column", - "TaskAssignCategoryColor": "Assign automatically a category based on a color", - "TaskAssignColorCategory": "Assign automatically a color based on a category", - "TaskAssignSpecificUser": "Assign the task to a specific user", - "TaskAssignCurrentUser": "Assign the task to the person who does the action", - "TaskUpdateStartDate": "Automatically update the start date", - "TaskAssignUser": "Change the assignee based on an external username", - "TaskAssignCategoryLabel": "Change the category based on an external label", - "TaskClose": "Close a task", - "CommentCreation": "Create a comment from an external provider", - "TaskCreation": "Create a task from an external provider", - "TaskDuplicateAnotherProject": "Duplicate the task to another project", - "TaskMoveColumnAssigned": "Move the task to another column when assigned to a user", - "TaskMoveColumnUnAssigned": "Move the task to another column when assignee is cleared", - "TaskMoveAnotherProject": "Move the task to another project", - "TaskOpen": "Open a task" - } -} -``` - -### getAvailableActionEvents - -- Purpose: **Get list of available events for actions** -- Parameters: none -- Result on success: **list of events** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "getAvailableActionEvents", - "id": 2116665643 -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 2116665643, - "result": { - "bitbucket.webhook.commit": "Bitbucket commit received", - "task.close": "Closing a task", - "github.webhook.commit": "Github commit received", - "github.webhook.issue.assignee": "Github issue assignee change", - "github.webhook.issue.closed": "Github issue closed", - "github.webhook.issue.commented": "Github issue comment created", - "github.webhook.issue.label": "Github issue label change", - "github.webhook.issue.opened": "Github issue opened", - "github.webhook.issue.reopened": "Github issue reopened", - "gitlab.webhook.commit": "Gitlab commit received", - "gitlab.webhook.issue.closed": "Gitlab issue closed", - "gitlab.webhook.issue.opened": "Gitlab issue opened", - "task.move.column": "Move a task to another column", - "task.open": "Open a closed task", - "task.assignee_change": "Task assignee change", - "task.create": "Task creation", - "task.create_update": "Task creation or modification", - "task.update": "Task modification" - } -} -``` - -### getCompatibleActionEvents - -- Purpose: **Get list of events compatible with an action** -- Parameters: - - **action_name** (string, required) -- Result on success: **list of events** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "getCompatibleActionEvents", - "id": 899370297, - "params": [ - "TaskClose" - ] -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 899370297, - "result": { - "bitbucket.webhook.commit": "Bitbucket commit received", - "github.webhook.commit": "Github commit received", - "github.webhook.issue.closed": "Github issue closed", - "gitlab.webhook.commit": "Gitlab commit received", - "gitlab.webhook.issue.closed": "Gitlab issue closed", - "task.move.column": "Move a task to another column" - } -} -``` - -### getActions - -- Purpose: **Get list of actions for a project** -- Parameters: - - **project_id** (integer, required) -- Result on success: **list of actions properties** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "getActions", - "id": 1433237746, - "params": [ - "1" - ] -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 1433237746, - "result": [ - { - "id" : "13", - "project_id" : "2", - "event_name" : "task.move.column", - "action_name" : "TaskAssignSpecificUser", - "params" : { - "column_id" : "5", - "user_id" : "1" - } - } - ] -} -``` - -### createAction - -- Purpose: **Create an action** -- Parameters: - - **project_id** (integer, required) - - **event_name** (string, required) - - **action_name** (string, required) - - **params** (key/value parameters, required) -- Result on success: **action_id** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "createAction", - "id": 1433237746, - "params": { - "project_id" : "2", - "event_name" : "task.move.column", - "action_name" : "TaskAssignSpecificUser", - "params" : { - "column_id" : "3", - "user_id" : "2" - } - } -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 1433237746, - "result": 14 -} -``` - -### removeAction - -- Purpose: **Remove an action** -- Parameters: - - **action_id** (integer, required) -- Result on success: **true** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "removeAction", - "id": 1510741671, - "params": [ - 1 - ] -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 1510741671, - "result": true -} -``` - -### createTask - -- Purpose: **Create a new task** -- Parameters: - - **title** (string, required) - - **project_id** (integer, required) - - **color_id** (string, optional) - - **column_id** (integer, optional) - - **owner_id** (integer, optional) - - **creator_id** (integer, optional) - - **date_due**: ISO8601 format (string, optional) - - **description** Markdown content (string, optional) - - **category_id** (integer, optional) - - **score** (integer, optional) - - **swimlane_id** (integer, optional) - - **recurrence_status** (integer, optional) - - **recurrence_trigger** (integer, optional) - - **recurrence_factor** (integer, optional) - - **recurrence_timeframe** (integer, optional) - - **recurrence_basedate** (integer, optional) -- Result on success: **task_id** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "createTask", - "id": 1176509098, - "params": { - "owner_id": 1, - "creator_id": 0, - "date_due": "", - "description": "", - "category_id": 0, - "score": 0, - "title": "Test", - "project_id": 1, - "color_id": "green", - "column_id": 2, - "recurrence_status": 0, - "recurrence_trigger": 0, - "recurrence_factor": 0, - "recurrence_timeframe": 0, - "recurrence_basedate": 0 - } -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 1176509098, - "result": 3 -} -``` - -### getTask - -- Purpose: **Get task by the unique id** -- Parameters: - - **task_id** (integer, required) -- Result on success: **task properties** -- Result on failure: **null** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "getTask", - "id": 700738119, - "params": { - "task_id": 1 - } -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 700738119, - "result": { - "id": "1", - "title": "Task #1", - "description": "", - "date_creation": "1409963206", - "color_id": "blue", - "project_id": "1", - "column_id": "2", - "owner_id": "1", - "position": "1", - "is_active": "1", - "date_completed": null, - "score": "0", - "date_due": "0", - "category_id": "0", - "creator_id": "0", - "date_modification": "1409963206", - "reference": "", - "date_started": null, - "time_spent": "0", - "time_estimated": "0", - "swimlane_id": "0", - "date_moved": "1430875287", - "recurrence_status": "0", - "recurrence_trigger": "0", - "recurrence_factor": "0", - "recurrence_timeframe": "0", - "recurrence_basedate": "0", - "recurrence_parent": null, - "recurrence_child": null, - "url": "http:\/\/127.0.0.1:8000\/?controller=task&action=show&task_id=1&project_id=1", - "color": { - "name": "Yellow", - "background": "rgb(245, 247, 196)", - "border": "rgb(223, 227, 45)" - } - } -} -``` - -### getTaskByReference - -- Purpose: **Get task by the external reference** -- Parameters: - - **project_id** (integer, required) - - **reference** (string, required) -- Result on success: **task properties** -- Result on failure: **null** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "getTaskByReference", - "id": 1992081213, - "params": { - "project_id": 1, - "reference": "TICKET-1234" - } -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 1992081213, - "result": { - "id": "5", - "title": "Task with external ticket number", - "description": "[Link to my ticket](http:\/\/my-ticketing-system\/1234)", - "date_creation": "1434227446", - "color_id": "yellow", - "project_id": "1", - "column_id": "1", - "owner_id": "0", - "position": "4", - "is_active": "1", - "date_completed": null, - "score": "0", - "date_due": "0", - "category_id": "0", - "creator_id": "0", - "date_modification": "1434227446", - "reference": "TICKET-1234", - "date_started": null, - "time_spent": "0", - "time_estimated": "0", - "swimlane_id": "0", - "date_moved": "1434227446", - "recurrence_status": "0", - "recurrence_trigger": "0", - "recurrence_factor": "0", - "recurrence_timeframe": "0", - "recurrence_basedate": "0", - "recurrence_parent": null, - "recurrence_child": null, - "url": "http:\/\/127.0.0.1:8000\/?controller=task&action=show&task_id=5&project_id=1" - } -} -``` - -### getAllTasks - -- Purpose: **Get all available tasks** -- Parameters: - - **project_id** (integer, required) - - **status_id**: The value 1 for active tasks and 0 for inactive (integer, required) -- Result on success: **List of tasks** -- Result on failure: **false** - -Request example to fetch all tasks on the board: - -```json -{ - "jsonrpc": "2.0", - "method": "getAllTasks", - "id": 133280317, - "params": { - "project_id": 1, - "status_id": 1 - } -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 133280317, - "result": [ - { - "id": "1", - "title": "Task #1", - "description": "", - "date_creation": "1409961789", - "color_id": "blue", - "project_id": "1", - "column_id": "2", - "owner_id": "1", - "position": "1", - "is_active": "1", - "date_completed": null, - "score": "0", - "date_due": "0", - "category_id": "0", - "creator_id": "0", - "date_modification": "1409961789", - "reference": "", - "date_started": null, - "time_spent": "0", - "time_estimated": "0", - "swimlane_id": "0", - "date_moved": "1430783191", - "recurrence_status": "0", - "recurrence_trigger": "0", - "recurrence_factor": "0", - "recurrence_timeframe": "0", - "recurrence_basedate": "0", - "recurrence_parent": null, - "recurrence_child": null, - "url": "http:\/\/127.0.0.1:8000\/?controller=task&action=show&task_id=1&project_id=1" - }, - { - "id": "2", - "title": "Test", - "description": "", - "date_creation": "1409962115", - "color_id": "green", - "project_id": "1", - "column_id": "2", - "owner_id": "1", - "position": "2", - "is_active": "1", - "date_completed": null, - "score": "0", - "date_due": "0", - "category_id": "0", - "creator_id": "0", - "date_modification": "1409962115", - "reference": "", - "date_started": null, - "time_spent": "0", - "time_estimated": "0", - "swimlane_id": "0", - "date_moved": "1430783191", - "recurrence_status": "0", - "recurrence_trigger": "0", - "recurrence_factor": "0", - "recurrence_timeframe": "0", - "recurrence_basedate": "0", - "recurrence_parent": null, - "recurrence_child": null, - "url": "http:\/\/127.0.0.1:8000\/?controller=task&action=show&task_id=2&project_id=1" - }, - ... - ] -} -``` - -### getOverdueTasks - -- Purpose: **Get all overdue tasks** -- Result on success: **List of tasks** -- Result on failure: **false** - -Request example to fetch all tasks on the board: - -```json -{ - "jsonrpc": "2.0", - "method": "getOverdueTasks", - "id": 133280317 -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 133280317, - "result": [ - { - "id": "1", - "title": "Task #1", - "date_due": "1409961789", - "project_id": "1", - "project_name": "Test", - "assignee_username":"admin", - "assignee_name": null - }, - { - "id": "2", - "title": "Test", - "date_due": "1409962115", - "project_id": "1", - "project_name": "Test", - "assignee_username":"admin", - "assignee_name": null - }, - ... - ] -} -``` - -### updateTask - -- Purpose: **Update a task** -- Parameters: - - **id** (integer, required) - - **title** (string, optional) - - **project_id** (integer, optional) - - **color_id** (string, optional) - - **owner_id** (integer, optional) - - **creator_id** (integer, optional) - - **date_due**: ISO8601 format (string, optional) - - **description** Markdown content (string, optional) - - **category_id** (integer, optional) - - **score** (integer, optional) - - **recurrence_status** (integer, optional) - - **recurrence_trigger** (integer, optional) - - **recurrence_factor** (integer, optional) - - **recurrence_timeframe** (integer, optional) - - **recurrence_basedate** (integer, optional) -- Result on success: **true** -- Result on failure: **false** - -Request example to change the task color: - -```json -{ - "jsonrpc": "2.0", - "method": "updateTask", - "id": 1406803059, - "params": { - "id": 1, - "color_id": "blue" - } -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 1406803059, - "result": true -} -``` - -### openTask - -- Purpose: **Set a task to the status open** -- Parameters: - - **task_id** (integer, required) -- Result on success: **true** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "openTask", - "id": 1888531925, - "params": { - "task_id": 1 - } -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 1888531925, - "result": true -} -``` - -### closeTask - -- Purpose: **Set a task to the status close** -- Parameters: - - **task_id** (integer, required) -- Result on success: **true** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "closeTask", - "id": 1654396960, - "params": { - "task_id": 1 - } -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 1654396960, - "result": true -} -``` - -### removeTask - -- Purpose: **Remove a task** -- Parameters: - - **task_id** (integer, required) -- Result on success: **true** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "removeTask", - "id": 1423501287, - "params": { - "task_id": 1 - } -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 1423501287, - "result": true -} -``` - -### moveTaskPosition - -- Purpose: **Move a task to another column or another position** -- Parameters: - - **project_id** (integer, required) - - **task_id** (integer, required) - - **column_id** (integer, required) - - **position** (integer, required) - - **swimlane_id** (integer, optional, default=0) -- Result on success: **true** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "moveTaskPosition", - "id": 117211800, - "params": { - "project_id": 1, - "task_id": 1, - "column_id": 2, - "position": 1 - } -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 117211800, - "result": true -} -``` - -### createUser - -- Purpose: **Create a new user** -- Parameters: - - **username** Must be unique (string, required) - - **password** Must have at least 6 characters (string, required) - - **name** (string, optional) - - **email** (string, optional) - - **is_admin** Set the value 1 for admins or 0 for regular users (integer, optional) - - **is_project_admin** Set the value 1 for project admins or 0 for regular users (integer, optional) -- Result on success: **user_id** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "createUser", - "id": 1518863034, - "params": { - "username": "biloute", - "password": "123456" - } -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 1518863034, - "result": 22 -} -``` - -### createLdapUser - -- Purpose: **Create a new user authentified by LDAP** -- Parameters: - - **username** (string, optional if email is set) - - **email** (string, optional if username is set) - - **is_admin** Set the value 1 for admins or 0 for regular users (integer, optional) - - **is_project_admin** Set the value 1 for project admins or 0 for regular users (integer, optional) -- Result on success: **user_id** -- Result on failure: **false** - -The user will only be created if a matching is found on the LDAP server. -Username or email (or both) must be provided. - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "createLdapUser", - "id": 1518863034, - "params": { - "username": "biloute", - } -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 1518863034, - "result": 22 -} -``` - -### getUser - -- Purpose: **Get user information** -- Parameters: - - **user_id** (integer, required) -- Result on success: **user properties** -- Result on failure: **null** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "getUser", - "id": 1769674781, - "params": { - "user_id": 1 - } -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 1769674781, - "result": { - "id": "1", - "username": "biloute", - "password": "$2y$10$dRs6pPoBu935RpmsrhmbjevJH5MgZ7Kr9QrnVINwwyZ3.MOwqg.0m", - "is_admin": "0", - "is_ldap_user": "0", - "name": "", - "email": "", - "google_id": null, - "github_id": null, - "notifications_enabled": "0" - } -} -``` - -### getAllUsers - -- Purpose: **Get all available users** -- Parameters: - - **none** -- Result on success: **List of users** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "getAllUsers", - "id": 1438712131 -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 1438712131, - "result": [ - { - "id": "1", - "username": "biloute", - "name": "", - "email": "", - "is_admin": "0", - "is_ldap_user": "0", - "notifications_enabled": "0", - "google_id": null, - "github_id": null - }, - ... - ] -} -``` - -### updateUser - -- Purpose: **Update a user** -- Parameters: - - **id** (integer) - - **username** (string, optional) - - **name** (string, optional) - - **email** (string, optional) - - **is_admin** (integer, optional) - - **is_project_admin** Set the value 1 for project admins or 0 for regular users (integer, optional) -- Result on success: **true** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "updateUser", - "id": 322123657, - "params": { - "id": 1, - "is_admin": 1 - } -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 322123657, - "result": true -} -``` - -### removeUser - -- Purpose: **Remove a user** -- Parameters: - - **user_id** (integer, required) -- Result on success: **true** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "removeUser", - "id": 2094191872, - "params": { - "user_id": 1 - } -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 2094191872, - "result": true -} -``` - - -### createCategory - -- Purpose: **Create a new category** -- Parameters: -- **project_id** (integer, required) - - **name** (string, required, must be unique for the given project) -- Result on success: **category_id** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "createCategory", - "id": 541909890, - "params": { - "name": "Super category", - "project_id": 1 - } -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 541909890, - "result": 4 -} -``` - -### getCategory - -- Purpose: **Get category information** -- Parameters: - - **category_id** (integer, required) -- Result on success: **category properties** -- Result on failure: **null** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "getCategory", - "id": 203539163, - "params": { - "category_id": 1 - } -} -``` - -Response example: - -```json -{ - - "jsonrpc": "2.0", - "id": 203539163, - "result": { - "id": "1", - "name": "Super category", - "project_id": "1" - } -} -``` - -### getAllCategories - -- Purpose: **Get all available categories** -- Parameters: - - **project_id** (integer, required) -- Result on success: **List of categories** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "getAllCategories", - "id": 1261777968, - "params": { - "project_id": 1 - } -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 1261777968, - "result": [ - { - "id": "1", - "name": "Super category", - "project_id": "1" - } - ] -} -``` - -### updateCategory - -- Purpose: **Update a category** -- Parameters: - - **id** (integer, required) - - **name** (string, required) -- Result on success: **true** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "updateCategory", - "id": 570195391, - "params": { - "id": 1, - "name": "Renamed category" - } -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 570195391, - "result": true -} -``` - -### removeCategory - -- Purpose: **Remove a category** -- Parameters: - - **category_id** (integer) -- Result on success: **true** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "removeCategory", - "id": 88225706, - "params": { - "category_id": 1 - } -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 88225706, - "result": true -} -``` - - -### createComment - -- Purpose: **Create a new comment** -- Parameters: - - **task_id** (integer, required) - - **user_id** (integer, required) - - **content** Markdown content (string, required) -- Result on success: **comment_id** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "createComment", - "id": 1580417921, - "params": { - "task_id": 1, - "user_id": 1, - "content": "Comment #1" - } -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 1580417921, - "result": 11 -} -``` - -### getComment - -- Purpose: **Get comment information** -- Parameters: - - **comment_id** (integer, required) -- Result on success: **comment properties** -- Result on failure: **null** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "getComment", - "id": 867839500, - "params": { - "comment_id": 1 - } -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 867839500, - "result": { - "id": "1", - "task_id": "1", - "user_id": "1", - "date_creation": "1410881970", - "comment": "Comment #1", - "username": "admin", - "name": null - } -} -``` - -### getAllComments - -- Purpose: **Get all available comments** -- Parameters: - - **task_id** (integer, required) -- Result on success: **List of comments** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "getAllComments", - "id": 148484683, - "params": { - "task_id": 1 - } -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 148484683, - "result": [ - { - "id": "1", - "date_creation": "1410882272", - "task_id": "1", - "user_id": "1", - "comment": "Comment #1", - "username": "admin", - "name": null - }, - ... - ] -} -``` - -### updateComment - -- Purpose: **Update a comment** -- Parameters: - - **id** (integer, required) - - **content** Markdown content (string, required) -- Result on success: **true** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "updateComment", - "id": 496470023, - "params": { - "id": 1, - "content": "Comment #1 updated" - } -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 1493368950, - "result": true -} -``` - -### removeComment - -- Purpose: **Remove a comment** -- Parameters: - - **comment_id** (integer, required) -- Result on success: **true** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "removeComment", - "id": 328836871, - "params": { - "comment_id": 1 - } -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 328836871, - "result": true -} -``` - -### createSubtask - -- Purpose: **Create a new subtask** -- Parameters: - - **task_id** (integer, required) - - **title** (integer, required) - - **user_id** (int, optional) - - **time_estimated** (int, optional) - - **time_spent** (int, optional) - - **status** (int, optional) -- Result on success: **subtask_id** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "createSubtask", - "id": 2041554661, - "params": { - "task_id": 1, - "title": "Subtask #1" - } -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 2041554661, - "result": 45 -} -``` - -### getSubtask - -- Purpose: **Get subtask information** -- Parameters: - - **subtask_id** (integer) -- Result on success: **subtask properties** -- Result on failure: **null** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "getSubtask", - "id": 133184525, - "params": { - "subtask_id": 1 - } -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 133184525, - "result": { - "id": "1", - "title": "Subtask #1", - "status": "0", - "time_estimated": "0", - "time_spent": "0", - "task_id": "1", - "user_id": "0" - } -} -``` - -### getAllSubtasks - -- Purpose: **Get all available subtasks** -- Parameters: - - **task_id** (integer, required) -- Result on success: **List of subtasks** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "getAllSubtasks", - "id": 2087700490, - "params": { - "task_id": 1 - } -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 2087700490, - "result": [ - { - "id": "1", - "title": "Subtask #1", - "status": "0", - "time_estimated": "0", - "time_spent": "0", - "task_id": "1", - "user_id": "0", - "username": null, - "name": null, - "status_name": "Todo" - }, - ... - ] -} -``` - -### updateSubtask - -- Purpose: **Update a subtask** -- Parameters: - - **id** (integer, required) - - **task_id** (integer, required) - - **title** (integer, optional) - - **user_id** (integer, optional) - - **time_estimated** (integer, optional) - - **time_spent** (integer, optional) - - **status** (integer, optional) -- Result on success: **true** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "updateSubtask", - "id": 191749979, - "params": { - "id": 1, - "task_id": 1, - "status": 1, - "time_spent": 5, - "user_id": 1 - } -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 191749979, - "result": true -} -``` - -### removeSubtask - -- Purpose: **Remove a subtask** -- Parameters: - - **subtask_id** (integer, required) -- Result on success: **true** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "removeSubtask", - "id": 1382487306, - "params": { - "subtask_id": 1 - } -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 1382487306, - "result": true -} -``` - -### getAllLinks - -- Purpose: **Get the list of possible relations between tasks** -- Parameters: none -- Result on success: **List of links** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "getAllLinks", - "id": 113057196 -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 113057196, - "result": [ - { - "id": "1", - "label": "relates to", - "opposite_id": "0" - }, - { - "id": "2", - "label": "blocks", - "opposite_id": "3" - }, - { - "id": "3", - "label": "is blocked by", - "opposite_id": "2" - }, - { - "id": "4", - "label": "duplicates", - "opposite_id": "5" - }, - { - "id": "5", - "label": "is duplicated by", - "opposite_id": "4" - }, - { - "id": "6", - "label": "is a child of", - "opposite_id": "7" - }, - { - "id": "7", - "label": "is a parent of", - "opposite_id": "6" - }, - { - "id": "8", - "label": "targets milestone", - "opposite_id": "9" - }, - { - "id": "9", - "label": "is a milestone of", - "opposite_id": "8" - }, - { - "id": "10", - "label": "fixes", - "opposite_id": "11" - }, - { - "id": "11", - "label": "is fixed by", - "opposite_id": "10" - } - ] -} -``` - -### getOppositeLinkId - -- Purpose: **Get the opposite link id of a task link** -- Parameters: - - **link_id** (integer, required) -- Result on success: **link_id** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "getOppositeLinkId", - "id": 407062448, - "params": [ - 2 - ] -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 407062448, - "result": "3" -} -``` - -### getLinkByLabel - -- Purpose: **Get a link by label** -- Parameters: - - **label** (integer, required) -- Result on success: **link properties** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "getLinkByLabel", - "id": 1796123316, - "params": [ - "blocks" - ] -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 1796123316, - "result": { - "id": "2", - "label": "blocks", - "opposite_id": "3" - } -} -``` - -### getLinkById - -- Purpose: **Get a link by id** -- Parameters: - - **link_id** (integer, required) -- Result on success: **link properties** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "getLinkById", - "id": 1190238402, - "params": [ - 4 - ] -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 1190238402, - "result": { - "id": "4", - "label": "duplicates", - "opposite_id": "5" - } -} -``` - -### createLink - -- Purpose: **Create a new task relation** -- Parameters: - - **label** (integer, required) - - **opposite_label** (integer, optional) -- Result on success: **link_id** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "createLink", - "id": 1040237496, - "params": [ - "foo", - "bar" - ] -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 1040237496, - "result": 13 -} -``` - -### updateLink - -- Purpose: **Update a link** -- Parameters: - - **link_id** (integer, required) - - **opposite_link_id** (integer, required) - - **label** (string, required) -- Result on success: **true** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "updateLink", - "id": 2110446926, - "params": [ - "14", - "12", - "boo" - ] -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 2110446926, - "result": true -} -``` - -### removeLink - -- Purpose: **Remove a link** -- Parameters: - - **link_id** (integer, required) -- Result on success: **true** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "removeLink", - "id": 2136522739, - "params": [ - "14" - ] -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 2136522739, - "result": true -} -``` - -### createTaskLink - -- Purpose: **Create a link between two tasks** -- Parameters: - - **task_id** (integer, required) - - **opposite_task_id** (integer, required) - - **link_id** (integer, required) -- Result on success: **task_link_id** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "createTaskLink", - "id": 509742912, - "params": [ - 2, - 3, - 1 - ] -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 509742912, - "result": 1 -} -``` - -### updateTaskLink - -- Purpose: **Update task link** -- Parameters: - - **task_link_id** (integer, required) - - **task_id** (integer, required) - - **opposite_task_id** (integer, required) - - **link_id** (integer, required) -- Result on success: **true** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "updateTaskLink", - "id": 669037109, - "params": [ - 1, - 2, - 4, - 2 - ] -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 669037109, - "result": true -} -``` - -### getTaskLinkById - -- Purpose: **Get a task link** -- Parameters: - - **task_link_id** (integer, required) -- Result on success: **task link properties** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "getTaskLinkById", - "id": 809885202, - "params": [ - 1 - ] -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 809885202, - "result": { - "id": "1", - "link_id": "1", - "task_id": "2", - "opposite_task_id": "3" - } -} -``` - -### getAllTaskLinks - -- Purpose: **Get all links related to a task** -- Parameters: - - **task_id** (integer, required) -- Result on success: **list of task link** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "getAllTaskLinks", - "id": 810848359, - "params": [ - 2 - ] -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 810848359, - "result": [ - { - "id": "1", - "task_id": "3", - "label": "relates to", - "title": "B", - "is_active": "1", - "project_id": "1", - "task_time_spent": "0", - "task_time_estimated": "0", - "task_assignee_id": "0", - "task_assignee_username": null, - "task_assignee_name": null, - "column_title": "Backlog" - } - ] -} -``` - -### removeTaskLink - -- Purpose: **Remove a link between two tasks** -- Parameters: - - **task_link_id** (integer, required) -- Result on success: **true** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "removeTaskLink", - "id": 473028226, - "params": [ - 1 - ] -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 473028226, - "result": true -} -``` - -### createFile - -- Purpose: **Create and upload a new task attachment** -- Parameters: - - **project_id** (integer, required) - - **task_id** (integer, required) - - **filename** (integer, required) - - **blob** File content encoded in base64 (string, required) -- Result on success: **file_id** -- Result on failure: **false** -- Note: **The maximum file size depends of your PHP configuration, this method should not be used to upload large files** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "createFile", - "id": 94500810, - "params": [ - 1, - 1, - "My file", - "cGxhaW4gdGV4dCBmaWxl" - ] -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 94500810, - "result": 1 -} -``` - -### getAllFiles - -- Purpose: **Get all files attached to task** -- Parameters: - - **task_id** (integer, required) -- Result on success: **list of files** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "getAllFiles", - "id": 1880662820, - "params": { - "task_id": 1 - } -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 1880662820, - "result": [ - { - "id": "1", - "name": "My file", - "path": "1\/1\/0db4d0a897a4c852f6e12f0239d4805f7b4ab596", - "is_image": "0", - "task_id": "1", - "date": "1432509941", - "user_id": "0", - "size": "15", - "username": null, - "user_name": null - } - ] -} -``` - -### getFile - -- Purpose: **Get file information** -- Parameters: - - **file_id** (integer, required) -- Result on success: **file properties** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "getFile", - "id": 318676852, - "params": [ - "1" - ] -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 318676852, - "result": { - "id": "1", - "name": "My file", - "path": "1\/1\/0db4d0a897a4c852f6e12f0239d4805f7b4ab596", - "is_image": "0", - "task_id": "1", - "date": "1432509941", - "user_id": "0", - "size": "15" - } -} -``` - -### downloadFile - -- Purpose: **Download file contents (encoded in base64)** -- Parameters: - - **file_id** (integer, required) -- Result on success: **base64 encoded string** -- Result on failure: **empty string** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "downloadFile", - "id": 235943344, - "params": [ - "1" - ] -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 235943344, - "result": "cGxhaW4gdGV4dCBmaWxl" -} -``` - -### removeFile - -- Purpose: **Remove file** -- Parameters: - - **file_id** (integer, required) -- Result on success: **true** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "removeFile", - "id": 447036524, - "params": [ - "1" - ] -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 447036524, - "result": true -} -``` - -### removeAllFiles - -- Purpose: **Remove all files associated to a task** -- Parameters: - - **task_id** (integer, required) -- Result on success: **true** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "removeAllFiles", - "id": 593312993, - "params": { - "task_id": 1 - } -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 593312993, - "result": true -} -``` - -### getMe - -- Purpose: **Get logged user session** -- Parameters: None -- Result on success: **user session data** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "getMe", - "id": 1718627783 -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 1718627783, - "result": { - "id": 2, - "username": "user", - "is_admin": false, - "is_ldap_user": false, - "name": "", - "email": "", - "google_id": null, - "github_id": null, - "notifications_enabled": "0", - "timezone": null, - "language": null, - "disable_login_form": "0", - "twofactor_activated": false, - "twofactor_secret": null, - "token": "", - "notifications_filter": "4" - } -} -``` - -### getMyDashboard - -- Purpose: **Get the dashboard of the logged user without pagination** -- Parameters: None -- Result on success: **Dashboard information** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "getMyDashboard", - "id": 447898718 -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 1563664593, - "result": { - "projects": [ - { - "id": "2", - "name": "my project", - "is_active": "1", - "token": "", - "last_modified": "1438205337", - "is_public": "0", - "is_private": "1", - "is_everybody_allowed": "0", - "default_swimlane": "Default swimlane", - "show_default_swimlane": "1", - "description": null, - "identifier": "", - "columns": [ - { - "id": "5", - "title": "Backlog", - "position": "1", - "project_id": "2", - "task_limit": "0", - "description": "", - "nb_tasks": 0 - }, - { - "id": "6", - "title": "Ready", - "position": "2", - "project_id": "2", - "task_limit": "0", - "description": "", - "nb_tasks": 0 - }, - { - "id": "7", - "title": "Work in progress", - "position": "3", - "project_id": "2", - "task_limit": "0", - "description": "", - "nb_tasks": 0 - }, - { - "id": "8", - "title": "Done", - "position": "4", - "project_id": "2", - "task_limit": "0", - "description": "", - "nb_tasks": 0 - } - ], - "url": { - "board": "http:\/\/127.0.0.1:8000\/?controller=board&action=show&project_id=2", - "calendar": "http:\/\/127.0.0.1:8000\/?controller=calendar&action=show&project_id=2", - "list": "http:\/\/127.0.0.1:8000\/?controller=listing&action=show&project_id=2" - } - } - ], - "tasks": [ - { - "id": "1", - "title": "new title", - "date_due": "0", - "date_creation": "1438205336", - "project_id": "2", - "color_id": "yellow", - "time_spent": "0", - "time_estimated": "0", - "project_name": "my project", - "url": "http:\/\/127.0.0.1:8000\/?controller=task&action=show&task_id=1&project_id=2" - } - ], - "subtasks": [] - } -} -``` - -### getMyActivityStream - -- Purpose: **Get the last 100 events for the logged user** -- Parameters: None -- Result on success: **List of events** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "getMyActivityStream", - "id": 1132562181 -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 1132562181, - "result": [ - { - "id": "1", - "date_creation": "1438205054", - "event_name": "task.create", - "creator_id": "2", - "project_id": "2", - "task_id": "1", - "author_username": "user", - "author_name": "", - "email": "", - "task": { - "id": "1", - "reference": "", - "title": "my user title", - "description": "", - "date_creation": "1438205054", - "date_completed": null, - "date_modification": "1438205054", - "date_due": "0", - "date_started": null, - "time_estimated": "0", - "time_spent": "0", - "color_id": "yellow", - "project_id": "2", - "column_id": "5", - "owner_id": "0", - "creator_id": "2", - "position": "1", - "is_active": "1", - "score": "0", - "category_id": "0", - "swimlane_id": "0", - "date_moved": "1438205054", - "recurrence_status": "0", - "recurrence_trigger": "0", - "recurrence_factor": "0", - "recurrence_timeframe": "0", - "recurrence_basedate": "0", - "recurrence_parent": null, - "recurrence_child": null, - "category_name": null, - "swimlane_name": null, - "project_name": "my project", - "default_swimlane": "Default swimlane", - "column_title": "Backlog", - "assignee_username": null, - "assignee_name": null, - "creator_username": "user", - "creator_name": "" - }, - "changes": [], - "author": "user", - "event_title": "user created the task #1", - "event_content": "\n

    \n user created the task #1<\/a><\/p>\n

    \n my user title<\/em>\n<\/p>" - } - ] -} -``` - -### createMyPrivateProject - -- Purpose: **Create a private project for the logged user** -- Parameters: - - **name** (string, required) - - **description** (string, optional) -- Result on success: **project_id** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "createMyPrivateProject", - "id": 1271580569, - "params": [ - "my project" - ] -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 1271580569, - "result": 2 -} -``` - -### getMyProjectsList - -- Purpose: **Get projects of the connected user** -- Parameters: None -- Result on success: **dictionary of project_id => project_name** -- Result on failure: **false** - -Request example: - -```json -{ - "jsonrpc": "2.0", - "method": "getMyProjectsList", - "id": 987834805 -} -``` - -Response example: - -```json -{ - "jsonrpc": "2.0", - "id": 987834805, - "result": { - "2": "my project" - } -} -``` diff --git a/docs/application-configuration.markdown b/docs/application-configuration.markdown deleted file mode 100644 index 32710a39..00000000 --- a/docs/application-configuration.markdown +++ /dev/null @@ -1,40 +0,0 @@ -Application settings -==================== - -Some parameters for the application can be changed on the settings page. -Only administrators can change those settings. - -Go to the menu **Settings**, then choose **Application settings** on the left. - -![Application settings](http://kanboard.net/screenshots/documentation/application-settings.png) - -### Application URL - -This parameter is used for email notifications. -The email footer will contains a link to the Kanboard task. - -### Language - -The application language can be changed at anytime. -The language will be set for all users. - -### Timezone - -By default, Kanboard use UTC as timezone, but you can define your own timezone. -The list contains all supported timezones by your web server. - -### Date format - -Input format used for date fields, by example the due date for tasks. - -Kanboard offer 3 different choices: - -- DD/MM/YYYY -- MM/DD/YYYY (default) -- YYYY/MM/DD - -The [ISO 8601](http://en.wikipedia.org/wiki/ISO_8601) format is always accepted (YYYY-MM-DD or YYYY_MM_DD). - -### Custom Stylesheet - -Write your own CSS to override or improve Kanboard default style. diff --git a/docs/assets.markdown b/docs/assets.markdown deleted file mode 100644 index 29bf515b..00000000 --- a/docs/assets.markdown +++ /dev/null @@ -1,25 +0,0 @@ -How to build assets (Javascript and CSS files) -============================================== - -Stylesheet and Javascript files are merged together and minified. - -- Original CSS files are stored in the folder `assets/css/src/*.css` -- Original Javascript code is stored in the folder `assets/js/src/*.js` - -Requirements ------------- - -- Unix operating system -- make -- yuicompressor in your path (`brew install yuicompressor`) - -Build assets ------------- - -- Build Stylesheet files: `make css` -- Build Javascript files: `make js` -- Build both: `make` - -This script generates the files `assets/css/app.css` and `assets/js/app.js`. - -This tool is only available in the repository (development version). diff --git a/docs/automatic-actions.markdown b/docs/automatic-actions.markdown deleted file mode 100644 index c4e2bc4c..00000000 --- a/docs/automatic-actions.markdown +++ /dev/null @@ -1,138 +0,0 @@ -Automatic Actions -================= - -To minimize the user interaction, Kanboard support automatic actions. - -Each automatic action is defined like that: - -- An event to listen -- An action linked to this event -- Eventually there is some parameters to define - -Each project can have a different set of automatic actions, the configuration panel is located on the project listing page, just click on the link **Automatic actions**. - -Add a new action ----------------- - -### Choose an action - -![Choose an action](http://kanboard.net/screenshots/documentation/project-automatic-action-step1.png) - -### Choose an event - -![Choose an event](http://kanboard.net/screenshots/documentation/project-automatic-action-step2.png) - -### Define action parameters - -![Define parameters](http://kanboard.net/screenshots/documentation/project-automatic-action-step3.png) - -List of available events ------------------------- - -- Move a task to another column -- Move a task to another position in the same column -- Task modification -- Task creation -- Reopen a task -- Closing a task -- Task creation or modification -- Task assignee change -- Task link created or updated -- Github commit received -- Github issue opened -- Github issue closed -- Github issue reopened -- Github issue assignee change -- Github issue label change -- Github issue comment created -- Gitlab issue opened -- Gitlab issue closed -- Gitlab commit received -- Bitbucket commit received -- Bitbucket issue opened -- Bitbucket issue closed -- Bitbucket issue reopened -- Bitbucket issue assignee change -- Bitbucket issue comment created - -List of available actions -------------------------- - -- Close the task -- Open a task -- Assign the task to a specific user -- Assign the task to the person who does the action -- Duplicate the task to another project -- Move the task to another project -- Move the task to another column when assigned to a user -- Move the task to another column when assignee is cleared -- Assign a color when the task is moved to a specific column -- Assign a color to a specific user -- Assign automatically a color based on a category -- Assign automatically a category based on a color -- Create a comment from an external provider -- Create a task from an external provider -- Add a comment log when moving the task between columns -- Change the assignee based on an external username -- Change the category based on an external label -- Automatically update the start date -- Move the task to another column when the category is changed -- Send a task by email to someone -- Change task color when using a specific task link - -Examples --------- - -Here are some examples used in the real life: - -### When I move a task to the column "Done", automatically close this task - -- Choose the action: **Close the task** -- Choose the event: **Move a task to another column** -- Define the action parameter: **Column = Done** (this is the destination column) - -### When I move a task to the column "To be validated", assign this task to a specific user - -- Choose the action: **Assign the task to a specific user** -- Choose the event: **Move a task to another column** -- Define the action parameters: **Column = To be validated** and **User = Bob** (Bob is our tester) - -### When I move a task to the column "Work in progress", assign this task to the current user - -- Choose the action: **Assign the task to the person who does the action** -- Choose the event: **Move a task to another column** -- Define the action parameter: **Column = Work in progress** - -### When a task is completed, duplicate this task to another project - -Let's say we have two projects "Customer orders" and "Production", once the order is validated, swap it to the "Production" project. - -- Choose the action: **Duplicate the task to another project** -- Choose the event: **Closing a task** -- Define the action parameters: **Column = Validated** and **Project = Production** - -### When a task is moved to the last column, move the exact same task to another project - -Let's say we have two projects "Ideas" and "Development", once the idea is validated, swap it to the "Development" project. - -- Choose the action: **Move the task to another project** -- Choose the event: **Move a task to another column** -- Define the action parameters: **Column = Validated** and **Project = Development** - -### I want to assign automatically a color to the user Bob - -- Choose the action: **Assign a color to a specific user** -- Choose the event: **Task assignee change** -- Define the action parameters: **Color = Green** and **Assignee = Bob** - -### I want to assign automatically a color to the defined category "Feature Request" - -- Choose the action: **Assign automatically a color based on a category** -- Choose the event: **Task creation or modification** -- Define the action parameters: **Color = Blue** and **Category = Feature Request** - -### I want to set the start date automatically when the task is moved to the column "Work in progress" - -- Choose the action: **Automatically update the start date** -- Choose the event: **Move a task to another column** -- Define the action parameters: **Column = Work in progress** diff --git a/docs/bitbucket-webhooks.markdown b/docs/bitbucket-webhooks.markdown deleted file mode 100644 index 7f59aa11..00000000 --- a/docs/bitbucket-webhooks.markdown +++ /dev/null @@ -1,55 +0,0 @@ -Bitbucket webhooks -================== - -Bitbucket events can be connected to Kanboard automatic actions. - -List of supported events ------------------------- - -- Bitbucket commit received -- Bitbucket issue opened -- Bitbucket issue closed -- Bitbucket issue reopened -- Bitbucket issue assignee change -- Bitbucket issue comment created - -List of supported actions -------------------------- - -- Create a task from an external provider -- Change the assignee based on an external username -- Create a comment from an external provider -- Close a task -- Open a task - -Configuration -------------- - -![Bitbucket configuration](http://kanboard.net/screenshots/documentation/bitbucket-webhooks.png) - -1. On Kanboard, go to the project settings and choose the section **Integrations** -2. Copy the Bitbucket webhook url -3. On Bitbucket, go to the project settings and go to the section **Webhooks** -4. Choose a title for your webhook and paste the Kanboard url - -Examples --------- - -### Close a Kanboard task when a commit pushed to Bitbucket - -- Choose the event: **Bitbucket commit received** -- Choose the action: **Close the task** - -When one or more commits are sent to Bitbucket, Kanboard will receive the information, each commit message with a task number included will be closed. - -Example: - -- Commit message: "Fix bug #1234" -- That will close the Kanboard task #1234 - -### Add comment when a commit received - -- Choose the event: **Bitbucket commit received** -- Choose the action: **Create a comment from an external provider** - -The comment will contains the commit message and the url to the commit. diff --git a/docs/board-collapsed-expanded.markdown b/docs/board-collapsed-expanded.markdown deleted file mode 100644 index e094e817..00000000 --- a/docs/board-collapsed-expanded.markdown +++ /dev/null @@ -1,19 +0,0 @@ -Collapsed and Expanded mode -=========================== - -Tasks on the board can be displayed in collapsed or in expanded mode. -Switching from one view to another can be done with the keyboard shortcut **"s"** or by using the dropdown menu on the left. - -Collapsed mode --------------- - -![Tasks collapsed](http://kanboard.net/screenshots/documentation/board-collapsed-mode.png) - -- If the task is assigned to someone, the initials of the person are shown next to the task number -- If the task title is too long, you can put your mouse over the task to show a tooltip with the full title. - -Expanded mode -------------- - -![Tasks expanded](http://kanboard.net/screenshots/documentation/board-expanded-mode.png) - diff --git a/docs/board-configuration.markdown b/docs/board-configuration.markdown deleted file mode 100644 index 1c5ff51a..00000000 --- a/docs/board-configuration.markdown +++ /dev/null @@ -1,24 +0,0 @@ -Board settings -============== - -Go to the menu **Settings**, then choose **Board settings** on the left. - -![Board settings](http://kanboard.net/screenshots/documentation/board-settings.png) - -### Task highlighting - -This feature display a shadow around the task when a task is moved recently. - -Set the value 0 to disable this feature, 2 days by default (172800 seconds). - -Everything moved since 2 days will have shadow around the task. - -### Refresh interval for public board - -When you share a board, the page will refresh automatically every 60 seconds by default. - -### Refresh interval for private board - -When your web browser is open on a board, Kanboard check every 10 seconds if something have been changed by someone else. - -Technically this process is done by Ajax polling. diff --git a/docs/board-horizontal-scrolling-and-compact-view.markdown b/docs/board-horizontal-scrolling-and-compact-view.markdown deleted file mode 100644 index 16d1e74c..00000000 --- a/docs/board-horizontal-scrolling-and-compact-view.markdown +++ /dev/null @@ -1,12 +0,0 @@ -Horizontal scrolling and compact mode -===================================== - -When the board can't fit on your screen, an horizontal scroll bar will appear at the bottom. - -However, it's possible to switch to the compact the view to display all columns in your screen. - -![Board in compact mode](http://kanboard.net/screenshots/documentation/board-compact-mode.png) - -Switching between horizontal scrolling and compact view can be done with the keyboard shortcut **"c"** or by using the dropdown menu on the top left. - -Note: It's possible that text overlaps in compact mode, that will be improved over the next releases. \ No newline at end of file diff --git a/docs/board-show-hide-columns.markdown b/docs/board-show-hide-columns.markdown deleted file mode 100644 index e459f555..00000000 --- a/docs/board-show-hide-columns.markdown +++ /dev/null @@ -1,11 +0,0 @@ -Show and hide columns on the board -================================== - -You can hide or display columns very easily on the board: - -![Board with hidden columns](http://kanboard.net/screenshots/documentation/board-hide-show-column.png) - -- To hide a column, just click on the column title -- To show a hidden column, click on the vertical title - -When a column is hidden the number of tasks is displayed at the top. diff --git a/docs/bruteforce-protection.markdown b/docs/bruteforce-protection.markdown deleted file mode 100644 index 633cfe87..00000000 --- a/docs/bruteforce-protection.markdown +++ /dev/null @@ -1,26 +0,0 @@ -Bruteforce Protection -===================== - -The brute force protection of Kanboard works at the user account level: - -- After 3 authentication failure for the same username, the login form show a captcha image to prevent automated bot tentatives. -- After 6 authentication failure, the user account is locked down for a period of 15 minutes. - -This feature works only for authentication methods that use the login form. - -However, **after 3 authentication failure through the user API**, the account have to be unlocked by using the login form. - -Kanboard doesn't block any IP addresses since bots can use several anonymous proxies. However, you can use external tools like [fail2ban](http://www.fail2ban.org) to avoid massive scans. - -Default settings can be changed with these configuration variables: - -```php -// Enable captcha after 3 authentication failure -define('BRUTEFORCE_CAPTCHA', 3); - -// Lock the account after 6 authentication failure -define('BRUTEFORCE_LOCKDOWN', 6); - -// Lock account duration in minute -define('BRUTEFORCE_LOCKDOWN_DURATION', 15); -``` diff --git a/docs/budget.markdown b/docs/budget.markdown deleted file mode 100644 index 63408d46..00000000 --- a/docs/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/docs/calendar-configuration.markdown b/docs/calendar-configuration.markdown deleted file mode 100644 index 95e13e52..00000000 --- a/docs/calendar-configuration.markdown +++ /dev/null @@ -1,42 +0,0 @@ -Calendar settings -================= - -Go to the menu **Settings**, then choose **Calendar settings** on the left. - -![Calendar settings](http://kanboard.net/screenshots/documentation/calendar-settings.png) - -There are two different calendars in Kanboard: - -- Project calendar -- User calendar (available from the dashboard) - -Project calendar ----------------- - -This calendar show tasks with defined due date and tasks based on the creation date or the start date. - -### Show tasks based on the creation date - -- The start date of the calendar event is the creation date of the task. -- The end date of the event is the date of completion. - -### Show tasks based on the start date - -- The start date of the calendar event is the start date of the task. -- This date can be defined manually. -- The end date of the event is the date of completion. -- If there is no start date the task will not appear on the calendar. - -User calendar -------------- - -This calendar show only tasks assigned to the user and optionally subtasks information. - -### Show subtasks based on the time tracking - -- Display subtasks in the calendar from the information recorded in the time tracking table. -- The intersection with the user timetable is also calculated. - -### Show subtask estimates (forecast of future work) - -- Display the estimate of future work for subtasks in status "todo" and with a defined "estimate" value. diff --git a/docs/calendar.markdown b/docs/calendar.markdown deleted file mode 100644 index 7b95baa2..00000000 --- a/docs/calendar.markdown +++ /dev/null @@ -1,20 +0,0 @@ -Calendar -======== - -There are two different views for the calendar: - -- The project view with filters (available from the board) -- The user view (available from the dashboard and from the user section) - -At this time the calendar is able to display these information: - -- Tasks with a due date, displayed at the top. **The due date can be changed by moving the task to another day**. -- Tasks based on the creation date or the start date. **These events cannot be modified with the calendar**. -- Subtask time tracking, all recorded time slot will be shown in the calendar. -- Subtask estimates, forecast of work left - -![Calendar](http://kanboard.net/screenshots/documentation/calendar.png) - -The calendar configuration can be changed in the settings page. - -Note: The due date doesn't contains time information. diff --git a/docs/centos-installation.markdown b/docs/centos-installation.markdown deleted file mode 100644 index 6cfc31ff..00000000 --- a/docs/centos-installation.markdown +++ /dev/null @@ -1,77 +0,0 @@ -Centos Installation -=================== - -Centos 7 --------- - -Install PHP and Apache: - -```bash -yum install -y php php-mbstring php-pdo php-gd unzip wget -``` - -By default Centos 7 use PHP 5.4.16 and Apache 2.4.6. - -Restart Apache: - -```bash -systemctl restart httpd.service -``` - -Install Kanboard: - -```bash -cd /var/www/html -wget http://kanboard.net/kanboard-latest.zip -unzip kanboard-latest.zip -chown -R apache:apache kanboard/data -rm kanboard-latest.zip -``` - -If SELinux is enabled, be sure that the Apache user can write to the directory data: - -```bash -chcon -R -t httpd_sys_content_rw_t /var/www/html/kanboard/data -``` - -Be sure to configure your server to allow Kanboard to send emails and make external network requests, by example with SELinux: - -```bash -setsebool -P httpd_can_network_connect=1 -``` - -Allowing external connections is necessary if you use LDAP, SMTP, Webhooks or any third-party integrations. - -Centos 6.x ----------- - -Install PHP and Apache: - -```bash -yum install -y php php-mbstring php-pdo php-gd unzip wget -``` - -By default Centos 6.5 use PHP 5.3.3 and Apache 2.2.15. - -Enable short tags: - -- Edit the file `/etc/php.ini` -- Change the line `short_open_tag = On` - -Restart Apache: - -```bash -service httpd restart -``` - -Install Kanboard: - -```bash -cd /var/www/html -wget http://kanboard.net/kanboard-latest.zip -unzip kanboard-latest.zip -chown -R apache:apache kanboard/data -rm kanboard-latest.zip -``` - -Go to `http://your_server/kanboard/`. \ No newline at end of file diff --git a/docs/cli.markdown b/docs/cli.markdown deleted file mode 100644 index 38cba496..00000000 --- a/docs/cli.markdown +++ /dev/null @@ -1,144 +0,0 @@ -Command Line Interface -====================== - -Kanboard provide a simple command line interface that can be used from any Unix terminal. -This tool can be used only on the local machine. - -This feature is useful to run commands outside the web server process by example running a huge report. - -Usage ------ - -- Open a terminal and go to your Kanboard directory (example: `cd /var/www/kanboard`) -- Run the command `./kanboard` - -```bash -Kanboard version master - -Usage: - command [options] [arguments] - -Options: - -h, --help Display this help message - -q, --quiet Do not output any message - -V, --version Display this application version - --ansi Force ANSI output - --no-ansi Disable ANSI output - -n, --no-interaction Do not ask any interactive question - -v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug - -Available commands: - help Displays help for a command - list Lists commands - export - export:daily-project-column-stats Daily project column stats CSV export (number of tasks per column and per day) - export:subtasks Subtasks CSV export - export:tasks Tasks CSV export - export:transitions Task transitions CSV export - locale - locale:compare Compare application translations with the fr_FR locale - locale:sync Synchronize all translations based on the fr_FR locale - notification - notification:overdue-tasks Send notifications for overdue tasks - projects - projects:daily-stats Calculate daily statistics for all projects -``` - -Available commands ------------------- - -### Tasks CSV export - -Usage: - -```bash -./kanboard export:tasks -``` - -Example: - -```bash -./kanboard export:tasks 1 2014-10-01 2014-11-30 > /tmp/my_custom_export.csv -``` - -CSV data are sent to `stdout`. - -### Subtasks CSV export - -Usage: - -```bash -./kanboard export:subtasks -``` - -Example: - -```bash -./kanboard export:subtasks 1 2014-10-01 2014-11-30 > /tmp/my_custom_export.csv -``` - -### Task transitions CSV export - -Usage: - -```bash -./kanboard export:transitions -``` - -Example: - -```bash -./kanboard export:transitions 1 2014-10-01 2014-11-30 > /tmp/my_custom_export.csv -``` - -### Export daily summaries data in CSV - -The exported data will be printed on the standard output: - -```bash -./kanboard export:daily-project-column-stats -``` - -Example: - -```bash -./kanboard export:daily-project-column-stats 1 2014-10-01 2014-11-30 > /tmp/my_custom_export.csv -``` - -### Send notifications for overdue tasks - -Emails will be sent to all users with notifications enabled. - -```bash -./kanboard notification:overdue-tasks -``` - -You can also display the overdue tasks with the flag `--show`: - -```bash -$ ./kanboard notification:overdue-tasks --show -+-----+---------+------------+------------+--------------+----------+ -| Id | Title | Due date | Project Id | Project name | Assignee | -+-----+---------+------------+------------+--------------+----------+ -| 201 | Test | 2014-10-26 | 1 | Project #0 | admin | -| 202 | My task | 2014-10-28 | 1 | Project #0 | | -+-----+---------+------------+------------+--------------+----------+ -``` - -Cronjob example: - -```bash -# Everyday at 8am we check for due tasks -0 8 * * * cd /path/to/kanboard && ./kanboard notification:overdue-tasks >/dev/null 2>&1 -``` - -### Run daily project stats calculation - -You can add a background task to calculate the project statistics everyday: - -```bash -$ ./kanboard projects:daily-stats -Run calculation for Project #0 -Run calculation for Project #1 -Run calculation for Project #10 -``` diff --git a/docs/closing-tasks.markdown b/docs/closing-tasks.markdown deleted file mode 100644 index 235387a9..00000000 --- a/docs/closing-tasks.markdown +++ /dev/null @@ -1,16 +0,0 @@ -Closing tasks -============= - -When a task is closed, they are hidden from the board. - -However, you can always access to the list of closed tasks by using the query **status:closed** in any search form or simply choose **Closed tasks** from the filter dropdown. - -There are two different way to close a task, from the task dropdown menu on the board: - -![Close a task from dropdown menu](http://kanboard.net/screenshots/documentation/menu-close-task.png) - -Or from the task sidebar menu in the task detail view: - -![Close a task](http://kanboard.net/screenshots/documentation/closing-tasks.png) - -Note: When you close a task, all subtasks not completed will be changed to the status "Done". \ No newline at end of file diff --git a/docs/coding-standards.markdown b/docs/coding-standards.markdown deleted file mode 100644 index e0e762db..00000000 --- a/docs/coding-standards.markdown +++ /dev/null @@ -1,24 +0,0 @@ -Coding standards -================ - -PHP code --------- - -- Indentation: 4 spaces -- Line return: Unix => `\n` -- Encoding: UTF-8 -- Use only the opening tags ` `\n` - -CSS code --------- - -- Indentation: 4 spaces -- Line return: Unix => `\n` diff --git a/docs/config.markdown b/docs/config.markdown deleted file mode 100644 index b5c3ce0d..00000000 --- a/docs/config.markdown +++ /dev/null @@ -1,242 +0,0 @@ -Config file -=========== - -You can customize the default settings of Kanboard by adding a file `config.php` at the project root. -You can also rename the `config.default.php` and change the desired values. - -Enable/Disable debug mode -------------------------- - -```php -define('DEBUG', false); -``` - -The debug mode logs all SQL queries and the time taken to generate pages. - -Debug file path ---------------- - -```php -define('DEBUG_FILE', __DIR__.'/data/debug.log'); -``` - -All debug information are saved in this file. -If you prefer to send logs to `stdout` or `stderr` replace the value by `php://stdout` or `php://stderr`. - -Folder for uploaded files -------------------------- - -```php -define('FILES_DIR', 'data/files/'); -``` - -Don't forget the trailing slash. - -Enable/disable url rewrite --------------------------- - -```php -define('ENABLE_URL_REWRITE', false); -``` - -Email configuration -------------------- - -```php -// E-mail address for the "From" header (notifications) -define('MAIL_FROM', 'notifications@kanboard.local'); - -// Mail transport to use: "smtp", "sendmail" or "mail" (PHP mail function) -define('MAIL_TRANSPORT', 'mail'); - -// SMTP configuration to use when the "smtp" transport is chosen -define('MAIL_SMTP_HOSTNAME', ''); -define('MAIL_SMTP_PORT', 25); -define('MAIL_SMTP_USERNAME', ''); -define('MAIL_SMTP_PASSWORD', ''); -define('MAIL_SMTP_ENCRYPTION', null); // Valid values are "null", "ssl" or "tls" - -// Sendmail command to use when the transport is "sendmail" -define('MAIL_SENDMAIL_COMMAND', '/usr/sbin/sendmail -bs'); -``` - -Database settings ------------------ - -```php -// Database driver: sqlite, mysql or postgres (sqlite by default) -define('DB_DRIVER', 'sqlite'); - -// Mysql/Postgres username -define('DB_USERNAME', 'root'); - -// Mysql/Postgres password -define('DB_PASSWORD', ''); - -// Mysql/Postgres hostname -define('DB_HOSTNAME', 'localhost'); - -// Mysql/Postgres database name -define('DB_NAME', 'kanboard'); - -// Mysql/Postgres custom port (null = default port) -define('DB_PORT', null); -``` - -LDAP settings -------------- - -```php -// Enable LDAP authentication (false by default) -define('LDAP_AUTH', false); - -// LDAP server hostname -define('LDAP_SERVER', ''); - -// LDAP server port (389 by default) -define('LDAP_PORT', 389); - -// By default, require certificate to be verified for ldaps:// style URL. Set to false to skip the verification. -define('LDAP_SSL_VERIFY', true); - -// Enable LDAP START_TLS -define('LDAP_START_TLS', false); - -// LDAP bind type: "anonymous", "user" (use the given user/password from the form) and "proxy" (a specific user to browse the LDAP directory) -define('LDAP_BIND_TYPE', 'anonymous'); - -// LDAP username to connect with. null for anonymous bind (by default). -// Or for user bind type, you can use a pattern: %s@kanboard.local -define('LDAP_USERNAME', null); - -// LDAP password to connect with. null for anonymous bind (by default). -define('LDAP_PASSWORD', null); - -// LDAP account base, i.e. root of all user account -// Example: ou=People,dc=example,dc=com -define('LDAP_ACCOUNT_BASE', ''); - -// LDAP query pattern to use when searching for a user account -// Example for ActiveDirectory: '(&(objectClass=user)(sAMAccountName=%s))' -// Example for OpenLDAP: 'uid=%s' -define('LDAP_USER_PATTERN', ''); - -// Name of an attribute of the user account object which should be used as the full name of the user. -define('LDAP_ACCOUNT_FULLNAME', 'displayname'); - -// Name of an attribute of the user account object which should be used as the email of the user. -define('LDAP_ACCOUNT_EMAIL', 'mail'); - -// Name of an attribute of the user account object which should be used as the id of the user. -// Example for ActiveDirectory: 'samaccountname' -// Example for OpenLDAP: 'uid' -define('LDAP_ACCOUNT_ID', 'samaccountname'); - -// By default Kanboard lowercase the ldap username to avoid duplicate users (the database is case sensitive) -// Set to true if you want to preserve the case -define('LDAP_USERNAME_CASE_SENSITIVE', false); - -// Automatically create user account -define('LDAP_ACCOUNT_CREATION', true); -``` - -Google Authentication settings ------------------------------- - -```php -// Enable/disable Google authentication -define('GOOGLE_AUTH', false); - -// Google client id (Get this value from the Google developer console) -define('GOOGLE_CLIENT_ID', ''); - -// Google client secret key (Get this value from the Google developer console) -define('GOOGLE_CLIENT_SECRET', ''); -``` - -Github Authentication settings ------------------------------- - -```php -// Enable/disable GitHub authentication -define('GITHUB_AUTH', false); - -// GitHub client id (Copy it from your settings -> Applications -> Developer applications) -define('GITHUB_CLIENT_ID', ''); - -// GitHub client secret key (Copy it from your settings -> Applications -> Developer applications) -define('GITHUB_CLIENT_SECRET', ''); -``` - -Reverse-Proxy Authentication settings -------------------------------------- - -```php -// Enable/disable the reverse proxy authentication -define('REVERSE_PROXY_AUTH', false); - -// Header name to use for the username -define('REVERSE_PROXY_USER_HEADER', 'REMOTE_USER'); - -// Username of the admin, by default blank -define('REVERSE_PROXY_DEFAULT_ADMIN', ''); - -// Default domain to use for setting the email address -define('REVERSE_PROXY_DEFAULT_DOMAIN', ''); -``` - -RememberMe Authentication settings ----------------------------------- - -```php -// Enable/disable remember me authentication -define('REMEMBER_ME_AUTH', true); -``` - -Secure HTTP headers settings ----------------------------- - -```php -// Enable or disable "Strict-Transport-Security" HTTP header -define('ENABLE_HSTS', true); - -// Enable or disable "X-Frame-Options: DENY" HTTP header -define('ENABLE_XFRAME', true); -``` - -Bruteforce protection ---------------------- - -```php -// Enable captcha after 3 authentication failure -define('BRUTEFORCE_CAPTCHA', 3); - -// Lock the account after 6 authentication failure -define('BRUTEFORCE_LOCKDOWN', 6); - -// Lock account duration in minute -define('BRUTEFORCE_LOCKDOWN_DURATION', 15); -``` - -Session -------- - -```php -// Session duration in second (0 = until the browser is closed) -// See http://php.net/manual/en/session.configuration.php#ini.session.cookie-lifetime -define('SESSION_DURATION', 0); -``` - -Various settings ----------------- - -```php -// Escape html inside markdown text -define('MARKDOWN_ESCAPE_HTML', true); - -// API alternative authentication header, the default is HTTP Basic Authentication defined in RFC2617 -define('API_AUTHENTICATION_HEADER', ''); - -// Hide login form, useful if all your users use Google/Github/ReverseProxy authentication -define('HIDE_LOGIN_FORM', false); -``` diff --git a/docs/contributing.markdown b/docs/contributing.markdown deleted file mode 100644 index 955ea5cd..00000000 --- a/docs/contributing.markdown +++ /dev/null @@ -1,69 +0,0 @@ -Contributor Guidelines -====================== - -How can I help? ---------------- - -Kanboard is not perfect but there is many ways to help: - -- Give feedback -- Report bugs -- Add or update translations -- Improve the documentation -- Writing code -- Tell your friends that Kanboard is awesome :) - -Before doing any large undertaking, open a new issue and explain your proposal. - -I want to give feedback ------------------------ - -- You think something should be improved (user interface, feature request) -- Check if your idea is not already proposed -- Open a new issue -- Describe your idea -- You can also up vote with +1 on existing proposals - -I want to report a bug ----------------------- - -- Check if the issue is not already reported -- Open a new ticket -- Explain what is broken -- Describe how to reproduce the bug -- Describe your environment (Kanboard version, OS, web server, PHP version, database version, hosting type) - -I want to translate Kanboard ----------------------------- - -Kanboard is translated in many languages. -However, translations are not complete, take look at the [translation guide to contribute](http://kanboard.net/documentation/translations). - -I want to improve the documentation ------------------------------------ - -- You think something is not clear, there is grammatical errors, typo errors, anything. -- The documentation is written in Markdown and stored in the folder `docs`. -- Edit the file and send a pull-request. -- The documentation on the official website is synchronized with the repository. - -I want to contribute to the code --------------------------------- - -Pull-requests are always welcome, however to be accepted you have to follow those directives: - -- **Before doing any large change or design proposal, open a new ticket to start a discussion.** -- If you want to add a new feature, respect the philosophy behind Kanboard. **We focus on simplicity**, we don't want to have a bloated software. -- The same apply for the user interface, **simplicity and efficiency**. -- Send only one pull-request per feature or bug fix, your patch will be merged into one single commit in the master branch. -- Make sure the [unit tests pass](tests.markdown). -- Respect the [coding standards](coding-standards.makrdown). -- Write maintainable code, avoid code duplication, use PHP good practices. - -In any case, if you are not sure about something open a new ticket. - -Tell your friends that Kanboard is awesome :) ---------------------------------------------- - -If you use Kanboard, spread the word around you. -Tell them that free and open source software are cool :) diff --git a/docs/create-tasks-by-email.markdown b/docs/create-tasks-by-email.markdown deleted file mode 100644 index 46dae480..00000000 --- a/docs/create-tasks-by-email.markdown +++ /dev/null @@ -1,44 +0,0 @@ -Create tasks by email -===================== - -You can create tasks directly by sending an email. - -At the moment, Kanboard is integrated with 3 external services: - -- [Mailgun](http://kanboard.net/documentation/mailgun) -- [Sendgrid](http://kanboard.net/documentation/sendgrid) -- [Postmark](http://kanboard.net/documentation/postmark) - -These services handle incoming emails without having to configure any SMTP server. - -When an email is received, Kanboard receive the message on a specific end-point. -All complicated works are already handled by those services. - -Incoming emails workflow ------------------------- - -1. You send an email to a specific address, by example **something+myproject@inbound.mydomain.tld** -2. Your email is forwarded to the third-party SMTP servers -3. The SMTP provider call the Kanboard webhook with the email in JSON or multipart/form-data formats -4. Kanboard parse the received email and create the task to the right project - -Note: New tasks are automatically created in the first column. - -Email format ------------- - -- The local part of the email address must use the plus separator, by example **kanboard+project123** -- The string defined after the plus sign must match a project identifier, by example **project123** is the identifier of the project **Project 123** -- The email subject becomes the task title -- The email body becomes the task description (Markdown format) - -Incoming emails can be written in text or HTML formats. -**Kanboard is able to convert simple HTML emails to Markdown**. - -Security and requirements -------------------------- - -- The Kanboard webhook is protected by a random token -- The sender email address must match a Kanboard user -- The Kanboard project must have a unique identifier, by example **MYPROJECT** -- The Kanboard user must be member of the project diff --git a/docs/creating-projects.markdown b/docs/creating-projects.markdown deleted file mode 100644 index c4d80eb0..00000000 --- a/docs/creating-projects.markdown +++ /dev/null @@ -1,31 +0,0 @@ -Creating projects -================= - -Kanboard can handle multiple projects. There are two kinds of project: - -- Project with mutliple users (you work in team) -- Private project for a single user - -Creating projects for multiple users -------------------------------------- - -- Only administrators can create those projects -- User management is available - -From the dashboard, click on the link **New project**. -Then the form appears: - -![Project creation form](http://kanboard.net/screenshots/documentation/project-creation-form.png) - -It's very easy, you just have to find a name for your project! - -Creating a private project --------------------------- - -- Everybody can create a private project -- There is **NO** user management -- Only the owner and administrators can access to the project - -From the dashboard, click on the link **New private project**. - -Note: project names must be unique across the application. diff --git a/docs/creating-tasks.markdown b/docs/creating-tasks.markdown deleted file mode 100644 index afcc5ecb..00000000 --- a/docs/creating-tasks.markdown +++ /dev/null @@ -1,27 +0,0 @@ -Creating tasks -============== - -From the board, click on the plus sign next to the column name: - -![Task creation from the board](http://kanboard.net/screenshots/documentation/task-creation-board.png) - -Then the task creation form appears: - -![Task creation form](http://kanboard.net/screenshots/documentation/task-creation-form.png) - -The only mandatory field is the title. - -Field description: - -- **Title**: The title of your task, that will be displayed on the board. -- **Description**: Allow you to add more information about the task, the content can be written in [Markdown](http://kanboard.net/documentation/syntax-guide). -- **Create another task**: Check this box if you want to create a similar task (fields will be prefilled). -- **Assignee**: The person that will work on the task. -- **Category**: Only one category can be assign to a task. -- **Column**: The column where the task will be created, your task will be positioned at the bottom. -- **Color**: Choose the color of the card. -- **Complexity**: Used in agile project management (Scrum), the complexity or story points is a number that tells the team how hard the story is. Often, people use the fibonacci series. -- **Original Estimate**: Estimation in hours to complete the tasks. -- **Due Date**: Overdue tasks will have a red due date and upcoming due dates will be black on the board. Several date format are accepted in addition to the date picker. - -With the preview link, you can see the task description converted from the Markdown syntax. \ No newline at end of file diff --git a/docs/currency-rate.markdown b/docs/currency-rate.markdown deleted file mode 100644 index b959e4d1..00000000 --- a/docs/currency-rate.markdown +++ /dev/null @@ -1,11 +0,0 @@ -Currency Rate -============== - -Since each user can have a predefined hourly rate in different currency. -If you have to handle multiple currencies, you define here the rate according to the reference currency. - -This feature is used for project budget calculation. - -![Currency Rate](http://kanboard.net/screenshots/documentation/currency-rate.png) - -Currency rate settings are located in **Settings > Currency rates**. \ No newline at end of file diff --git a/docs/debian-installation.markdown b/docs/debian-installation.markdown deleted file mode 100644 index 147fe452..00000000 --- a/docs/debian-installation.markdown +++ /dev/null @@ -1,63 +0,0 @@ -How to install Kanboard on Debian? -================================== - -Debian 8 (Jessie) ------------------ - -Install Apache and PHP: - -```bash -apt-get update -apt-get install -y php5 php5-sqlite php5-gd unzip -service apache2 restart -``` - -Install Kanboard: - -```bash -cd /var/www/html -wget http://kanboard.net/kanboard-latest.zip -unzip kanboard-latest.zip -chown -R www-data:www-data kanboard/data -rm kanboard-latest.zip -``` - -Debian 7 (Wheezy) ------------------ - -Install Apache and PHP: - -```bash -apt-get update -apt-get install -y php5 php5-sqlite php5-gd unzip -``` - -Install Kanboard: - -```bash -cd /var/www -wget http://kanboard.net/kanboard-latest.zip -unzip kanboard-latest.zip -chown -R www-data:www-data kanboard/data -rm kanboard-latest.zip -``` - -Debian 6 (Squeeze) ------------------- - -Install Apache and PHP: - -```bash -apt-get update -apt-get install -y libapache2-mod-php5 php5-sqlite php5-gd unzip -``` - -Install Kanboard: - -```bash -cd /var/www -wget http://kanboard.net/kanboard-latest.zip -unzip kanboard-latest.zip -chown -R www-data:www-data kanboard/data -rm kanboard-latest.zip -``` diff --git a/docs/docker.markdown b/docs/docker.markdown deleted file mode 100644 index 44f3b976..00000000 --- a/docs/docker.markdown +++ /dev/null @@ -1,47 +0,0 @@ -How to run Kanboard with Docker? -================================ - -Kanboard can run easily with [Docker](https://www.docker.com). -There is a `Dockerfile` in the repository to build your own container. - -Use the automated build ------------------------ - -Every new commit on the repository trigger a new build on [Docker Hub](https://registry.hub.docker.com/u/kanboard/kanboard/). - -```bash -docker pull kanboard/kanboard -docker run -d --name kanboard -p 80:80 -t kanboard/kanboard:latest -``` - -The tag **latest** is the **development version** of Kanboard, use at your own risk. - -Build your own Docker image ---------------------------- - -Clone the Kanboard repository and run the following command: - -```bash -docker build -t youruser/kanboard:master . -``` - -To run your image in background on the port 80: - -```bash -docker run -d --name kanboard -p 80:80 -t youruser/kanboard:master -``` - -Store your data on a volume ---------------------------- - -By default Kanboard will store attachments and the Sqlite database in the directory data. Run this command to use a custom volume path: - -```bash -docker run -d --name kanboard -v /your/local/data/folder:/var/www/html/data -p 80:80 -t kanboard/kanboard:master -``` - -References ----------- - -- [Official Kanboard images](https://registry.hub.docker.com/u/kanboard/kanboard/) -- [Docker documentation](https://docs.docker.com/) diff --git a/docs/duplicate-move-tasks.markdown b/docs/duplicate-move-tasks.markdown deleted file mode 100644 index dcb01df5..00000000 --- a/docs/duplicate-move-tasks.markdown +++ /dev/null @@ -1,58 +0,0 @@ -Duplicate and move tasks -======================== - -Duplicate a task into the same project --------------------------------------- - -Go to the task view and choose **Duplicate** on the left. - -![Task Duplication](http://kanboard.net/screenshots/documentation/task-duplication.png) - -A new task will be created with the same properties as the original. - -Duplicate a task to another project ------------------------------------ - -Go to the task view and choose **Duplicate to another project**. - -![Task Duplication Another Project](http://kanboard.net/screenshots/documentation/task-duplication-another-project.png) - -Only projects where you are member will be shown in the dropdown. - -Before to copy the tasks, Kanboard will ask you the destination properties that are not common between the source and destination project. - -Basically, you need to define: - -- The destination swimlane -- The column -- The category -- The assignee - -Move a task to another project ------------------------------- - -Go to the task view and choose **Move to another project**. - -Moving a task to another project work in the same way as the duplication, you have to choose the new properties of the task. - -List of fields duplicated -------------------------- - -Here are the list of properties duplicated: - -- title -- description -- date_due -- color_id -- project_id -- column_id -- owner_id -- score -- category_id -- time_estimated -- swimlane_id -- recurrence_status -- recurrence_trigger -- recurrence_factor -- recurrence_timeframe -- recurrence_basedate diff --git a/docs/editing-projects.markdown b/docs/editing-projects.markdown deleted file mode 100644 index c615fd53..00000000 --- a/docs/editing-projects.markdown +++ /dev/null @@ -1,16 +0,0 @@ -Editing projects -================ - -Projects can be renamed and disabled at any time. - -To rename a project, just click on the link "Edit project" on the left. - -![Project edition](http://kanboard.net/screenshots/documentation/project-edition.png) - -Administrators can convert a private project to a multiple users project by changing the checkbox "Private project". -You can also do the opposite action converting a multiple users project to a private project. - -This checkbox **enable or disable user managements for the project**. - -Note: When you make a project private, all existing users will still have access to the project. -Adjust the list of users according to your needs. diff --git a/docs/email-configuration.markdown b/docs/email-configuration.markdown deleted file mode 100644 index c66996c6..00000000 --- a/docs/email-configuration.markdown +++ /dev/null @@ -1,173 +0,0 @@ -Email configuration -=================== - -User settings -------------- - -To receive email notifications, users of Kanboard must have: - -- Activated notifications in their profile -- Have a valid email address in their profile -- Be member of the project that will trigger notifications - -Note: The logged user who performs the action doesn't receive any notifications, only other project members. - -Email transports ----------------- - -There are several email transports available: - -- SMTP -- Sendmail -- PHP native mail function -- Mailgun -- Postmark -- Sendgrid - -Server settings ---------------- - -By default, Kanboard will use the bundled PHP mail function to send emails. -Usually that require no configuration if your server can already send emails. - -However, it's possible to use other methods, the SMTP protocol and Sendmail. - -### SMTP configuration - -Rename the file `config.default.php` to `config.php` and change these values: - -```php -// We choose "smtp" as mail transport -define('MAIL_TRANSPORT', 'smtp'); - -// We define our server settings -define('MAIL_SMTP_HOSTNAME', 'mail.example.com'); -define('MAIL_SMTP_PORT', 25); - -// Credentials for authentication on the SMTP server (not mandatory) -define('MAIL_SMTP_USERNAME', 'username'); -define('MAIL_SMTP_PASSWORD', 'super password'); -``` - -It's also possible to use a secure connection, TLS or SSL: - -```php -define('MAIL_SMTP_ENCRYPTION', 'ssl'); // Valid values are "null", "ssl" or "tls" -``` - -### Sendmail configuration - -By default the sendmail command will be `/usr/sbin/sendmail -bs` but you can customize that in your config file. - -Example: - -```php -// We choose "sendmail" as mail transport -define('MAIL_TRANSPORT', 'sendmail'); - -// If you need to change the sendmail command, replace the value -define('MAIL_SENDMAIL_COMMAND', '/usr/sbin/sendmail -bs'); -``` - -### PHP native mail function - -This is the default configuration: - -```php -define('MAIL_TRANSPORT', 'mail'); -``` - -### Mailgun HTTP API - -You can use the HTTP API of Mailgun to send emails. - -Configuration: - -```php -// We choose "mailgun" as mail transport -define('MAIL_TRANSPORT', 'mailgun'); - -// Mailgun API key -define('MAILGUN_API_TOKEN', 'YOUR_API_KEY'); - -// Mailgun domain name -define('MAILGUN_DOMAIN', 'YOUR_DOMAIN_CONFIGURED_IN_MAILGUN'); - -// Be sure to use the sender email address configured in Mailgun -define('MAIL_FROM', 'sender-address-configured-in-mailgun@example.org'); -``` - -### Postmark HTTP API - -Postmark is a third-party email service. -If you already use the Postmark integration to receive emails in Kanboard you can use the same provider to send email too. - -This system use their HTTP API instead of the SMTP protocol. - -Here are the required settings for this configuration: - -```php -// We choose "postmark" as mail transport -define('MAIL_TRANSPORT', 'postmark'); - -// Copy and paste your Postmark API token -define('POSTMARK_API_TOKEN', 'COPY HERE YOUR POSTMARK API TOKEN'); - -// Be sure to use the Postmark configured sender email address -define('MAIL_FROM', 'sender-address-configured-in-postmark@example.org'); -``` - -### Sendgrid HTTP API - -You can use the HTTP API of Sendgrid to send emails. - -Configuration: - -```php -// We choose "sendgrid" as mail transport -define('MAIL_TRANSPORT', 'sendgrid'); - -// Sendgrid username -define('SENDGRID_API_USER', 'YOUR_SENDGRID_USERNAME'); - -// Sendgrid password -define('SENDGRID_API_KEY', 'YOUR_SENDGRID_PASSWORD'); -``` - -### The sender email address - -By default, emails will use the sender address `notifications@kanboard.local`. -It's not possible to reply to this address. - -You can customize this address by changing the value of the constant `MAIL_FROM` in your config file. - -```php -define('MAIL_FROM', 'kanboard@mydomain.tld'); -``` - -That can be useful if your SMTP server configuration doesn't accept the default address. - -### How to display a link to the task in notifications? - -To do that, you have to specify the URL of your Kanboard installation in your [Application Settings](http://kanboard.net/documentation/application-configuration). -By default, nothing is defined, so no links will be displayed. - -Examples: - -- http://demo.kanboard.net/ -- http://myserver/kanboard/ -- http://kanboard.mydomain.com/ - -Don't forget the ending slash `/`. - -You need to define that manually because Kanboard cannot guess the URL from a command line script and some people have very specific configuration. - -Troubleshooting ---------------- - -If no emails are send and you are sure that everything is configured correctly: - -- Check your spam folder -- Enable the debug mode and check the debug file `data/debug.log`, you should see the exact error -- Be sure that your server or your hosting provider allow you to send emails -- If you use SeLinux, allow PHP to send emails diff --git a/docs/faq.markdown b/docs/faq.markdown deleted file mode 100644 index 3d542a30..00000000 --- a/docs/faq.markdown +++ /dev/null @@ -1,113 +0,0 @@ -Frequently Asked Questions -========================== - -Can you recommend a web hosting provider for Kanboard? ------------------------------------------------------- - -Kanboard works well with any great VPS hosting provider such as [Digital Ocean](https://www.digitalocean.com/?refcode=4b541f47aae4), -[Linode](https://www.linode.com/?r=4e381ac8a61116f40c60dc7438acc719610d8b11) or [Gandi](https://www.gandi.net/). - -To have the best performances, choose a provider with fast disk I/O because Kanboard use Sqlite by default. -Avoid hosting providers that use a shared NFS mount point. - -I get a blank page after installing or upgrading Kanboard ---------------------------------------------------------- - -- Check if you have installed all requirements on your server -- Check if the files have the correct permissions -- If you use php-fpm and opcode caching, reload the process to be sure to clear the cache -- Enable PHP error logging in your php.ini -- Check the PHP and Apache error logs you should see the exact error - - -Page not found and the url seems wrong (&amp;) ----------------------------------------------- - -- The url looks like `/?controller=auth&action=login&redirect_query=` instead of `?controller=auth&action=login&redirect_query=` -- Kanboard returns a "Page not found" error - -This issue come from your PHP configuration, the value of `arg_separator.output` is not the PHP's default, there is different ways to fix that: - -Change the value directly in your `php.ini` if you have the permission: - -``` -arg_separator.output = "&" -``` - -Override the value with a `.htaccess`: - -``` -php_value arg_separator.output "&" -``` - -Otherwise Kanboard will try to override the value directly in PHP. - - -Known issues with eAccelerator ------------------------------- - -Kanboard doesn't work very well with [eAccelerator](http://eaccelerator.net). -The issue caused can be a blank page or an Apache crash: - -``` -[Wed Mar 05 21:36:56 2014] [notice] child pid 22630 exit signal Segmentation fault (11) -``` - -The best way to avoid this issue is to disable eAccelerator or define manually which files you want to cache with the config parameter `eaccelerator.filter`. - -The project [eAccelerator seems dead and not updated since 2012](https://github.com/eaccelerator/eaccelerator/commits/master). -We recommend to switch to the last version of PHP because it's bundled with [OPcache](http://php.net/manual/en/intro.opcache.php). - - -Why the minimum requirement is PHP 5.3.3? ------------------------------------------ - -Kanboard use the function `password_hash()` to crypt passwords but it's available only for PHP >= 5.5. - -However, there is a backport for [older versions of PHP](https://github.com/ircmaxell/password_compat#requirements). -This library require at least PHP 5.3.7 to work correctly. - -Apparently, Centos and Debian backports security patches so PHP 5.3.3 should be ok. - -Kanboard v1.0.10 and v1.0.11 requires at least PHP 5.3.7 but this change has been reverted to be compatible with PHP 5.3.3 with Kanboard >= v1.0.12 - - -How to test Kanboard with the PHP built-in web server? ------------------------------------------------------- - -If you don't want to install a web server like Apache on localhost. You can test with the [embedded web server of PHP](http://www.php.net/manual/en/features.commandline.webserver.php): - -```bash -unzip kanboard-VERSION.zip -cd kanboard -php -S localhost:8000 -open http://localhost:8000/ -``` - - -How to migrate my tasks from Wunderlist? ----------------------------------------- - -You can use an external tool to import automatically your tasks and lists from Wunderlist to Kanboard. - -This is a command line script made by a contributor of Kanboard. -It's simple, quick and dirty but it works :) - -More information here: - -- [Wunderlist](http://www.wunderlist.com/) -- - - -How to install Kanboard on Yunohost? ------------------------------------- - -[YunoHost](https://yunohost.org/) is a server operating system aiming to make self-hosting accessible to everyone. - -There is a [package to install Kanboard on Yunohost easily](https://github.com/mbugeia/kanboard_ynh). - - -Are there some tutorials about Kanboard in other languages? ------------------------------------------------------------ - -- [German article series about Kanboard](http://demaya.de/wp/2014/07/kanboard-eine-jira-alternative-im-detail-installation/) diff --git a/docs/freebsd-installation.markdown b/docs/freebsd-installation.markdown deleted file mode 100644 index 84b35ad8..00000000 --- a/docs/freebsd-installation.markdown +++ /dev/null @@ -1,127 +0,0 @@ -FreeBSD 10 Installation -======================= - -Install from packages ---------------------- - -```bash -$ pkg update -$ pkg upgrade -$ pkg install apache24 mod_php56 kanboard -``` - -Enable Apache in your `/etc/rc.conf`: - -```bash -$ echo apache24_enable="YES" >> /etc/rc.conf -``` - -Set up PHP for Apache: - -```bash -$ echo "AddType application/x-httpd-php .php" >> /usr/local/etc/apache24/Includes/php.conf -$ echo "DirectoryIndex index.php index.html" >> /usr/local/etc/apache24/Includes/php.conf -``` - -Then start Apache: - -```bash -$ service apache24 start -``` - -Add symlink to Kanboard folder into your Apache docroot: - -```bash -cd /usr/local/www/apache24/data -ln -s /usr/local/www/kanboard -``` - -Go to http://your.server.domain.tld/kanboard and enjoy! - -*Notes*: -- If you want to use additional features like LDAP integration etc. -please install proper PHP module using pkg. -- You may have to adjust the permissions of the folder data - -Installing from ports ---------------------- - -Generally 3 elements have to be installed: - -- Apache -- mod_php for Apache -- Kanboard - -Fetch and extract ports... - -```bash -$ portsnap fetch -$ portsnap extract -``` - -or update already existing: - -```bash -$ portsnap fetch -$ portsnap update -``` - -More details regarding portsnap can be found in the [FreeBSD Handbook](https://www.freebsd.org/doc/handbook/ports-using.html). - -Install Apache: - -```bash -$ cd /usr/ports/www/apache24 -$ make install clean -``` -Enable Apache in your `/etc/rc.conf`: - -```bash -$ echo apache24_enable="YES" >> /etc/rc.conf -``` - -Install mod_php for Apache: - -```bash -$ cd /usr/ports/www/mod_php5 -$ make install clean -``` - -Install Kanboard form ports: - -```bash -$ cd /usr/ports/www/kanboard -$ make install clean -``` - -Set up PHP for Apache: - -```bash -$ echo "AddType application/x-httpd-php .php" >> /usr/local/etc/apache24/Includes/php.conf -$ echo "DirectoryIndex index.php index.html" >> /usr/local/etc/apache24/Includes/php.conf -``` - -Then start Apache: - -```bash -$ service apache24 start -``` - -Go to http://your.server.domain.tld/kanboard and enjoy! - -*Note*: -If you want to use additional features like LDAP integration etc. -please install proper PHP module from `lang/php5-extensions`. - -Manual installation -------------------- - -As of version 1.0.16 Kanboard can be found in FreeBSD ports -there is no need to install it manually. - -Please note ------------ - -Port is being hosted on [bitbucket](https://bitbucket.org/if0/freebsd-kanboard/). Feel free to comment, -fork and suggest updates! - \ No newline at end of file diff --git a/docs/gantt-chart-projects.markdown b/docs/gantt-chart-projects.markdown deleted file mode 100644 index 450b8bfc..00000000 --- a/docs/gantt-chart-projects.markdown +++ /dev/null @@ -1,16 +0,0 @@ -Gantt chart for all projects -============================ - -The goal of this Gantt chart is to display an overview of all projects based on the start and end dates. - -- This Gantt chart is available in the project management section -- Only project administrators and administrators can access to this section -- Project administrators will see only projects where they are members - -![Gantt Chart for all projects](http://kanboard.net/screenshots/documentation/gantt-chart-all-projects.png) - -- The **start date** and the **end date** of projects are used to draw the chart -- Horizontal bars can be resized and moved horizontally with your mouse -- There is no vertical drag and drop -- Project bars are displayed in black when there is no start or end date defined -- The information tooltip show the list of project managers and standard members diff --git a/docs/gantt-chart-tasks.markdown b/docs/gantt-chart-tasks.markdown deleted file mode 100644 index b84c8046..00000000 --- a/docs/gantt-chart-tasks.markdown +++ /dev/null @@ -1,20 +0,0 @@ -Gantt chart for tasks -====================== - -The goal of this Gantt chart is to display a time based overview of the tasks for a given project. - -- The Gantt chart is available from the the action menu -- Only project managers can access to this section - -![Gantt Chart](http://kanboard.net/screenshots/documentation/gantt-chart-project.png) - -- The **start date** and the **due date** of tasks are used to draw the chart -- Tasks can be resized and moved horizontally with your mouse -- There is no vertical drag and drop -- The bar is the same color as the task -- Each bar display a progression status in percentage, this percentage is calculated by using the column position on the board -- To fit with the Kanban model, tasks can be ordered by the board positions or by start date -- New tasks created from this view will be displayed on the board at the position 1 in the first column -- Tasks are displayed in black when there is no start or due date defined - -![Task not defined](http://kanboard.net/screenshots/documentation/gantt-chart-not-defined.png) diff --git a/docs/github-authentication.markdown b/docs/github-authentication.markdown deleted file mode 100644 index ba0f371f..00000000 --- a/docs/github-authentication.markdown +++ /dev/null @@ -1,80 +0,0 @@ -Github Authentication -===================== - -Requirements ------------- - -OAuth Github API credentials (available in your [Settings > Applications > Developer applications](https://github.com/settings/applications)) - -How does this work? -------------------- - -The Github authentication in Kanboard uses the [OAuth 2.0](http://oauth.net/2/) protocol, so any user of Kanboard can be linked to a Github account. - -That means you can use your Github account to login on Kanboard. - -How to link a Github account ----------------------------- - -1. Go to your user profile -2. Click on **External accounts** -3. Click on the link **Link my Github Account** -4. You are redirected to the **Github Authorize application form** -5. Authorize Kanboard by clicking on the button **Accept** -6. Your account is now linked - -Now, on the login page you can be authenticated in one click with the link **Login with my Github Account**. - -Your name and email are automatically updated from your Github Account if defined. - -Installation instructions -------------------------- - -### Setting up OAuth 2.0 - -- On Github, go to the page [Register a new OAuth application](https://github.com/settings/applications/new) -- Just follow the [official Github documentation](https://developer.github.com/guides/basics-of-authentication/#registering-your-app) -- In Kanboard, you can get the **callback url** in **Settings > Integrations > Github Authentication** - -### Setting up Kanboard - -Either create a new `config.php` file or rename the `config.default.php` file and set the following values: - -```php -// Enable/disable Github authentication -define('GITHUB_AUTH', true); - -// Github client id (Copy it from your settings -> Applications -> Developer applications) -define('GITHUB_CLIENT_ID', 'YOUR_GITHUB_CLIENT_ID'); - -// Github client secret key (Copy it from your settings -> Applications -> Developer applications) -define('GITHUB_CLIENT_SECRET', 'YOUR_GITHUB_CLIENT_SECRET'); -``` - -### Github Entreprise - -To use this authentication method with Github Enterprise you have to change the default urls. - -Replace these values by your self-hosted instance of Github: - -```php -// Github oauth2 authorize url -define('GITHUB_OAUTH_AUTHORIZE_URL', 'https://github.com/login/oauth/authorize'); - -// Github oauth2 token url -define('GITHUB_OAUTH_TOKEN_URL', 'https://github.com/login/oauth/access_token'); - -// Github API url (don't forget the slash at the end) -define('GITHUB_API_URL', 'https://api.github.com/'); -``` - -Notes ------ - -Kanboard uses these information from your public Github profile: - -- Full name -- Public email address -- Github unique id - -The Github unique id is used to link the local user account and the Github account. diff --git a/docs/github-webhooks.markdown b/docs/github-webhooks.markdown deleted file mode 100644 index a20b5a18..00000000 --- a/docs/github-webhooks.markdown +++ /dev/null @@ -1,99 +0,0 @@ -Github webhooks integration -=========================== - -Kanboard can be synchronized with Github. -Currently, it's only a one-way synchronization: Github to Kanboard. - -Github webhooks are plugged to Kanboard automatic actions. -When an event occurs on Github, an action can be performed on Kanboard. - -List of available events ------------------------- - -- Github commit received -- Github issue opened -- Github issue closed -- Github issue reopened -- Github issue assignee change -- Github issue label change -- Github issue comment created - -List of available actions -------------------------- - -- Create a task from an external provider -- Change the assignee based on an external username -- Change the category based on an external label -- Create a comment from an external provider -- Close a task -- Open a task - -Configuration on Github ------------------------ - -Go to your project settings page, on the left choose "Webhooks & Services", then click on the button "Add webhook". - -![Github configuration](http://kanboard.net/screenshots/documentation/github-webhooks.png) - -- **Payload url**: Copy and paste the link from the Kanboard project settings (section **Integrations > Github**). -- Select **"Send me everything"** - -![Github webhook](http://kanboard.net/screenshots/documentation/kanboard-github-webhooks.png) - -Each time an event happens, Github will send an event to Kanboard now. -The Kanboard webhook url is protected by a random token. - -Everything else is handled by automatic actions in your Kanboard project settings. - -Examples --------- - -### Close a Kanboard task when a commit pushed to Github - -- Choose the event: **Github commit received** -- Choose the action: **Close the task** - -When one or more commits are sent to Github, Kanboard will receive the information, each commit message with a task number included will be closed. - -Example: - -- Commit message: "Fix bug #1234" -- That will close the Kanboard task #1234 - -### Create a Kanboard task when a new issue is opened on Github - -- Choose the event: **Github issue opened** -- Choose the action: **Create a task from an external provider** - -When a task is created from a Github issue, the link to the issue is added to the description and the task have a new field named "Reference" (this is the Github ticket number). - -### Close a Kanboard task when an issue is closed on Github - -- Choose the event: **Github issue closed** -- Choose the action: **Close the task** - -### Reopen a Kanboard task when an issue is reopened on Github - -- Choose the event: **Github issue reopened** -- Choose the action: **Open the task** - -### Assign a task to a Kanboard user when an issue is assigned on Github - -- Choose the event: **Github issue assignee change** -- Choose the action: **Change the assignee based on an external username** - -Note: The username must be the same between Github and Kanboard and the user must be member of the project. - -### Assign a category when an issue is tagged on Github - -- Choose the event: **Github issue label change** -- Choose the action: **Change the category based on an external label** -- Define the label and the category - -### Create a comment on Kanboard when an issue is commented on Github - -- Choose the event: **Github issue comment created** -- Choose the action: **Create a comment from an external provider** - -If the username is the same between Github and Kanboard the comment author will be assigned, otherwise there is no author. -The user also have to be member of the project in Kanboard. diff --git a/docs/gitlab-authentication.markdown b/docs/gitlab-authentication.markdown deleted file mode 100644 index 3cf6d283..00000000 --- a/docs/gitlab-authentication.markdown +++ /dev/null @@ -1,78 +0,0 @@ -Gitlab Authentication -===================== - -Requirements ------------- - -- Account on [Gitlab.com](https://gitlab.com) or you own self-hosted Gitlab instance -- Have Kanboard registered as application in Gitlab - -How does this work? -------------------- - -The Gitlab authentication in Kanboard uses the [OAuth 2.0](http://oauth.net/2/) protocol, so any user of Kanboard can be linked to a Gitlab account. - -That means you can use your Gitlab account to login on Kanboard. - -How to link a Gitlab account ----------------------------- - -1. Go to your user profile -2. Click on **External accounts** -3. Click on the link **Link my Gitlab Account** -4. You are redirected to the **Gitlab authorization form** -5. Authorize Kanboard by clicking on the button **Accept** -6. Your account is now linked - -Now, on the login page you can be authenticated in one click with the link **Login with my Gitlab Account**. - -Your name and email are automatically updated from your Gitlab Account if defined. - -Installation instructions -------------------------- - -### Setting up OAuth 2.0 - -- On Gitlab, register a new application by following the [official documentation](http://doc.gitlab.com/ce/integration/oauth_provider.html) -- In Kanboard, you can get the **callback url** in **Settings > Integrations > Gitlab Authentication**, just copy and paste the url - -### Setting up Kanboard - -Either create a new `config.php` file or rename the `config.default.php` file and set the following values: - -```php -// Enable/disable Gitlab authentication -define('GITLAB_AUTH', true); - -// Gitlab application id -define('GITLAB_CLIENT_ID', 'YOUR_APPLICATION_ID'); - -// Gitlab application secret -define('GITLAB_CLIENT_SECRET', 'YOUR_APPLICATION_SECRET'); -``` - -### Custom endpoints for self-hosted Gitlab - -Change these default values if you use a self-hosted instance of Gitlab: - -```php -// Gitlab oauth2 authorize url -define('GITLAB_OAUTH_AUTHORIZE_URL', 'https://gitlab.com/oauth/authorize'); - -// Gitlab oauth2 token url -define('GITLAB_OAUTH_TOKEN_URL', 'https://gitlab.com/oauth/token'); - -// Gitlab API url endpoint (don't forget the slash at the end) -define('GITLAB_API_URL', 'https://gitlab.com/api/v3/'); -``` - -Notes ------ - -Kanboard uses these information from your Gitlab profile: - -- Full name -- Email address -- Gitlab unique id - -The Gitlab unique id is used to link the local user account and the Gitlab account. diff --git a/docs/gitlab-webhooks.markdown b/docs/gitlab-webhooks.markdown deleted file mode 100644 index 9d9ecaf5..00000000 --- a/docs/gitlab-webhooks.markdown +++ /dev/null @@ -1,65 +0,0 @@ -Gitlab webhooks -=============== - -Gitlab events can be connected to Kanboard automatic actions. - -List of supported events ------------------------- - -- Gitlab commit received -- Gitlab issue opened -- Gitlab issue closed -- Gitlab issue comment created - -List of supported actions -------------------------- - -- Create a task from an external provider -- Close a task -- Create a comment from an external provider - -Configuration -------------- - -![Gitlab configuration](http://kanboard.net/screenshots/documentation/gitlab-webhooks.png) - -1. On Kanboard, go to the project settings and choose the section **Integrations** -2. Copy the Gitlab webhook url -3. On Gitlab, go to the project settings and go to the section **Webhooks** -4. Check the boxes **Push Events**, **Comments** and **Issues Events** -5. Paste the url and save - -Examples --------- - -### Close a Kanboard task when a commit pushed to Gitlab - -- Choose the event: **Gitlab commit received** -- Choose the action: **Close the task** - -When one or more commits are sent to Gitlab, Kanboard will receive the information, each commit message with a task number included will be closed. - -Example: - -- Commit message: "Fix bug #1234" -- That will close the Kanboard task #1234 - -### Create a Kanboard task when a new issue is opened on Gitlab - -- Choose the event: **Gitlab issue opened** -- Choose the action: **Create a task from an external provider** - -When a task is created from a Gitlab issue, the link to the issue is added to the description and the task have a new field named "Reference" (this is the Gitlab ticket number). - -### Close a Kanboard task when an issue is closed on Gitlab - -- Choose the event: **Gitlab issue closed** -- Choose the action: **Close the task** - -### Create a comment on Kanboard when an issue is commented on Gitlab - -- Choose the event: **Gitlab issue comment created** -- Choose the action: **Create a comment from an external provider** - -If the username is the same between Gitlab and Kanboard the comment author will be assigned, otherwise there is no author. -The user also have to be member of the project in Kanboard. \ No newline at end of file diff --git a/docs/google-authentication.markdown b/docs/google-authentication.markdown deleted file mode 100644 index 0f4f3ec1..00000000 --- a/docs/google-authentication.markdown +++ /dev/null @@ -1,64 +0,0 @@ -Google Authentication -===================== - -Requirements ------------- - -OAuth Google API credentials (available in the Google Developer Console) - -How does this work? -------------------- - -- The Google authentication in Kanboard use the OAuth 2.0 protocol -- Any user account in Kanboard can be linked to a Google Account -- When a Kanboard user account is linked to Google, you can login with one click - -Procedure to link a Google Account ----------------------------------- - -1. Go to your user profile -2. Click on **External accounts** -3. Click on the link **Link my Google Account** -4. You are redirected to the **Google Consent screen** -5. Authorize Kanboard by clicking on the button **Accept** -6. Your account is now linked - -Now, on the login page you can be authenticated in one click with the link **Login with my Google Account**. - -Your name and email are automatically updated from your Google Account. - -Installation instructions -------------------------- - -### Setting up OAuth 2.0 in Google Developer Console - -- Follow the [official Google documentation](https://developers.google.com/accounts/docs/OAuth2Login#appsetup) to create a new application -- In Kanboard, you can get the **redirect url** in **Settings > Integrations > Google Authentication** - -### Setting up Kanboad - -Create a custom `config.php` file or copy the `config.default.php` file: - -```php - Integrations > Hipchat** -- To send notifications for only some projects, go to **Project settings > Integrations > Hipchat** - -Each project can send notifications to a separate room. - -Send notifications to a room ------------------------------ - -Example of notifications: - -![Hipchat notification](http://kanboard.net/screenshots/documentation/hipchat-notification.png) - -This feature use the room notification token system of Hipchat. - -### Hipchat configuration - -![Hipchat room token](http://kanboard.net/screenshots/documentation/hipchat-room-token.png) - -1. Go to to **My account** -2. Click on the tab **Rooms** and select the room you want to send the notifications -3. On the left, choose **Tokens** -4. Enter a label, by example "Kanboard" and save - -### Kanboard configuration - -![Hipchat settings](http://kanboard.net/screenshots/documentation/hipchat-settings.png) - -1. Go to **Settings > Integrations > Hipchat** or **Project settings > Integrations > Hipchat** -2. Replace the API url if you use the self-hosted version of Hipchat -3. Set the room name or the room API ID -4. Copy and paste the token generated previously - -Now, Kanboard events will be sent to the Hipchat room. diff --git a/docs/hourly-rate.markdown b/docs/hourly-rate.markdown deleted file mode 100644 index 172f2f47..00000000 --- a/docs/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/docs/ical.markdown b/docs/ical.markdown deleted file mode 100644 index 5c52bf82..00000000 --- a/docs/ical.markdown +++ /dev/null @@ -1,78 +0,0 @@ -Syncing your calendars -====================== - -Kanboard supports iCal feeds for projects and users. -This feature allow you to import Kanboard tasks in almost any calendar program (by example Microsoft Outlook, Apple Calendar, Mozilla Thunderbird and Google Calendar). - -Calendar subscriptions are **read-only** access, you cannot create tasks from an external calendar software. -The Calendar feed export follow the iCal standard. - -Note: Only tasks within the date range of -2 months to +6 months are exported to the iCalendar feed. - -Project calendars ------------------ - -- Each project have its own calendar. -- The subscription link is unique per project, the link is activated when you enable the public access of your project: **Project settings > Public access**. -- This calendar show only tasks for the selected project. - -User calendars --------------- - -- Each user have its own calendar. -- The subscription link is unique per user, the link is activated when you enable the public access of your user: **User profile > Public access**. -- This calendar show tasks assigned to the user for all projects. - -Adding your Kanboard calendar to Apple Calendar ------------------------------------------------ - -- Open Calendar -- Select **File > New Calendar Subscription** -- Copy and paste the iCal feed url from Kanboard - -![Add iCal subscription](http://kanboard.net/screenshots/documentation/apple-calendar-add-subscription.png) - -- You can choose to synchronize the calendar with iCloud to be available across all your devices -- Don't forget to select the refresh frequency - -![Edit iCal subscription](http://kanboard.net/screenshots/documentation/apple-calendar-edit-subscription.png) - -Adding your Kanboard calendar to Microsoft Outlook --------------------------------------------------- - -![Outlook Add Internet Calendar](http://kanboard.net/screenshots/documentation/outlook-add-subscription.png) - -- Open Outlook -- Select **Open Calendar > From Internet** -- Copy and paste the iCal feed url from Kanboard - -![Outlook Edit Internet Calendar](http://kanboard.net/screenshots/documentation/outlook-edit-subscription.png) - -Adding your Kanboard calendar to Mozilla Thunderbird ----------------------------------------------------- - -- Install the Add-on **Lightning** to add the calendar support to Thunderbird -- Click on **File > New Calendar** -- In the dialog box, choose **On the Network** - -![Thunderbird Step 1](http://kanboard.net/screenshots/documentation/thunderbird-new-calendar-step1.png) - -- Choose the format iCalendar -- Copy and paste the iCal feed url from Kanboard - -![Thunderbird Step 2](http://kanboard.net/screenshots/documentation/thunderbird-new-calendar-step2.png) - -- Choose the colors and other settings and finally save - -Adding your Kanboard calendar to Google Calendar ------------------------------------------------- - -- Click the down-arrow next to **Other calendars**. -- Select **Add by URL** from the menu. -- Copy and paste the iCal feed url from Kanboard - -![Google Calendar](http://kanboard.net/screenshots/documentation/google-calendar-add-subscription.png) - -Your Kanboard calendar can also be available from your Android device if you enable the synchronization. - -Note: According to the Google Support, external calendars are not refreshed very often, [read the documentation](https://support.google.com/calendar/answer/37100?hl=en&ref_topic=1672445). diff --git a/docs/index.markdown b/docs/index.markdown deleted file mode 100644 index 10db316a..00000000 --- a/docs/index.markdown +++ /dev/null @@ -1,138 +0,0 @@ -Documentation -============= - -Using Kanboard --------------- - -### Introduction - -- [What is Kanban?](what-is-kanban.markdown) -- [Kanban vs Todo Lists and Scrum](kanban-vs-todo-and-scrum.markdown) -- [Usage examples](usage-examples.markdown) - -### Using the board - -- [Board, Calendar and List views](project-views.markdown) -- [Collapsed and expanded mode](board-collapsed-expanded.markdown) -- [Horizontal scrolling and compact mode](board-horizontal-scrolling-and-compact-view.markdown) -- [Show and hide columns](board-show-hide-columns.markdown) - -### Working with projects - -- [Creating projects](creating-projects.markdown) -- [Editing projects](editing-projects.markdown) -- [Sharing boards and tasks](sharing-projects.markdown) -- [Automatic actions](automatic-actions.markdown) -- [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) - -### Working with tasks - -- [Creating tasks](creating-tasks.markdown) -- [Closing tasks](closing-tasks.markdown) -- [Duplicate and move tasks](duplicate-move-tasks.markdown) -- [Adding screenshots](screenshots.markdown) -- [Task links](task-links.markdown) -- [Transitions](transitions.markdown) -- [Time tracking](time-tracking.markdown) -- [Recurring tasks](recurring-tasks.markdown) -- [Create tasks by email](create-tasks-by-email.markdown) -- [Subtasks](subtasks.markdown) -- [Analytics for tasks](analytics-tasks.markdown) - -### Working with users - -- [User management](user-management.markdown) -- [Notifications](notifications.markdown) -- [Hourly rate](hourly-rate.markdown) -- [Timetable](timetable.markdown) -- [Two factor authentication](2fa.markdown) - -### Settings - -- [Keyboard shortcuts](keyboard-shortcuts.markdown) -- [Application settings](application-configuration.markdown) -- [Project settings](project-configuration.markdown) -- [Board settings](board-configuration.markdown) -- [Calendar settings](calendar-configuration.markdown) -- [Link settings](link-labels.markdown) -- [Currency rate](currency-rate.markdown) - -### Integrations - -- [Bitbucket webhooks](bitbucket-webhooks.markdown) -- [Github webhooks](github-webhooks.markdown) -- [Gitlab webhooks](gitlab-webhooks.markdown) -- [Hipchat](hipchat.markdown) -- [Jabber](jabber.markdown) -- [Mailgun](mailgun.markdown) -- [Sendgrid](sendgrid.markdown) -- [Slack](slack.markdown) -- [Postmark](postmark.markdown) -- [iCalendar subscriptions](ical.markdown) -- [RSS/Atom subscriptions](rss.markdown) -- [Json-RPC API](api-json-rpc.markdown) -- [Webhooks](webhooks.markdown) - -### More - -- [Advanced Search Syntax](search.markdown) -- [Command line interface](cli.markdown) -- [Syntax guide](syntax-guide.markdown) -- [Bruteforce protection](bruteforce-protection.markdown) -- [Frequently asked questions](faq.markdown) - -Technical details ------------------ - -### Installation - -- [Recommended configuration](recommended-configuration.markdown) -- [Installation instructions](installation.markdown) -- [Upgrade Kanboard to a new version](update.markdown) -- [Installation on Ubuntu](ubuntu-installation.markdown) -- [Installation on Debian](debian-installation.markdown) -- [Installation on Centos](centos-installation.markdown) -- [Installation on FreeBSD](freebsd-installation.markdown) -- [Installation on Windows Server with IIS](windows-iis-installation.markdown) -- [Installation on Windows Server with Apache](windows-apache-installation.markdown) -- [Installation on Heroku](heroku.markdown) -- [Example with Nginx + HTTPS + SPDY + PHP-FPM](nginx-ssl-php-fpm.markdown) -- [Run Kanboard with Docker](docker.markdown) - -### Configuration - -- [Config file](config.markdown) -- [Email configuration](email-configuration.markdown) -- [URL rewriting](nice-urls.markdown) - -### Database - -- [Sqlite database management](sqlite-database.markdown) -- [How to use Mysql](mysql-configuration.markdown) -- [How to use Postgresql](postgresql-configuration.markdown) - -### Authentication - -- [LDAP authentication](ldap-authentication.markdown) -- [Google authentication](google-authentication.markdown) -- [Github authentication](github-authentication.markdown) -- [Gitlab authentication](gitlab-authentication.markdown) -- [Reverse proxy authentication](reverse-proxy-authentication.markdown) - -### Contributors - -- [Contributor guide](contributing.markdown) -- [Translations](translations.markdown) -- [Coding standards](coding-standards.markdown) -- [Running tests](tests.markdown) -- [Build assets](assets.markdown) -- [Run Kanboard with Vagrant](vagrant.markdown) - -The documentation is written in [Markdown](http://en.wikipedia.org/wiki/Markdown). -If you want to improve the documentation, just send a pull-request. diff --git a/docs/installation.markdown b/docs/installation.markdown deleted file mode 100644 index 53e7095b..00000000 --- a/docs/installation.markdown +++ /dev/null @@ -1,40 +0,0 @@ -Installation -============ - -Requirements ------------- - -- Apache or Nginx -- PHP >= 5.3.3 (Kanboard is compatible with PHP 5.3, 5.4, 5.5, 5.6 and 7.0) -- PHP extensions required: mbstring, gd and pdo_sqlite -- A modern web browser - -From the archive (stable version) ---------------------------------- - -1. You must have a web server with PHP installed -2. Download the source code and copy the directory `kanboard` where you want -3. Check if the directory `data` is writeable -4. With your browser go to -5. The default login and password is **admin/admin** -6. Start to use the software -7. Don't forget to change your password! - -Note: The folder data is the location where Kanboard stores uploaded files as well as the Sqlite database. - -From the repository (development version) ------------------------------------------ - -You must install [composer](https://getcomposer.org/) to use this method. - -1. `git clone https://github.com/fguillot/kanboard.git` -2. `composer install` -3. Go to the third step just above - -Note: This method will install the **current development version**, use at your own risk. - -Security --------- - -- Don't forget to change the default user/password -- Don't allow everybody to access to the directory `data` from the URL. There is already a `.htaccess` for Apache but nothing for Nginx. diff --git a/docs/jabber.markdown b/docs/jabber.markdown deleted file mode 100644 index fe365168..00000000 --- a/docs/jabber.markdown +++ /dev/null @@ -1,34 +0,0 @@ -Jabber/XMPP integration -======================= - -You can send notifications to a Jabber room for all projects or only for specific projects. - -- To send notifications for all projects, go to **Settings > Integrations > Jabber** -- To send notifications for only some projects, go to **Project settings > Integrations > Jabber** - -Each project can send notifications to a separate room. - -## Example of notification - -Here an example with the Jabber client Adium: - -![Jabber notification](http://kanboard.net/screenshots/documentation/jabber-notification.png) - -## Configuration - -![Jabber settings](http://kanboard.net/screenshots/documentation/jabber-settings.png) - -1. Go to **Settings > Integrations > Jabber** or **Project settings > Integrations > Jabber** -2. **XMPP server address**: URL of the XMPP server, example: **tcp://172.28.128.3:5222** -3. **Jabber domain**: The **"to"** attribute of the XMPP protocol, example: **example.com** -4. **Username**: The Jabber username used by Kanboard, example: **kanboard** -5. **Password**: The Jabber password -6. **Jabber nickname**: The nickname used to connect to the room -7. **Multi-user chat room**: The address of the room, example: **demo@conference.example.com** - -Now, Kanboard events will be sent to the Jabber conference room. - -## Troubleshooting - -- Enable the debug mode -- All connection errors with the XMPP server are recorded in the log files `data/debug.log` or syslog diff --git a/docs/kanban-vs-todo-and-scrum.markdown b/docs/kanban-vs-todo-and-scrum.markdown deleted file mode 100644 index 3d53023a..00000000 --- a/docs/kanban-vs-todo-and-scrum.markdown +++ /dev/null @@ -1,37 +0,0 @@ -Kanban vs Todo lists and Scrum -============================== - -Kanban vs Todo lists --------------------- - -### Todo lists: - -- Single phase (just a list of items) -- Multitasking possible (not efficient) - -### Kanban: - -- Multiple phases, each column represent a step -- Bring focus and avoid multitasking because you can set a work in progress limit per column - -Kanban vs Scrum ---------------- - -### Scrum: - -- Sprints are time-boxed, usually 2 or 4 weeks -- Do not allow changes during the iteration -- Estimation is required -- Uses velocity as default metric -- Scrum board is cleared between each sprint -- Scrum has predefined roles like scrum master, product owner and the team -- A lot of meetings: planning, backlog grooming, daily stand-up, retrospective - -### Kanban: - -- Continuous flow -- Changes can be made at anytime -- Estimation is optional -- Use lead and cycle time to measure performance -- Kanban board is persistent -- Kanban doesn't impose strict constraints or meetings, process is more flexible diff --git a/docs/keyboard-shortcuts.markdown b/docs/keyboard-shortcuts.markdown deleted file mode 100644 index 959b1522..00000000 --- a/docs/keyboard-shortcuts.markdown +++ /dev/null @@ -1,24 +0,0 @@ -Keyboard shortcuts -================== - -Board/Calendar/List view ------------------------- - -- Switch to the board view = **v b** -- Switch to the calendar view = **v c** -- Switch to the list view = **v l** - -Board view ----------- - -- New task = **n** -- Expand/collapse tasks = **s** -- Compact/wide view = **c** - -Application ------------ - -- Open board switcher = **b** -- Go to the search/filter box = **f** -- Close dialog box = **ESC** -- Submit a form = **CTRL+ENTER** or **⌘+ENTER** \ No newline at end of file diff --git a/docs/ldap-authentication.markdown b/docs/ldap-authentication.markdown deleted file mode 100644 index 53b3d012..00000000 --- a/docs/ldap-authentication.markdown +++ /dev/null @@ -1,234 +0,0 @@ -LDAP authentication -=================== - -Requirements ------------- - -- LDAP extension for PHP -- LDAP server: - - OpenLDAP - - Microsoft Active Directory - - Novell eDirectory - -Workflow --------- - -When the LDAP authentication is activated, the login process work like that: - -1. Try first to authenticate the user by using the database -2. If the user is not found inside the database, a LDAP authentication is performed -3. If the LDAP authentication is successful, by default a local user is created automatically with no password and marked as LDAP user. - -### Differences between a local user and a LDAP user are the following: - -- LDAP users have no local passwords -- LDAP users can't modify their password with the user interface -- By default, all LDAP users have no admin privileges -- To become administrator, a LDAP user must be promoted by another administrator - -The full name and the email address are automatically fetched from the LDAP server. - -Configuration -------------- - -You have to create a custom config file named `config.php` (you can also use the template `config.default.php`). -This file must be stored in the root directory of Kanboard. - -### LDAP bind type - -There is 3 possible ways to browse the LDAP directory: - -#### Anonymous browsing - -```php -define('LDAP_BIND_TYPE', 'anonymous'); -define('LDAP_USERNAME', null); -define('LDAP_PASSWORD', null); -``` - -This is the default value but some LDAP servers don't allow that. - -#### Proxy user - -A specific user is used to browse the LDAP directory. -By example, Novell eDirectory use that method. - -```php -define('LDAP_BIND_TYPE', 'proxy'); -define('LDAP_USERNAME', 'my proxy user'); -define('LDAP_PASSWORD', 'my proxy password'); -``` - -#### User credentials - -This method use the credentials provided by the end-user. -By example, Microsoft Active Directory doesn't allow anonymous browsing by default and if you don't want to use a proxy user you can use this method. - -```php -define('LDAP_BIND_TYPE', 'user'); -define('LDAP_USERNAME', '%s@mydomain.local'); -define('LDAP_PASSWORD', null); -``` - -Here, the `LDAP_USERNAME` is use to define a replacement pattern: - -```php -define('LDAP_USERNAME', '%s@mydomain.local'); - -// Another way to do the same: - -define('LDAP_USERNAME', 'MYDOMAIN\\%s'); -``` - -### Example for Microsoft Active Directory - -Let's say we have a domain `KANBOARD` (kanboard.local) and the primary controller is `myserver.kanboard.local`. -Microsoft Active Directory doesn't allow anonymous binding by default. - -First example with a proxy user: - -```php - Link settings**) - -![Link Labels](http://kanboard.net/screenshots/documentation/link-labels.png) - -Each label may have an opposite label defined. -If there is no opposite, the label is considered bi-directionnal. - -![Link Label Creation](http://kanboard.net/screenshots/documentation/link-label-creation.png) diff --git a/docs/mailgun.markdown b/docs/mailgun.markdown deleted file mode 100644 index 6465903a..00000000 --- a/docs/mailgun.markdown +++ /dev/null @@ -1,28 +0,0 @@ -Mailgun -======= - -You can use the service [Mailgun](http://www.mailgun.com/) to create tasks directly by email. - -This integration works with the inbound email service of Mailgun (routes). -Kanboard use a webhook to handle incoming emails. - -The [incoming email workflow is described here](create-tasks-by-email.markdown). - -Mailgun configuration ---------------------- - -Create a new route in the web interface or via the API ([official documentation](https://documentation.mailgun.com/user_manual.html#routes)), here an example: - -``` -match_recipient("^kanboard\+(.*)@mydomain.tld$") -forward("https://mykanboard/?controller=webhook&action=mailgun&token=mytoken") -``` - -The Kanboard webhook url is displayed in **Settings > Integrations > Mailgun** - -Kanboard configuration ----------------------- - -1. Be sure that your users have an email address in their profiles -2. Assign a project identifier to the desired projects: **Project settings > Edit** -3. Try to send an email to your project diff --git a/docs/mysql-configuration.markdown b/docs/mysql-configuration.markdown deleted file mode 100644 index eef1e125..00000000 --- a/docs/mysql-configuration.markdown +++ /dev/null @@ -1,44 +0,0 @@ -How to use Mysql or MariaDB instead of Sqlite -============================================= - -By default Kanboard use Sqlite to stores its data. -However it's possible to use Mysql or MariaDB instead of Sqlite. - -Requirements ------------- - -- Mysql server -- The PHP extension `pdo_mysql` installed (Debian/Ubuntu: `apt-get install php5-mysql`) - -Note: Kanboard is tested with **Mysql >= 5.5 and MariaDB >= 10.0** - -Mysql configuration -------------------- - -### Create a database - -The first step is to create a database on your Mysql server. -By example, you can do that with the command line mysql client: - -```sql -CREATE DATABASE kanboard; -``` - -### Create a config file - -The file `config.php` should contains those values: - -```php - kanboard.pem -``` - -Copy the certificates in a new directory: - -```bash -mkdir /etc/nginx/ssl -cp kanboard.pem /etc/nginx/ssl -cp kanboard.key.nopass /etc/nginx/ssl -chmod 400 /etc/nginx/ssl/* -``` - -Configure Nginx ---------------- - -Now, we can customize our installation, start to modify the main configuration file `/etc/nginx/nginx.conf`: - -```nginx -user www-data; -worker_processes auto; -pid /run/nginx.pid; - -events { - worker_connections 1024; -} - -http { - sendfile on; - tcp_nopush on; - tcp_nodelay on; - keepalive_timeout 65; - types_hash_max_size 2048; - server_tokens off; - - # SSL shared cache between workers - ssl_session_cache shared:SSL:10m; - ssl_session_timeout 10m; - - # We disable weak protocols and ciphers - ssl_protocols TLSv1 TLSv1.1 TLSv1.2; - ssl_prefer_server_ciphers on; - ssl_ciphers HIGH:!SSLv2:!MEDIUM:!LOW:!EXP:!RC4:!DSS:!aNULL:@STRENGTH; - - include /etc/nginx/mime.types; - default_type application/octet-stream; - - access_log /var/log/nginx/access.log; - error_log /var/log/nginx/error.log; - - # We enable the Gzip compression for some mime types - gzip on; - gzip_disable "msie6"; - gzip_vary on; - gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; - - include /etc/nginx/conf.d/*.conf; - include /etc/nginx/sites-enabled/*; -} -``` - -Create a new virtual host for Kanboard `/etc/nginx/sites-available/kanboard` - - -```nginx -server { - # We also enable the SPDY protocol - listen 443 ssl spdy; - - # Our SSL certificate - ssl on; - ssl_certificate /etc/nginx/ssl/kanboard.pem; - ssl_certificate_key /etc/nginx/ssl/kanboard.key.nopass; - - # You can change the default root directory here - root /usr/share/nginx/html; - - index index.php; - - # Your domain name - server_name localhost; - - # The maximum body size, useful for file uploads - client_max_body_size 10M; - - location / { - try_files $uri $uri/ =404; - } - - error_page 404 /404.html; - error_page 500 502 503 504 /50x.html; - location = /50x.html { - root /usr/share/nginx/html; - } - - # PHP-FPM configuration - location ~ \.php$ { - try_files $uri =404; - fastcgi_split_path_info ^(.+\.php)(/.+)$; - fastcgi_pass unix:/var/run/php5-fpm.sock; - fastcgi_index index.php; - include fastcgi.conf; - } - - # Deny access to the directory data - location ~* /data { - deny all; - return 404; - } - - # Deny access to .htaccess - location ~ /\.ht { - deny all; - return 404; - } -} -``` - -Now it's time to test our setup - -```bash -# Disable the default virtual host -sudo unlink /etc/nginx/sites-enabled/default - -# Add our default virtual host -sudo ln -s /etc/nginx/sites-available/kanboard /etc/nginx/sites-enabled/kanboard - -# Check the config file -sudo nginx -t -nginx: the configuration file /etc/nginx/nginx.conf syntax is ok -nginx: configuration file /etc/nginx/nginx.conf test is successful - -# Restart nginx -sudo service nginx restart -``` - -Kanboard Installation ---------------------- - -You can install Kanboard in a subdirectory or not, it's up to you. - -```bash -cd /usr/share/nginx/html -sudo wget http://kanboard.net/kanboard-latest.zip -sudo unzip kanboard-latest.zip -sudo chown -R www-data:www-data kanboard/data -sudo rm kanboard-latest.zip -``` - -Now, you should be able to use Kanboard with your web browser. diff --git a/docs/nice-urls.markdown b/docs/nice-urls.markdown deleted file mode 100644 index 38f7c41d..00000000 --- a/docs/nice-urls.markdown +++ /dev/null @@ -1,36 +0,0 @@ -URL rewriting -============= - -Kanboard is able to work indifferently with url rewriting enabled or not. - -- Example of URL rewritten: `/board/123` -- Otherwise: `?controller=board&action=show&project_id=123` - -If you use Kanboard with Apache and with the mode rewrite enabled, nice urls will be used automatically. - -URL Shortcuts -------------- - -- Go to the task #123: **/t/123** -- Go to the board of the project #2: **/b/2** -- Go to the project calendar #5: **/c/5** -- Go to the list view of the project #8: **/l/8** -- Go to the project settings for the project id #42: **/p/42** - -Configuration -------------- - -By default, Kanboard will check if the Apache mode rewrite is enabled. - -To avoid the automatic detection of url rewriting from the web server, you can enable this feature in your config file: - -``` -define('ENABLE_URL_REWRITE', true); -``` - -When this constant is at `true`: - -- URLs generated from command line tools will be also converted -- If you use another web server than Apache, by example Nginx or Microsoft IIS, you have to configure yourself the url rewriting - -Note: Kanboard always fallback to old school urls when it's not configured, this configuration is optional. diff --git a/docs/notifications.markdown b/docs/notifications.markdown deleted file mode 100644 index f42c66cb..00000000 --- a/docs/notifications.markdown +++ /dev/null @@ -1,30 +0,0 @@ -Notifications -============= - -Kanboard is able to send notifications through several channels: - -- Email -- Jabber/XMPP -- Hipchat -- Slack - -Actually, Jabber/Hipchat/Slack notifications are sent to a room or group channel because they are configured at the project level. -However, email notifications are sent to an individual. - -User notifications ------------------- - -Each user must enable the notifications in their profile: **User Profile > Email notifications**. It's disabled by default. - -You need of course a valid email address in you profile and the application must be configured to send emails. - -![Notifications](http://kanboard.net/screenshots/documentation/notifications.png) - -For each project your are member, you can choose to receive notifications for: - -- All tasks -- Only for tasks assigned to you -- Only for tasks created by you -- Only for tasks created by you and assigned to you - -You can also select only some projects, by default it's all projects where you are member. diff --git a/docs/postgresql-configuration.markdown b/docs/postgresql-configuration.markdown deleted file mode 100644 index 3c07ff16..00000000 --- a/docs/postgresql-configuration.markdown +++ /dev/null @@ -1,40 +0,0 @@ -Postgresql configuration -======================== - -By default, Kanboard use Sqlite to store its data but it's also possible to use Postgresql. - -Requirements ------------- - -- A Postgresql server already installed and configured -- The PHP extension `pdo_pgsql` installed (Debian/Ubuntu: `apt-get install php5-pgsql`) - -Note: Kanboard is tested with **Postgresql 9.3 and 9.4** - -Configuration -------------- - -### Create an empty database with the command `pgsql`: - -```sql -CREATE DATABASE kanboard; -``` - -### Create a config file - -The file `config.php` should contains those values: - -```php - Integrations > Postmark** - -Kanboard configuration ----------------------- - -1. Be sure that your users have an email address in their profiles -2. Assign a project identifier to the desired projects: **Project settings > Edit** -3. Try to send an email to your project - -Troubleshootings ----------------- - -- Test the webhook url from the Postmark console, you should have a status code `200 OK` diff --git a/docs/project-configuration.markdown b/docs/project-configuration.markdown deleted file mode 100644 index 252ace67..00000000 --- a/docs/project-configuration.markdown +++ /dev/null @@ -1,42 +0,0 @@ -Project settings -================ - -Go to the menu **Settings**, then choose **Project settings** on the left. - -![Project settings](http://kanboard.net/screenshots/documentation/project-settings.png) - -### Default columns for new projects - -You can change the default column names here. -It's useful if you always create projects with the same columns. - -Each column name must be separated by a comma. - -By default, Kanboard use those column names: Backlog, Ready, Work in progress and Done. - -### Default categories for new projects - -Categories are not global to the application but attached to a project. -Each project can have different categories. - -However, if you always create the same categories for all your projects, you can define here the list of categories to create automatically. - -### Allow only one subtask in progress at the same time for a user - -When this option is enabled, a user can work with only one subtask at the time. - -If another subtask have the status "in progress", the user will see this dialog box: - -![Subtask user restriction](http://kanboard.net/screenshots/documentation/subtask-user-restriction.png) - -### Trigger automatically subtask time tracking - -- If enabled, when a subtask status is changed to "in progress", the timer will start automatically. -- Disable this option if you don't use time tracking. - -### Include closed tasks in the cumulative flow diagram - -- If enabled, closed tasks will be included in the cumulative flow diagram. -- If disabled, only open tasks will be included. -- This option affect the column "total" of the table "project_daily_column_stats" - diff --git a/docs/project-permissions.markdown b/docs/project-permissions.markdown deleted file mode 100644 index d4aa88e3..00000000 --- a/docs/project-permissions.markdown +++ /dev/null @@ -1,49 +0,0 @@ -Project permissions -=================== - -A project can have two kinds of people: **project managers** and **project members**. - -- Project managers can manage the configuration of the project and access to the reports. -- Project members can only do basic operations (create or move tasks). - -When you create a new project, you are automatically assigned as a project manager. - -Kanboard administrators can access to everything but they are not necessary project members or managers. Those permissions are defined at the project level. - -Permissions for each role -------------------------- - -### Project members - -- Use the board (create, move and edit tasks) -- Remove only tasks created by themselves - -### Project managers - -- Use the board -- Configure the project - - Share, rename, duplicate and disable the project - - Manage swimlanes, categories, columns and users - - Edit automatic actions -- CSV Exports -- Remove tasks of any project members -- Access to the analytics section - -They **cannot remove the project**. - -Manage users and permissions ----------------------------- - -To define project roles, go to the **project configuration page** then click on **User management**. - -### User management - -![Project permissions](http://kanboard.net/screenshots/documentation/project-permissions.png) - -From there, you can choose to add new members, change the role or revoke user access. - -### Allow everybody - -If you choose to allow everybody (all Kanboard users), the project is considered public. - -That means there is no role management anymore. Permissions per user cannot be applied. diff --git a/docs/project-views.markdown b/docs/project-views.markdown deleted file mode 100644 index a5e9e1f9..00000000 --- a/docs/project-views.markdown +++ /dev/null @@ -1,37 +0,0 @@ -Board, Calendar and List views -============================== - -For each project, tasks can be visualized with several views: **Board, Calendar and List**. Each view show the result of the filter box at the top. The search engine use the [advanced syntax](search.markdown). - -Board view ----------- - -![Board view](http://kanboard.net/screenshots/documentation/board-view.png) - -- With this view you can drag and drop tasks between columns easily. -- You can also use the keyboard shortcut **"v b"** to switch to the board view. -- Tasks with a shadow are recently modified. - -![Board Task Limit](http://kanboard.net/screenshots/documentation/board-task-limit.png) - -When the task limit is reached for a column, the background becomes red. That means there are too many tasks in progress at the same time. - -[Learn more about board configuration](board-configuration.markdown) - -Calendar view --------------- - -![Calendar view](http://kanboard.net/screenshots/documentation/calendar-view.png) - -- With this view you can visualize tasks with a due date. -- Depending of the settings, you can also see tasks in progress. -- You can also use the keyboard shortcut **"v c"** to switch to the calendar view. -- [Learn more about calendar configuration](calendar-configuration.markdown) - -List view --------------- - -![List view](http://kanboard.net/screenshots/documentation/list-view.png) - -- With this view all results of your search are displayed in a table. -- You can also use the keyboard shortcut **"v l"** to switch to the list view. diff --git a/docs/recommended-configuration.markdown b/docs/recommended-configuration.markdown deleted file mode 100644 index 35ed652d..00000000 --- a/docs/recommended-configuration.markdown +++ /dev/null @@ -1,36 +0,0 @@ -Recommended Configuration -========================= - -Server side ------------ - -- Modern Linux/Unix operating system: **Ubuntu/Debian or FreeBSD** -- Most recent version of PHP and Apache (Kanboard is compatible with PHP 5.3, 5.4, 5.5, 5.6 and 7.0) -- Use the Sqlite database only when you have a disk with fast I/O (SSD disks) otherwise use Mysql or Postgresql - -Client side ------------ - -- Use a modern browser: **Mozilla Firefox or Google Chrome or Safari** - -Tested configurations ---------------------- - -The following configurations are tested with Kanboard but that doesn't mean all features are available: - -### Server - -- Ubuntu 14.04 LTS -- Debian 6, 7 and 8 -- Centos 6.x and 7.0 -- Windows 2012 Server -- Windows 2008 Server - -### Desktops - -- Last version of Mozilla Firefox, Safari and Google Chrome -- Microsoft Internet Explorer 11 - -### Tablets - -- iPad mini 3 diff --git a/docs/recurring-tasks.markdown b/docs/recurring-tasks.markdown deleted file mode 100644 index b1de8d05..00000000 --- a/docs/recurring-tasks.markdown +++ /dev/null @@ -1,24 +0,0 @@ -Recurring tasks -=============== - -To fit with the Kanban methodology, the recurring tasks are not based on a date but on board events. - -- Recurring tasks are duplicated to the first column of the board when the selected events occurs -- The due date can be recalculated automatically -- Each task records the task id of the parent task that created it and the child task created - -Configuration -------------- - -Go to the task view page or use the dropdown menu on the board, then select **Edit recurrence**. - -![Recurring task](http://kanboard.net/screenshots/documentation/recurring-tasks.png) - -There are 3 triggers that currently create a new recurring task: - -- Moving a task from the first column -- Moving a task to the last column -- Closing the task - -Due dates, if set on the current task, can be recalculated by a given factor of days, months or years. -The base date for the calculation of the new due date can be either the existing due date, or the action date. diff --git a/docs/reverse-proxy-authentication.markdown b/docs/reverse-proxy-authentication.markdown deleted file mode 100644 index 7c001f3d..00000000 --- a/docs/reverse-proxy-authentication.markdown +++ /dev/null @@ -1,64 +0,0 @@ -Reverse Proxy Authentication -============================ - -This authentication method is often used for [SSO](http://en.wikipedia.org/wiki/Single_sign-on) (Single Sign-On) especially for large organizations. - -The authentication is done by another system, Kanboard doesn't know your password and suppose you are already authenticated. - -Requirements ------------- - -- A well configured reverse proxy - -or - -- Apache auth on the same server - - -How does this work? -------------------- - -1. Your reverse proxy authenticates the user and send the username through a HTTP header. -2. Kanboard retreive the username from the request - - The user is created automatically if necessary - - Open a new Kanboard session without any prompt assuming it's valid - -Installation instructions -------------------------- - -### Setting up your reverse proxy - -This is not in the scope of this documentation. -You should check the user login is sent by the reverse proxy using a HTTP header, and find which one. - -### Setting up Kanboard - -Create a custom `config.php` file or copy the `config.default.php` file: - -```php - Public access**. - -![Disable public access](http://kanboard.net/screenshots/documentation/project-disable-sharing.png) - -Enable/disable user RSS feeds --------------------------------- - -Go to **User profile > Public access**. - -The RSS link is protected by a random token, only people who knows the url can access to the feed. \ No newline at end of file diff --git a/docs/screenshots.markdown b/docs/screenshots.markdown deleted file mode 100644 index 3ec6bc7a..00000000 --- a/docs/screenshots.markdown +++ /dev/null @@ -1,25 +0,0 @@ -Adding screenshots -================== - -You can copy and paste images directly in Kanboard to save time. -These images are uploaded as attachments to the task. - -This is especially useful for taking screenshots to describe an issue by example. - -You can add screenshots directly from the board by clicking on the dropdown menu or in the task view page. - -![Dropdown screenshot menu](http://kanboard.net/screenshots/documentation/dropdown-screenshot.png) - -To add a new image, take your screenshot and paste with CTRL+V or Command+V: - -![Screenshot page](http://kanboard.net/screenshots/documentation/task-screenshot.png) - -On Mac OS X, you can use those shortcuts to take screenshots: - -- Command-Control-Shift-3: Take a screenshot of the screen, and save it to the clipboard -- Command-Control-Shift-4, then select an area: Take a screenshot of an area and save it to the clipboard -- Command-Control-Shift-4, then space, then click a window: Take a screenshot of a window and save it to the clipboard - -There are also several third-party applications that can be used to take screenshots with annotations and shapes. - -**Note: This feature doesn't works with all browsers.** diff --git a/docs/search.markdown b/docs/search.markdown deleted file mode 100644 index 34a20bc6..00000000 --- a/docs/search.markdown +++ /dev/null @@ -1,138 +0,0 @@ -Advanced Search Syntax -====================== - -Kanboard use a simple query language for advanced search. - -Example of query ----------------- - -This example will returns all tasks assigned to me with a due date for tomorrow and a title that contains "my title": - -``` -assigne:me due:tomorrow my title -``` - -Search by task id or title --------------------------- - -- Search by task id: `#123` -- Search by task id and task title: `123` -- Search by task title: anything that don't match any search attributes - -Search by status ----------------- - -Attribute: **status** - -- Query to find open tasks: `status:open` -- Query to find closed tasks: `status:closed` - -Search by assignee ------------------- - -Attribute: **assignee** - -- Query with the full name: `assignee:"Frederic Guillot"` -- Query with the username: `assignee:fguillot` -- Multiple assignee lookup: `assignee:user1 assignee:"John Doe"` -- Query for unassigned tasks: `assignee:nobody` -- Query for my assigned tasks: `assignee:me` - -Note: Kanboard will also search in assigned subtasks with the status todo and in progress. - -Search by color ---------------- - -Attribute: **color** - -- Query to search by color id: `color:blue` -- Query to search by color name: `color:"Deep Orange"` - -Search by due date ------------------- - -Attribute: **due** - -- Search tasks due today: `due:today` -- Search tasks due tomorrow: `due:tomorrow` -- Search tasks due yesterday: `due:yesterday` -- Search tasks due with the exact date: `due:2015-06-29` - -The date must use the ISO8601 format: **YYYY-MM-DD**. - -All string formats supported by the `strtotime()` function are supported, by example `next Thursday`, `-2 days`, `+2 months`, `tomorrow`, etc... - -Operators supported with a date: - -- Greater than: **due:>2015-06-29** -- Lower than: **due:<2015-06-29** -- Greater than or equal: **due:>=2015-06-29** -- Lower than or equal: **due:<=2015-06-29** - -Search by modification date ---------------------------- - -Attribute: **modified** or **updated** - -The date formats are the same as the due date. - -There is also a filter by recently modified tasks: `modified:recently`. - -This query will use the same value as the board highlight period configured in settings. - -Search by creation date ------------------------ - -Attribute: **created** - -Works in the same way as the modification date queries. - -Search by description ---------------------- - -Attribute: **description** - -Example: `description:"text search"` - -Search by external reference ----------------------------- - -The task reference is an external id of your task, by example a ticket number from another software. - -- Find tasks with a reference: `ref:1234` or `reference:TICKET-1234` - -Search by category ------------------- - -Attribute: **category** - -- Find tasks with a specific category: `category:"Feature Request"` -- Find all tasks that have those categories: `category:"Bug" category:"Improvements"` -- Find tasks with no category assigned: `category:none` - -Search by project ------------------ - -Attribute: **project** - -- Find tasks by project name: `project:"My project name"` -- Find tasks by project id: `project:23` -- Find tasks for several projects: `project:"My project A" project:"My project B"` - -Search by column ----------------- - -Attribute: **column** - -- Find tasks by column name: `column:"Work in progress"` -- Find tasks for several columns: `column:"Backlog" column:ready` - -Search by swimlane ------------------- - -Attribute: **swimlane** - -- Find tasks by swimlane: `swimlane:"Version 42"` -- Find tasks in the default swimlane: `swimlane:default` -- Find tasks into several swimlanes: `swimlane:"Version 1.2" swimlane:"Version 1.3"` - diff --git a/docs/sendgrid.markdown b/docs/sendgrid.markdown deleted file mode 100644 index 0f307dac..00000000 --- a/docs/sendgrid.markdown +++ /dev/null @@ -1,24 +0,0 @@ -Sendgrid -======== - -You can use the service [Sendgrid](https://sendgrid.com/) to create tasks directly by email. - -This integration works with the [Parse API of Sendgrid](https://sendgrid.com/docs/API_Reference/Webhooks/parse.html). -Kanboard use a webhook to handle incoming emails. - -The [incoming email workflow is described here](create-tasks-by-email.markdown). - -Sendgrid configuration ----------------------- - -1. Create a new domain or subdomain (by example **inbound.mydomain.tld**) with a MX record that point to **mx.sendgrid.net** -2. Add your domain and the Kanboard webhook url to [the configuration page in Sendgrid](https://sendgrid.com/developer/reply) - -The Kanboard webhook url is displayed in **Settings > Integrations > Sendgrid** - -Kanboard configuration ----------------------- - -1. Be sure that your users have an email address in their profiles -2. Assign a project identifier to the desired projects: **Project settings > Edit** -3. Try to send an email to your project diff --git a/docs/sharing-projects.markdown b/docs/sharing-projects.markdown deleted file mode 100644 index 3e72071b..00000000 --- a/docs/sharing-projects.markdown +++ /dev/null @@ -1,35 +0,0 @@ -Sharing boards and tasks -======================== - -By default, boards are private but it's possible to make a board public. - -A public board can't be modified, it's a **read-only access**. -This access is protected by a random token, only people who have the right token can see the board. - -Public boards are automatically refreshed every 60 seconds. -Task details are also available in read-only. - -Usage examples: - -- Share your board with someone outside of your organization -- Display the board on a large screen in your office - -Enable public access -------------------- - -Select your project, then click on "Public access" and finally click on the button "Enable public access". - -![Enable public access](http://kanboard.net/screenshots/documentation/project-enable-sharing.png) - -When the public access is enabled, a couple of links are generated: - -- Public board view -- RSS feed subscription link -- iCalendar subscription link - -![Disable public access](http://kanboard.net/screenshots/documentation/project-disable-sharing.png) - -You can also disable the public access whenever you want. - -Each time, you enable or disable the public access a new random token is generated. -The previous links will not work anymore. diff --git a/docs/slack.markdown b/docs/slack.markdown deleted file mode 100644 index f90464e8..00000000 --- a/docs/slack.markdown +++ /dev/null @@ -1,38 +0,0 @@ -Slack integration -================= - -You can send notifications to Slack for all projects or only for specific projects. - -- To send notifications for all projects, go to **Settings > Integrations > Slack** -- To send notifications for only some projects, go to **Project settings > Integrations > Slack** - -Each project can send notifications to a separate channel. - -Send notifications to a channel -------------------------------- - -Example of notifications: - -![Slack notification](http://kanboard.net/screenshots/documentation/slack-notification.png) - -This feature use the [Incoming webhook](https://api.slack.com/incoming-webhooks) system of Slack. - -### Slack configuration - -![Slack webhook creation](http://kanboard.net/screenshots/documentation/slack-add-incoming-webhook.png) - -1. Click on the Team dropdown and choose **Configure Integrations** -2. On the list of services, scroll-down and choose **DIY Integrations & Customizations > Incoming WebHooks** -3. Copy the webhook url to the Kanboard settings page: **Settings > Integrations > Slack** or **Project settings > Integrations > Slack** - -Now, Kanboard events will be sent to the Slack channel. - -### Overriding Channel (Optional) - -Optionally you can override the channel, private group or send direct messages by filling up **Channel/Group/User** text box. Leaving it empty will post to the channel configured during webhook configuration. - -Examples: - -- Send messages to another channel: **#mychannel1** -- Send messages to a private group: **#myprivategroup1** -- Send messages directly to someone: **@anotheruser1** diff --git a/docs/sqlite-database.markdown b/docs/sqlite-database.markdown deleted file mode 100644 index 0a6a0ab6..00000000 --- a/docs/sqlite-database.markdown +++ /dev/null @@ -1,50 +0,0 @@ -Sqlite database management -========================== - -Kanboard uses Sqlite by default to store its data. -All tasks, projects and users are stored inside this database. - -Technically, the database is just a single file located inside the directory `data` and named `db.sqlite`. - -Export/Backup -------------- - -### Command line - -Doing a backup is very easy, just copy the file `data/db.sqlite` somewhere else when nobody use the software. - -### User interface - -You can also download at any time the database directly from the **settings** menu. - -The downloaded database is compressed with Gzip, the filename becomes `db.sqlite.gz`. - -Import/Restoration ------------------- - -There is actually no way to restore the database from the user interface. -The restoration must be done manually when no body use the software. - -- To restore an old backup, just replace and overwrite the actual file `data/db.sqlite`. -- To uncompress a gzipped database, execute this command from a terminal `gunzip db.sqlite.gz`. - -Optimization ------------- - -Occasionally, it's possible to optimize the database file by running the command `VACUUM`. -This command rebuild the entire database and can be used for several reasons: - -- Reduce the file size, deleting data produce empty space but doesn't change the file size. -- The database is fragmented due to frequent inserts or updates. - -### From the command line - -``` -sqlite3 data/db.sqlite 'VACUUM' -``` - -### From the user interface - -Go to the menu **settings** and click on the link **Optimize the database**. - -For more information, read the [Sqlite documentation](https://sqlite.org/lang_vacuum.html). diff --git a/docs/subtasks.markdown b/docs/subtasks.markdown deleted file mode 100644 index 6ea67284..00000000 --- a/docs/subtasks.markdown +++ /dev/null @@ -1,47 +0,0 @@ -Subtasks -======== - -Subtasks are useful to split the work of a task. - -Each subtask: - -- Can be assigned to a project member -- Have 3 different statuses: **Todo**, **In progress**, **Done** -- Have time tracking information: **time spent** and **time estimated** -- Be ordered by position - -Creating subtasks ------------------ - -From the task view, on left sidebar click on **Add a subtask**: - -![Add a subtask](http://kanboard.net/screenshots/documentation/add-subtask.png) - -You can also add quickly a subtask by entering only the title: - -![Add a subtask from the task view](http://kanboard.net/screenshots/documentation/add-subtask-shortcut.png) - -Change subtask status ---------------------- - -When you click on the subtask title the status change: - -![Subtask in progress](http://kanboard.net/screenshots/documentation/subtask-status-inprogress.png) - -The icon before the title is updated according to the status. - -![Subtask done](http://kanboard.net/screenshots/documentation/subtask-status-done.png) - -Note: When the task is closed, all subtasks are changed to the status **Done**. - -Subtask timer -------------- - -Each time a subtask is in progress, the timer is also started. The timer can be started and stopped at any time. - -The timer records the time spent on the subtask automatically. You can also change manually the value of the time spent field when you edit a subtask. - -The time calculated is rounded to the nearest quarter. This information is recorded in a separate table. - -The task time spent is updated automatically according to the sum of all subtasks time spent. - diff --git a/docs/swimlanes.markdown b/docs/swimlanes.markdown deleted file mode 100644 index 25e8b6b9..00000000 --- a/docs/swimlanes.markdown +++ /dev/null @@ -1,29 +0,0 @@ -Swimlanes -========= - -Swimlanes are horizontal separations in your board. -By example, it's useful to separate software releases, divide your tasks in different products, teams or what ever you want. - -Board with swimlanes --------------------- - -![Swimlanes Configuration](http://kanboard.net/screenshots/documentation/swimlanes.png) - -Managing swimlanes ------------------- - -- All projects have a default swimlane. -- If there is more than one swimlane, the board will show all swimlanes. -- You can drag and drop tasks between swimlanes. - -To configure swimlanes go to the **project configuration page** and choose the section **Swimlanes**. - -![Swimlanes Configuration](http://kanboard.net/screenshots/documentation/swimlanes-configuration.png) - -From there, you can add a new swimlane or rename the default one. -You can also disable and change the position of the different swimlanes. - -- The default swimlane is always on the top but you can hide it. -- Inactive swimlanes are not shown on the board. -- **Removing a swimlane doesn't remove tasks assigned to it**, those tasks will be moved to the default swimlane. - diff --git a/docs/syntax-guide.markdown b/docs/syntax-guide.markdown deleted file mode 100644 index 8b1324f0..00000000 --- a/docs/syntax-guide.markdown +++ /dev/null @@ -1,139 +0,0 @@ -Syntax Guide -============ - -Kanboard use the [Markdown syntax](http://en.wikipedia.org/wiki/Markdown) for comments or task descriptions. -Here are some examples: - -Bold and italic ----------------- - -- Bold text: Use 2 asterisks or 2 underscores -- Italic text: Use 1 asterisk or 1 underscore - -### Source -``` -This **word** is very __important__. - -And here, an *italic* word with one _underscore_. -``` - -### Result - -This **word** is very __important__. - -And here, an *italic* word with one _underscore_. - -Unordered Lists ---------------- - -Unordered list can use asterisks, minuses or pluses. - -### Source - -``` -- Item 1 -- Item 2 -- Item 3 - -or - -* Item 1 -* Item 2 -* Item 3 -``` - -### Result - -- Item 1 -- Item 2 -- Item 3 - -Ordered lists -------------- - -Ordered lists are prefixed by a number like that: - -### Source - -``` -1. Do that first -2. Do this -3. And that -``` - -### Result - -1. Do that first -2. Do this -3. And that - -Links ------ - -### Source - -``` -[My link title](http://kanboard.net/) - - - -``` - -### Result - -[My link title](http://kanboard.net/) - - - -Source code ------------ - -### Inline code - -Use a backtick. - -``` -Execute this command: `tail -f /var/log/messages`. -``` - -### Result - -Execute this command: `tail -f /var/log/messages`. - -### Code blocks - -Use 3 backticks with eventually the language name. - -

    -```php
    -<?php
    -
    -phpinfo();
    -
    -?>
    -```
    -
    -
    - -### Result - -``` - -``` - -Titles ------- - -### Source - -``` -# Title level 1 - -## Title level 2 - -### Title level 3 -``` diff --git a/docs/task-links.markdown b/docs/task-links.markdown deleted file mode 100644 index 1eab51fd..00000000 --- a/docs/task-links.markdown +++ /dev/null @@ -1,22 +0,0 @@ -Task Links -========== - -Tasks can be linked together with predefined relationships: - -![Task Links](http://kanboard.net/screenshots/documentation/task-links.png) - -The default relationships are: - -- **relates to** -- **blocks** | is blocked by -- **is blocked by** | blocks -- **duplicates** | is duplicated by -- **is duplicated by** | duplicates -- **is a child of** | is a parent of -- **is a parent of** | is a child of -- **targets milestone** | is a milestone of -- **is a milestone of** | targets milestone -- **fixes** | is fixed by -- **is fixed by** | fixes - -Those labels can be changed in the application settings. diff --git a/docs/tests.markdown b/docs/tests.markdown deleted file mode 100644 index 31937f33..00000000 --- a/docs/tests.markdown +++ /dev/null @@ -1,176 +0,0 @@ -How to run units and functionals tests? -======================================= - -[PHPUnit](https://phpunit.de/) is used to run automatic tests on Kanboard. - -You can run tests across different databases (Sqlite, Mysql and Postgresql) to be sure that the result is the same everywhere. - -Requirements ------------- - -- Linux/Unix machine -- PHP command line -- PHPUnit installed -- Mysql and Postgresql (optional) - -Install the latest version of PHPUnit -------------------------------------- - -Simply download the PHPUnit PHAR et copy the file somewhere in your `$PATH`: - -```bash -wget https://phar.phpunit.de/phpunit.phar -chmod +x phpunit.phar -sudo mv phpunit.phar /usr/local/bin/phpunit -phpunit --version -PHPUnit 4.2.6 by Sebastian Bergmann. -``` - -Running unit tests ------------------- - -### Testing with Sqlite - -Sqlite tests use a in-memory database, nothing is written on the filesystem. - -The config file is `tests/units.sqlite.xml`. -From your Kanboard directory, run the command `phpunit -c tests/units.sqlite.xml`. - -Example: - -```bash -phpunit -c tests/units.sqlite.xml - -PHPUnit 4.2.6 by Sebastian Bergmann. - -Configuration read from /Volumes/Devel/apps/kanboard/tests/units.sqlite.xml - -................................................................. 65 / 74 ( 87%) -......... - -Time: 9.05 seconds, Memory: 17.75Mb - -OK (74 tests, 6145 assertions) -``` - -**NOTE:** PHPUnit is already included in the Vagrant environment - -### Testing with Mysql - -You must have Mysql or MariaDb installed on localhost. - -By default, those credentials are used: - -- Hostname: **localhost** -- Username: **root** -- Password: none -- Database: **kanboard_unit_test** - -For each execution the database is dropped and created again. - -The config file is `tests/units.mysql.xml`. -From your Kanboard directory, run the command `phpunit -c tests/units.mysql.xml`. - -Example: - -```bash -phpunit -c tests/units.mysql.xml - -PHPUnit 4.2.6 by Sebastian Bergmann. - -Configuration read from /Volumes/Devel/apps/kanboard/tests/units.mysql.xml - -................................................................. 65 / 74 ( 87%) -......... - -Time: 49.77 seconds, Memory: 17.50Mb - -OK (74 tests, 6145 assertions) -``` - -### Testing with Postgresql - -You must have Postgresql installed on localhost. - -By default, those credentials are used: - -- Hostname: **localhost** -- Username: **postgres** -- Password: none -- Database: **kanboard_unit_test** - -Be sure to allow the user `postgres` to create and drop databases. -For each execution the database is dropped and created again. - -The config file is `tests/units.postgres.xml`. -From your Kanboard directory, run the command `phpunit -c tests/units.postgres.xml`. - -Example: - -```bash -phpunit -c tests/units.postgres.xml - -PHPUnit 4.2.6 by Sebastian Bergmann. - -Configuration read from /Volumes/Devel/apps/kanboard/tests/units.postgres.xml - -................................................................. 65 / 74 ( 87%) -......... - -Time: 52.66 seconds, Memory: 17.50Mb - -OK (74 tests, 6145 assertions) -``` - -Running functionals tests -------------------------- - -Actually only the API calls are tested. - -Real HTTP calls are made with those tests. -So a local instance of Kanboard is necessary and must listen on `http://localhost:8000`. - -Don't forget that all data will be removed/altered by the test suite. -Moreover the script will reset and set a new API key. - -1. Start a local instance of Kanboard `php -S 127.0.0.1:8000` -2. Run the test suite from another terminal - -The same method as above is used to run tests across different databases: - -- Sqlite: `phpunit -c tests/functionals.sqlite.xml` -- Mysql: `phpunit -c tests/functionals.mysql.xml` -- Postgresql: `phpunit -c tests/functionals.postgres.xml` - -Example: - -```bash -phpunit -c tests/functionals.sqlite.xml - -PHPUnit 4.2.6 by Sebastian Bergmann. - -Configuration read from /Volumes/Devel/apps/kanboard/tests/functionals.sqlite.xml - -.......................................... - -Time: 1.72 seconds, Memory: 4.25Mb - -OK (42 tests, 160 assertions) -``` - -Continuous Integration with Travis-ci -------------------------------------- - -After each commit pushed on the main repository, unit tests are executed across 5 different versions of PHP: - -- PHP 7.0 -- PHP 5.6 -- PHP 5.5 -- PHP 5.4 -- PHP 5.3 - -Each version of PHP is tested against the 3 supported database: Sqlite, Mysql and Postgresql. - -That mean we run 15 jobs each time the repository is updated. The execution time is around 25 minutes. - -The Travis config file `.travis.yml` is located on the root directory of Kanboard. diff --git a/docs/time-tracking.markdown b/docs/time-tracking.markdown deleted file mode 100644 index 8c65b16a..00000000 --- a/docs/time-tracking.markdown +++ /dev/null @@ -1,43 +0,0 @@ -Time Tracking -============= - -Time tracking information can be defined at the task level or at the subtask level. - -Task time tracking ------------------- - -![Task time tracking](http://kanboard.net/screenshots/documentation/task-time-tracking.png) - -Tasks have two fields: - -- Time estimated -- Time spent - -These values represents hours of work and have to be set manually. - -Subtask time tracking ---------------------- - -![Subtask time tracking](http://kanboard.net/screenshots/documentation/subtask-time-tracking.png) - -Subtasks also have the fields "time spent" and "time estimated". - -When you change the value of these fields, **the task time tracking values are updated automatically and becomes the sum of all subtask values**. - -Kanboard records the time between each subtask status change in a separate table. - -- Changing subtask status from **todo** to **in pogress** logs the start time -- Changing subtask status from **in progress** to **done** logs the end time but also update the time spent of the subtask and the task - -The breakdown of all records is visible in the task view page: - -![Task timesheet](http://kanboard.net/screenshots/documentation/task-timesheet.png) - -For each subtask, the timer can be stopped/started at any time: - -![Subtask timer](http://kanboard.net/screenshots/documentation/subtask-timer.png) - -- The timer doesn't depends of the subtask status -- Each time you start the timer a new record is created in the time tracking table -- Each time you stop the clock the end date is recorded in the time tracking table -- The calculated time spent is rounded to the nearest quarter diff --git a/docs/timetable.markdown b/docs/timetable.markdown deleted file mode 100644 index 5d2f4c86..00000000 --- a/docs/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/docs/transitions.markdown b/docs/transitions.markdown deleted file mode 100644 index c32f696a..00000000 --- a/docs/transitions.markdown +++ /dev/null @@ -1,20 +0,0 @@ -Task transitions -================ - -Transitions record each movement of the tasks between columns. - -![Transitions](http://kanboard.net/screenshots/documentation/transitions.png) - -Available from the task view, you can see those information: - -- Date of the action -- Source column -- Destination column -- Executer (user that move the task) -- Time spent in the origin column - -Task transition data can also be exported from the project settings page. - -![Transitions Export](http://kanboard.net/screenshots/documentation/transitions-export.png) - -For the specified time range you will generate a CSV file that you can use with any spreadsheet software. diff --git a/docs/translations.markdown b/docs/translations.markdown deleted file mode 100644 index 7a4e325b..00000000 --- a/docs/translations.markdown +++ /dev/null @@ -1,79 +0,0 @@ -Translations -============ - -How to translate Kanboard to a new language? --------------------------------------------- - -- Translations are stored inside the directory `app/Locale` -- There is sub-directory for each language, by example for the French we have `fr_FR`, Italian `it_IT` etc... -- A translation is a PHP file that returns an Array with a key-value pairs -- The key is the original text in english and the value is the translation for the corresponding language -- **French translations are always up to date** -- Always use the last version (branch master) - -### Create a new translation: - -1. Make a new directory: `app/Locale/xx_XX` by example `app/Locale/fr_CA` for French Canadian -2. Create a new file for the translation: `app/Locale/xx_XX/translations.php` -3. Use the content of the French locales and replace the values -4. Inside the file `app/Model/Config.php`, add a new entry for your translation inside the function `getLanguages()` -5. Check with your local installation of Kanboard if everything is ok -6. Send a [pull-request with Github](https://help.github.com/articles/using-pull-requests/) - -How to update an existing translation? --------------------------------------- - -1. Open the translation file `app/Locale/xx_XX/translations.php` -2. Missing translations are commented with `//` and the values are empty, just fill blank and remove the comment -3. Check with your local installation of Kanboard and send a [pull-request](https://help.github.com/articles/using-pull-requests/) - -How to add new translated text in the application? --------------------------------------------------- - -Translations are displayed with the following functions in the source code: - -- `t()`: dispaly text with HTML escaping -- `e()`: display text without HTML escaping -- `dt()`: display date and time using the `strftime()` function formats - -Always use the english version in the source code. - -### Date and time translation - -Date strings use the function `strftime()` to format the date. - -By example, the original English version can be defined like that `Created on %B %e, %Y at %k:%M %p` and that will output something like that `Created on January 11, 2015 at 15:19 PM`. The French version can be modified to display a different format, `Créé le %d/%m/%Y à %H:%M` and the result will be `Créé le 11/01/2015 à 15:19`. - -All formats are available in the [PHP documentation](http://php.net/strftime). - -### Placeholders - -Text strings use the function `sprintf()` to replace elements: - -- `%s` is used to replace a string -- `%d` is used to replace an integer - -All formats are available in the [PHP documentation](http://php.net/sprintf). - -How to find missing translations in the applications? ------------------------------------------------------ - -From a terminal, run the following command: - -```bash -./kanboard locale:compare -``` - -All missing and unused translations are displayed on the screen. -Put that in the French locale and sync other locales (see below). - -How to synchronize translation files? -------------------------------------- - -From a Unix shell run this command: - -```bash -./kanboard locale:sync -``` - -The French translation is used a reference for other locales. diff --git a/docs/ubuntu-installation.markdown b/docs/ubuntu-installation.markdown deleted file mode 100644 index 5f9ee65b..00000000 --- a/docs/ubuntu-installation.markdown +++ /dev/null @@ -1,28 +0,0 @@ -How to install Kanboard on Ubuntu? -================================== - -Ubuntu 14.04 LTS ----------------- - -Install Apache and PHP: - -```bash -sudo apt-get update -sudo apt-get install -y php5 php5-sqlite unzip -``` - -In case your webserver was running restart to make sure the php modules are reloaded - -```bash -service apache2 restart -``` - -Install Kanboard: - -```bash -cd /var/www/html -sudo wget http://kanboard.net/kanboard-latest.zip -sudo unzip kanboard-latest.zip -sudo chown -R www-data:www-data kanboard/data -sudo rm kanboard-latest.zip -``` diff --git a/docs/update.markdown b/docs/update.markdown deleted file mode 100644 index d502f794..00000000 --- a/docs/update.markdown +++ /dev/null @@ -1,26 +0,0 @@ -Update -====== - -**Always make a backup of your database before upgrading!** - -From the archive (stable version) ---------------------------------- - -1. Close your session (logout) -2. Rename your actual Kanboard directory (to keep a backup) -3. Uncompress the new archive and copy your `data` directory to the newly uncompressed directory. -4. Copy your custom `config.php` (if you created one) to the root of the newly uncompressed directory. -5. Make the directory `data` writeable by the web server user -6. Login and check if everything is ok -7. Remove the old Kanboard directory - - -From the repository (development version) ------------------------------------------ - -1. Close your session (logout) -2. `git pull` -3. `composer install` -3. Login and check if everything is ok - -Note: This method will install the **current development version**, use at your own risk. diff --git a/docs/usage-examples.markdown b/docs/usage-examples.markdown deleted file mode 100644 index f2d457a6..00000000 --- a/docs/usage-examples.markdown +++ /dev/null @@ -1,67 +0,0 @@ -Usage examples -============== - -You can customize your boards according to your business activities: - -Software development --------------------- - -- Backlog -- Ready -- Work in progress -- To be validated -- Validated -- Deployed in production - -Bug tracking ------------- - -- Reported -- Confirmed -- Work in progress -- Tested -- Fixed - -Sales ------ - -- Leads -- Meeting -- Proposal -- Purchase - -Lean business management ------------------------- - -- Ideas -- Development -- Measure -- Analysis -- Done - -Recruiting process ------------------- - -- Job offers -- Candidates -- Phone screens -- Interviews -- Hires - -Online shops ------------- - -- Orders -- Packaging -- Ready to send -- Shipped - -Manufactory ------------ - -- Customer Orders -- Assembly -- Tests -- Packaging -- Ready to ship -- Shipped diff --git a/docs/user-management.markdown b/docs/user-management.markdown deleted file mode 100644 index 25cc8539..00000000 --- a/docs/user-management.markdown +++ /dev/null @@ -1,81 +0,0 @@ -User management -=============== - -Roles at the application level ------------------------------- - -Kanboard use a basic permission system, there are 3 type of users: - -### Administrators - -- Access to everything - -### Project Administrators - -- Can create multi-users and private projects -- Can convert multi-users and private projects -- Can see only their own projects -- Cannot change application settings -- Cannot manage users - -### Standard Users - -- Can create only private projects -- Can see only their own projects -- Cannot remove projects - -Roles at the project level --------------------------- - -These role are related to the project permission. - -### Project Managers - -- Can manage only their own projects -- Can access to reports and budget section - -### Project Members - -- Can do any daily operations in their projects (create and move tasks...) -- Cannot configure projects - -Note: Any "Standard User" can be promotted "Project Manager" for a given project, they don't necessary need to be "Project Administrator". - -Local and remote users ----------------------- - -- A local user is an account that use the database to store credentials. Local users use the login form for the authentication. -- A remote user is an account that use an external system to store credentials. By example, it can be LDAP, Github or Google accounts. Authentication of these users can be done through the login form or not. - -Add a new user --------------- - -To add a new user, you must be administrator. - -1. From the dashboard, go to the menu **User Management** -2. On the top, you have a link **New local user** or **New remote user** -3. Fill the form and save - -![New user](http://kanboard.net/screenshots/documentation/new-user.png) - -When you create a **local user**, you have to specify at least those values: - -- **username**: This is the unique identifier of your user (login) -- **password**: The password of your user must have at least 6 characters - -For **remote users**, only the username is mandatory. You can also pre-link Github or Google accounts if you already know their unique id. - -Edit users ----------- - -When you go to the **users** menu, you have the list of users, to modify a user click on the **edit link**. - -- If you are a regular user, you can change only your own profile -- You have to be administrator to be able to edit any users - -Remove users ------------- - -From the **users** menu, click on the link **remove**. This link is visible only if you are administrator. - -If you remove a specific user, **tasks assigned to this person will be unassigned** after the operation. diff --git a/docs/vagrant.markdown b/docs/vagrant.markdown deleted file mode 100644 index beebb323..00000000 --- a/docs/vagrant.markdown +++ /dev/null @@ -1,64 +0,0 @@ -Run Kanboard with Vagrant -========================= - -Vagrant is used to test Kanboard in different environments. - -Several configurations are available: - -- Ubuntu 14.04 LTS with Sqlite -- Ubuntu 14.04 LTS with Mysql -- Ubuntu 14.04 LTS with Postgresql -- Debian 8 with sqlite -- Debian 7.6 with Sqlite -- Debian 6 with Sqlite -- Centos 7 with Sqlite -- Centos 6.5 with Sqlite -- Freebsd 10 with Sqlite - -The installation process is not fully automated for all VM, manual configuration can be required. - -To use those configurations, you have to install the **last version of Virtualbox and Vagrant**. - -Standard boxes can be downloaded from Vagrant: - -```bash -vagrant box add ubuntu/trusty64 -vagrant box add debian/jessie64 -vagrant box add chef/debian-7.6 -vagrant box add chef/debian-6.0.10 -vagrant box add chef/centos-7.0 -vagrant box add chef/centos-6.5 -vagrant box add freebsd/FreeBSD-10.2-STABLE -``` - -### Example with Ubuntu and Sqlite - -If you want to test Kanboard on Ubuntu with Sqlite: - -```bash -vagrant up sqlite -``` - -Run composer: - -```bash -vagrant ssh sqlite -cd /var/www/html # change the path according to the chosen distribution -sudo composer install -``` - -After the initialization, go to **http://localhost:8001/**. - -If you want to use Postgresql or Mysql, you have to configure Kanboard manually (`config.php`) and configure the database inside the virtual machine. - -Available boxes are: - -- `vagrant up sqlite` -- `vagrant up mysql` -- `vagrant up postgres` -- `vagrant up debian8` -- `vagrant up debian7` -- `vagrant up debian6` -- `vagrant up centos7` -- `vagrant up centos65` -- `vagrant up freebsd10` diff --git a/docs/webhooks.markdown b/docs/webhooks.markdown deleted file mode 100644 index f7925350..00000000 --- a/docs/webhooks.markdown +++ /dev/null @@ -1,306 +0,0 @@ -Webhooks -======== - -Webhooks are useful to perform actions with external applications. - -- Webhooks can be used to create a task by calling a simple URL (You can also do that with the API) -- An external URL can be called automatically when an event occurs in Kanboard (task creation, comment updated, etc) - -How to write a webhook receiver? --------------------------------- - -All internal events of Kanboard can be sent to an external URL. - -- The webhook url have to be defined in **Settings > Webhooks > Webhook URL**. -- When an event is triggered Kanboard call automatically the predefined URL -- The data are encoded in JSON format and sent with a POST HTTP request -- The webhook token is also sent as a query string parameter, so you can check if the request really come from Kanboard. -- **Your custom URL must answer in less than 1 second**, those requests are synchronous (PHP limitation) and that can slow down the user interface if your script is too slow! - -### List of supported events - -- comment.create -- comment.update -- file.create -- task.move.project -- task.move.column -- task.move.position -- task.move.swimlane -- task.update -- task.create -- task.close -- task.open -- task.assignee_change -- subtask.update -- subtask.create - -### Example of HTTP request - -``` -POST https://your_webhook_url/?token=WEBHOOK_TOKEN_HERE -User-Agent: Kanboard Webhook -Content-Type: application/json -Connection: close - -{ - "event_name": "task.move.column", - "event_data": { - "task_id": "1", - "project_id": "1", - "position": 1, - "column_id": "1", - "swimlane_id": "0", - "src_column_id": "2", - "dst_column_id": "1", - "date_moved": "1431991532", - "recurrence_status": "0", - "recurrence_trigger": "0" - } -} -``` - -All event payloads are in the following format: - -```json -{ - "event_name": "model.event_name", - "event_data": { - "key1": "value1", - "key2": "value2", - ... - } -} -``` - -The `event_data` values are not necessary normalized across events. - -### Examples of event payloads - -Task creation: - -```json -{ - "event_name": "task.create", - "event_data": { - "title": "Demo", - "description": "", - "project_id": "1", - "owner_id": "1", - "category_id": 0, - "swimlane_id": 0, - "column_id": "2", - "color_id": "yellow", - "score": 0, - "time_estimated": 0, - "date_due": 0, - "creator_id": 1, - "date_creation": 1431991532, - "date_modification": 1431991532, - "date_moved": 1431991532, - "position": 1, - "task_id": 1 - } -} -``` - -Task modification: - -```json -{ - "event_name": "task.update", - "event_data": { - "id": "1", - "title": "Demo", - "description": "", - "date_creation": "1431991532", - "color_id": "yellow", - "project_id": "1", - "column_id": "1", - "owner_id": "1", - "position": "1", - "is_active": "1", - "date_completed": null, - "score": "0", - "date_due": "0", - "category_id": "2", - "creator_id": "1", - "date_modification": 1431991603, - "reference": "", - "date_started": 1431993600, - "time_spent": 0, - "time_estimated": 0, - "swimlane_id": "0", - "date_moved": "1431991572", - "recurrence_status": "0", - "recurrence_trigger": "0", - "recurrence_factor": "0", - "recurrence_timeframe": "0", - "recurrence_basedate": "0", - "recurrence_parent": null, - "recurrence_child": null, - "task_id": "1", - "changes": { - "category_id": "2" - } - } -} -``` - -Task update events have a field called `changes` that contains updated values. - -Move a task to another column: - -```json -{ - "event_name": "task.move.column", - "event_data": { - "task_id": "1", - "project_id": "1", - "position": 1, - "column_id": "1", - "swimlane_id": "0", - "src_column_id": "2", - "dst_column_id": "1", - "date_moved": "1431991532", - "recurrence_status": "0", - "recurrence_trigger": "0" - } -} -``` - -Move a task to another position: - -```json -{ - "event_name": "task.move.position", - "event_data": { - "task_id": "2", - "project_id": "1", - "position": 1, - "column_id": "1", - "swimlane_id": "0", - "src_column_id": "1", - "dst_column_id": "1", - "date_moved": "1431996905", - "recurrence_status": "0", - "recurrence_trigger": "0" - } -} -``` - -Comment creation: - -```json -{ - "event_name": "comment.create", - "event_data": { - "id": 1, - "task_id": "1", - "user_id": "1", - "comment": "test", - "date_creation": 1431991615 - } -} -``` - -Comment modification: - -``` -{ - "event_name": "comment.update", - "event_data": { - "id": "1", - "task_id": "1", - "user_id": "1", - "comment": "test edit" - } -} -``` - -Subtask creation: - -```json -{ - "event_name": "subtask.create", - "event_data": { - "id": 3, - "task_id": "1", - "title": "Test", - "user_id": "1", - "time_estimated": "2", - "position": 3 - } -} -``` - -Subtask modification: - -```json -{ - "event_name": "subtask.update", - "event_data": { - "id": "1", - "status": 1, - "task_id": "1" - } -} -``` - -File upload: - -```json -{ - "event_name": "file.create", - "event_data": { - "task_id": "1", - "name": "test.png" - } -} -``` - -Screenshot created: - -```json -{ - "event_name": "file.create", - "event_data": { - "task_id": "2", - "name": "Screenshot taken May 19, 2015 at 10:56 AM" - } -} -``` - -Note: Webhooks configuration and payload have changed since Kanboard >= 1.0.15 - -How to create a task with a webhook? ------------------------------------- - -Firstly, you have to get the token from the settings page. After that, just call this url from anywhere: - -```bash -# Create a task for the default project inside the first column -curl "http://myserver/?controller=webhook&action=task&token=superSecretToken&title=mySuperTask" - -# Create a task to another project inside a specific column with the color red -curl "http://myserver/?controller=webhook&action=task&token=superSecretToken&title=task123&project_id=3&column_id=7&color_id=red" -``` - -### Available responses - -- When a task is created successfully, Kanboard return the message "OK" in plain text. -- However if the task creation fail, you will got a "FAILED" message. -- If the token is wrong, you got a "Not Authorized" message and a HTTP status code 401. - -### Available parameters - -Base URL: `http://YOUR_SERVER_HOSTNAME/?controller=webhook&action=task` - -- `token`: Token displayed on the settings page (required) -- `title`: Task title (required) -- `description`: Task description -- `color_id`: Supported colors are yellow, blue, green, purple, red, orange and grey -- `project_id`: Project id (Get the id from the project page) -- `owner_id`: Assignee (Get the user id from the users page) -- `column_id`: Column on the board (Get the column id from the projects page, mouse over on the column name) - -Only the token and the title parameters are mandatory. The different id can also be found in the database. diff --git a/docs/what-is-kanban.markdown b/docs/what-is-kanban.markdown deleted file mode 100644 index 3a37bb7a..00000000 --- a/docs/what-is-kanban.markdown +++ /dev/null @@ -1,32 +0,0 @@ -What is Kanban? -=============== - -Kanban is a methodology originally developed by Toyota to be more efficient. - -There is only two constraints imposed by Kanban: - -- Visualize your workflow -- Limit your work in progress - -Visualize your workflow ------------------------ - -- Your work is displayed on a board, you have a clear overview of your project -- Each column represent a step in your workflow - -Bring focus and avoid multitasking ----------------------------------- - -- Each phase can have a work in progress limit -- Limits are great to identify bottlenecks -- Limits avoid working on too many tasks in the same time - -Measure performance and improvement ------------------------------------ - -Kanban uses lead and cycle times to measure performance: - -- **Lead time**: Time between the task is created and completed -- **Cycle time**: Time between the task is started and completed - -By example, you may have a lead time of 100 days and only have to work 1 hour to complete the task. diff --git a/docs/windows-apache-installation.markdown b/docs/windows-apache-installation.markdown deleted file mode 100644 index 25d39373..00000000 --- a/docs/windows-apache-installation.markdown +++ /dev/null @@ -1,126 +0,0 @@ -Installation on Windows Server and Apache -========================================= - -This guide will help you to setup step by step Kanboard on a Windows Server with Apache and PHP. - -Note: If you have a 64 bits platform choose "x64" otherwise choose "x86" for 32 bits systems. - -Visual C++ Redistributable Installation ---------------------------------------- - -PHP and Apache are compiled with Visual Studio so you need to install this library if it's not already done. - -1. Download the library from the [official Microsoft website](http://www.microsoft.com/en-us/download/details.aspx?id=30679) -2. Run the installer `vcredist_x64.exe` or `vcredist_x86.exe` according to your platform - -Apache installation -------------------- - -1. Download Apache binary from [Apache Lounge](http://www.apachelounge.com/download/) -2. Unzip the Apache24 folder to `C:\Apache24` - -### Define the server name - -Open the file `C:\Apache24\conf\httpd.conf` and add the directive: - -``` -ServerName localhost -``` - -### Install the Apache service - -Open a command prompt (`cmd.exe`) and go to the directory `C:\Apache24\bin`: - -```bash -cd C:\Apache24\bin - -# Install the windows service -httpd.exe -k install -``` - -### Install ApacheMonitor - -- Double click on `C:\Apache24\bin\ApacheMonitor.exe`, or put it in your startup folder. -- Right click on the icon and start Apache - -### Check the Apache installation - -Go to http://localhost/ you should see a blank page with the text "It works!". - -PHP installation ----------------- - -1. Download the last stable version of PHP from the [official PHP website](http://windows.php.net/download/), choose the **Thread Safe** version and use the exact same build type as Apache: x86 or x64 -2. Unzip the files to `C:\php` -3. Navigate to the PHP folder and rename the file `php.ini-production` to `php.ini` - -Edit the `php.ini`: - -Uncomment extension directory: - -```ini -extension_dir = "C:/php/ext" -``` - -Uncomment these PHP modules: - -```ini -extension=php_curl.dll -extension=php_gd2.dll -extension=php_ldap.dll -extension=php_mbstring.dll -extension=php_openssl.dll -extension=php_pdo_sqlite.dll -``` - -Set the timezone: - -```ini -date.timezone = America/Montreal -``` - -The list of supported timezones can be found in the [PHP documentation](http://php.net/manual/en/timezones.america.php). - -Load the PHP module for Apache: - -Add this configuration in the file `C:\Apache24\conf\httpd.conf`: - -``` -LoadModule php5_module "c:/php/php5apache2_4.dll" -AddHandler application/x-httpd-php .php - -# configure the path to php.ini -PHPIniDir "C:/php" - -# change this directive -DirectoryIndex index.php index.html -``` - -Restart Apache. - -Test your PHP installation: - -Create a file named `phpinfo.php` in the folder `C:\Apache24\htdocs`: - -```php - -``` - -Go to http://localhost/phpinfo.php and should see all information about your PHP installation. - -Kanboard installation ---------------------- - -- Download the zip file -- Uncompress the archive in `C:\Apache24\htdocs\kanboard` by example -- Open your web browser to use Kanboard http://localhost/kanboard/ -- The default credentials are **admin/admin** - -Tested configuration --------------------- - -- Windows 2008 R2 / Apache 2.4.12 / PHP 5.6.8 diff --git a/docs/windows-iis-installation.markdown b/docs/windows-iis-installation.markdown deleted file mode 100644 index 84a2e53c..00000000 --- a/docs/windows-iis-installation.markdown +++ /dev/null @@ -1,68 +0,0 @@ -Installation on Windows 2008/2012 with IIS -========================================== - -This guide will help you to setup step by step Kanboard on a Windows Server with IIS and PHP. - -PHP installation ----------------- - -- Install IIS on your server (Add a new role and don't forget to enable CGI/FastCGI) -- Install PHP by following the official documentation: - - [Microsoft IIS 5.1 and IIS 6.0](http://php.net/manual/en/install.windows.iis6.php) - - [Microsoft IIS 7.0 and later](http://php.net/manual/en/install.windows.iis7.php) - - [PHP for Windows is available here](http://windows.php.net/download/) - -Edit the `php.ini`, uncomment these PHP modules: - -```ini -extension=php_curl.dll -extension=php_gd2.dll -extension=php_ldap.dll -extension=php_mbstring.dll -extension=php_openssl.dll -extension=php_pdo_sqlite.dll -``` - -Set the timezone: - -```ini -date.timezone = America/Montreal -``` - -The list of supported timezones can be found in the [PHP documentation](http://php.net/manual/en/timezones.america.php). - -Check if PHP runs correctly: - -Go the IIS document root `C:\inetpub\wwwroot` and create a file `phpinfo.php`: - -```php - -``` - -Open a browser at `http://localhost/phpinfo.php` and you should see the current PHP settings. -If you got an error 500, something is not correctly done in your installation. - -Notes: - -- If you use PHP < 5.4, you have to enable the short tags in your php.ini -- Don't forget to enable the required php extensions mentioned above -- If you got an error about "the library MSVCP110.dll is missing", you probably need to download the Visual C++ Redistributable for Visual Studio from the Microsoft website. - -Kanboard installation ---------------------- - -- Download the zip file -- Uncompress the archive in `C:\inetpub\wwwroot\kanboard` by example -- Make sure the directory `data` is writable by the IIS user -- Open your web browser to use Kanboard http://localhost/kanboard/ -- The default credentials are **admin/admin** - -Tested configurations ---------------------- - -- Windows 2008 R2 Standard Edition / IIS 7.5 / PHP 5.5.16 -- Windows 2012 Standard Edition / IIS 8.5 / PHP 5.3.29 -- cgit v1.2.3