1
0
Fork 0
mirror of https://github.com/YunoHost-Apps/kanboard_ynh.git synced 2024-09-03 19:36:17 +02:00

Update to v1.0.18

This commit is contained in:
mbugeia 2015-09-08 22:16:28 +02:00
parent 8f05ed1953
commit 41ed9e9410
215 changed files with 3176 additions and 4333 deletions

View file

@ -126,6 +126,33 @@ define('GITHUB_CLIENT_ID', '');
// GitHub client secret key (Copy it from your settings -> Applications -> Developer applications) // GitHub client secret key (Copy it from your settings -> Applications -> Developer applications)
define('GITHUB_CLIENT_SECRET', ''); define('GITHUB_CLIENT_SECRET', '');
// 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/');
// Enable/disable Gitlab authentication
define('GITLAB_AUTH', false);
// Gitlab application id
define('GITLAB_CLIENT_ID', '');
// Gitlab application secret
define('GITLAB_CLIENT_SECRET', '');
// 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/');
// Enable/disable the reverse proxy authentication // Enable/disable the reverse proxy authentication
define('REVERSE_PROXY_AUTH', true); define('REVERSE_PROXY_AUTH', true);
@ -138,6 +165,9 @@ define('REVERSE_PROXY_DEFAULT_ADMIN', 'yuno_admin');
// Default domain to use for setting the email address // Default domain to use for setting the email address
define('REVERSE_PROXY_DEFAULT_DOMAIN', 'yuno_domain'); define('REVERSE_PROXY_DEFAULT_DOMAIN', 'yuno_domain');
// Enable/disable remember me authentication
define('REMEMBER_ME_AUTH', true);
// Enable or disable "Strict-Transport-Security" HTTP header // Enable or disable "Strict-Transport-Security" HTTP header
define('ENABLE_HSTS', true); define('ENABLE_HSTS', true);
@ -155,3 +185,16 @@ define('ENABLE_URL_REWRITE', false);
// Hide login form, useful if all your users use Google/Github/ReverseProxy authentication // Hide login form, useful if all your users use Google/Github/ReverseProxy authentication
define('HIDE_LOGIN_FORM', true); define('HIDE_LOGIN_FORM', true);
// 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 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);

View file

@ -77,8 +77,8 @@ class Google extends Base
return $this->user->update(array( return $this->user->update(array(
'id' => $user_id, 'id' => $user_id,
'google_id' => $profile['id'], 'google_id' => $profile['id'],
'email' => $profile['email'] ?: $user['email'], 'email' => empty($user['email']) ? $profile['email'] : $user['email'],
'name' => $profile['name'] ?: $user['name'], 'name' => empty($user['name']) ? $profile['name'] : $user['name'],
)); ));
} }

View file

@ -31,6 +31,7 @@ class Action extends Base
'projects_list' => $this->project->getList(false), 'projects_list' => $this->project->getList(false),
'colors_list' => $this->color->getList(), 'colors_list' => $this->color->getList(),
'categories_list' => $this->category->getList($project['id']), 'categories_list' => $this->category->getList($project['id']),
'links_list' => $this->link->getList(0, false),
'title' => t('Automatic actions') 'title' => t('Automatic actions')
))); )));
} }
@ -89,6 +90,7 @@ class Action extends Base
'projects_list' => $projects_list, 'projects_list' => $projects_list,
'colors_list' => $this->color->getList(), 'colors_list' => $this->color->getList(),
'categories_list' => $this->category->getList($project['id']), 'categories_list' => $this->category->getList($project['id']),
'links_list' => $this->link->getList(0, false),
'project' => $project, 'project' => $project,
'title' => t('Automatic actions') 'title' => t('Automatic actions')
))); )));

View file

@ -80,7 +80,7 @@ abstract class Base extends \Core\Base
private function sendHeaders($action) private function sendHeaders($action)
{ {
// HTTP secure headers // HTTP secure headers
$this->response->csp(array('style-src' => "'self' 'unsafe-inline'", 'img-src' => '*')); $this->response->csp(array('style-src' => "'self' 'unsafe-inline'", 'img-src' => '* data:'));
$this->response->nosniff(); $this->response->nosniff();
$this->response->xss(); $this->response->xss();
@ -269,12 +269,17 @@ abstract class Base extends \Core\Base
*/ */
protected function getTask() protected function getTask()
{ {
$project_id = $this->request->getIntegerParam('project_id');
$task = $this->taskFinder->getDetails($this->request->getIntegerParam('task_id')); $task = $this->taskFinder->getDetails($this->request->getIntegerParam('task_id'));
if (empty($task)) { if (empty($task)) {
$this->notfound(); $this->notfound();
} }
if ($project_id !== 0 && $project_id != $task['project_id']) {
$this->forbidden();
}
return $task; return $task;
} }

View file

@ -50,6 +50,8 @@ class Board extends Base
$params = $this->getProjectFilters('board', 'show'); $params = $this->getProjectFilters('board', 'show');
$this->response->html($this->template->layout('board/private_view', array( $this->response->html($this->template->layout('board/private_view', array(
'categories_list' => $this->category->getList($params['project']['id'], false),
'users_list' => $this->projectPermission->getMemberList($params['project']['id'], false),
'swimlanes' => $this->taskFilter->search($params['filters']['search'])->getBoard($params['project']['id']), 'swimlanes' => $this->taskFilter->search($params['filters']['search'])->getBoard($params['project']['id']),
'description' => $params['project']['description'], 'description' => $params['project']['description'],
'board_private_refresh_interval' => $this->config->get('board_private_refresh_interval'), 'board_private_refresh_interval' => $this->config->get('board_private_refresh_interval'),
@ -116,6 +118,29 @@ class Board extends Base
$this->response->html($this->renderBoard($project_id)); $this->response->html($this->renderBoard($project_id));
} }
/**
* Reload the board with new filters
*
* @access public
*/
public function reload()
{
if (! $this->request->isAjax()) {
return $this->response->status(403);
}
$project_id = $this->request->getIntegerParam('project_id');
if (! $this->projectPermission->isUserAllowed($project_id, $this->userSession->getId())) {
$this->response->text('Forbidden', 403);
}
$values = $this->request->getJson();
$this->userSession->setFilters($project_id, $values['search']);
$this->response->html($this->renderBoard($project_id));
}
/** /**
* Get links on mouseover * Get links on mouseover
* *
@ -154,8 +179,7 @@ class Board extends Base
$task = $this->getTask(); $task = $this->getTask();
$this->response->html($this->template->render('board/tooltip_files', array( $this->response->html($this->template->render('board/tooltip_files', array(
'files' => $this->file->getAllDocuments($task['id']), 'files' => $this->file->getAll($task['id']),
'images' => $this->file->getAllImages($task['id']),
'task' => $task, 'task' => $task,
))); )));
} }

View file

@ -30,7 +30,7 @@ class Project extends Base
->setUrl('project', 'index') ->setUrl('project', 'index')
->setMax(20) ->setMax(20)
->setOrder('name') ->setOrder('name')
->setQuery($this->project->getQueryColumnStats($project_ids)) ->setQuery($this->project->getQueryProjectDetails($project_ids))
->calculate(); ->calculate();
$this->response->html($this->template->layout('project/index', array( $this->response->html($this->template->layout('project/index', array(
@ -141,9 +141,16 @@ class Project extends Base
$project = $this->getProject(); $project = $this->getProject();
$values = $this->request->getValues(); $values = $this->request->getValues();
if ($project['is_private'] == 1 && $this->userSession->isAdmin() && ! isset($values['is_private'])) { if (isset($values['is_private'])) {
if (! $this->helper->user->isProjectAdministrationAllowed($project['id'])) {
unset($values['is_private']);
}
}
else if ($project['is_private'] == 1 && ! isset($values['is_private'])) {
if ($this->helper->user->isProjectAdministrationAllowed($project['id'])) {
$values += array('is_private' => 0); $values += array('is_private' => 0);
} }
}
list($valid, $errors) = $this->project->validateModification($values); list($valid, $errors) = $this->project->validateModification($values);
@ -402,7 +409,7 @@ class Project extends Base
*/ */
public function create(array $values = array(), array $errors = array()) public function create(array $values = array(), array $errors = array())
{ {
$is_private = $this->request->getIntegerParam('private', $this->userSession->isAdmin() ? 0 : 1); $is_private = $this->request->getIntegerParam('private', $this->userSession->isAdmin() || $this->userSession->isProjectAdmin() ? 0 : 1);
$this->response->html($this->template->layout('project/new', array( $this->response->html($this->template->layout('project/new', array(
'board_selector' => $this->projectPermission->getAllowedProjects($this->userSession->getId()), 'board_selector' => $this->projectPermission->getAllowedProjects($this->userSession->getId()),

View file

@ -186,7 +186,7 @@ class Subtask extends Base
$this->session['has_subtask_inprogress'] = $this->subtask->hasSubtaskInProgress($this->userSession->getId()); $this->session['has_subtask_inprogress'] = $this->subtask->hasSubtaskInProgress($this->userSession->getId());
$this->response->html($this->template->render('board/subtasks', array( $this->response->html($this->template->render('board/tooltip_subtasks', array(
'subtasks' => $this->subtask->getAll($task['id']), 'subtasks' => $this->subtask->getAll($task['id']),
'task' => $task, 'task' => $task,
))); )));

View file

@ -303,12 +303,16 @@ class User extends Base
$values = $this->request->getValues(); $values = $this->request->getValues();
if ($this->userSession->isAdmin()) { if ($this->userSession->isAdmin()) {
$values += array('is_admin' => 0); $values += array('is_admin' => 0, 'is_project_admin' => 0);
} }
else { else {
// Regular users can't be admin
if (isset($values['is_admin'])) { if (isset($values['is_admin'])) {
unset($values['is_admin']); // Regular users can't be admin unset($values['is_admin']);
}
if (isset($values['is_project_admin'])) {
unset($values['is_project_admin']);
} }
} }

View file

@ -10,6 +10,22 @@ namespace Core;
*/ */
class Router extends Base class Router extends Base
{ {
/**
* Controller
*
* @access private
* @var string
*/
private $controller = '';
/**
* Action
*
* @access private
* @var string
*/
private $action = '';
/** /**
* Store routes for path lookup * Store routes for path lookup
* *
@ -26,6 +42,28 @@ class Router extends Base
*/ */
private $urls = array(); private $urls = array();
/**
* Get action
*
* @access public
* @return string
*/
public function getAction()
{
return $this->action;
}
/**
* Get controller
*
* @access public
* @return string
*/
public function getController()
{
return $this->controller;
}
/** /**
* Get the path to compare patterns * Get the path to compare patterns
* *
@ -208,6 +246,9 @@ class Router extends Base
return false; return false;
} }
$this->action = $method;
$this->controller = $controller;
$instance = new $class($this->container); $instance = new $class($this->container);
$instance->beforeAction($controller, $method); $instance->beforeAction($controller, $method);
$instance->$method(); $instance->$method();

View file

@ -12,15 +12,6 @@ use ArrayAccess;
*/ */
class Session implements ArrayAccess class Session implements ArrayAccess
{ {
/**
* Sesion lifetime
*
* http://php.net/manual/en/session.configuration.php#ini.session.cookie-lifetime
*
* @var integer
*/
const SESSION_LIFETIME = 0; // Until the browser is closed
/** /**
* Return true if the session is open * Return true if the session is open
* *
@ -43,7 +34,7 @@ class Session implements ArrayAccess
{ {
// HttpOnly and secure flags for session cookie // HttpOnly and secure flags for session cookie
session_set_cookie_params( session_set_cookie_params(
self::SESSION_LIFETIME, SESSION_DURATION,
$base_path ?: '/', $base_path ?: '/',
null, null,
Request::isHTTPS(), Request::isHTTPS(),

View file

@ -1015,4 +1015,56 @@ return array(
// 'contributors' => '', // 'contributors' => '',
// 'License:' => '', // 'License:' => '',
// 'License' => '', // 'License' => '',
// 'Project Administrator' => '',
// 'Enter the text below' => '',
// 'Gantt chart for %s' => '',
// 'Sort by position' => '',
// 'Sort by date' => '',
// 'Add task' => '',
// 'Start date:' => '',
// 'Due date:' => '',
// 'There is no start date or due date for this task.' => '',
// 'Moving or resizing a task will change the start and due date of the task.' => '',
// 'There is no task in your project.' => '',
// 'Gantt chart' => '',
// 'People who are project managers' => '',
// 'People who are project members' => '',
// 'NOK - Norwegian Krone' => '',
// 'Show this column' => '',
// 'Hide this column' => '',
// 'open file' => '',
// 'End date' => '',
// 'Users overview' => '',
// 'Managers' => '',
// 'Members' => '',
// 'Shared project' => '',
// 'Project managers' => '',
// 'Project members' => '',
// 'Gantt chart for all projects' => '',
// 'Projects list' => '',
// 'Gantt chart for this project' => '',
// 'Project board' => '',
// 'End date:' => '',
// 'There is no start date or end date for this project.' => '',
// 'Projects Gantt chart' => '',
// 'Start date: %s' => '',
// 'End date: %s' => '',
// 'Link type' => '',
// 'Change task color when using a specific task link' => '',
// 'Task link creation or modification' => '',
// 'Login with my Gitlab Account' => '',
// 'Milestone' => '',
// 'Gitlab Authentication' => '',
// 'Help on Gitlab authentication' => '',
// 'Gitlab Id' => '',
// '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' => '',
); );

View file

@ -1015,4 +1015,56 @@ return array(
// 'contributors' => '', // 'contributors' => '',
// 'License:' => '', // 'License:' => '',
// 'License' => '', // 'License' => '',
// 'Project Administrator' => '',
// 'Enter the text below' => '',
// 'Gantt chart for %s' => '',
// 'Sort by position' => '',
// 'Sort by date' => '',
// 'Add task' => '',
// 'Start date:' => '',
// 'Due date:' => '',
// 'There is no start date or due date for this task.' => '',
// 'Moving or resizing a task will change the start and due date of the task.' => '',
// 'There is no task in your project.' => '',
// 'Gantt chart' => '',
// 'People who are project managers' => '',
// 'People who are project members' => '',
// 'NOK - Norwegian Krone' => '',
// 'Show this column' => '',
// 'Hide this column' => '',
// 'open file' => '',
// 'End date' => '',
// 'Users overview' => '',
// 'Managers' => '',
// 'Members' => '',
// 'Shared project' => '',
// 'Project managers' => '',
// 'Project members' => '',
// 'Gantt chart for all projects' => '',
// 'Projects list' => '',
// 'Gantt chart for this project' => '',
// 'Project board' => '',
// 'End date:' => '',
// 'There is no start date or end date for this project.' => '',
// 'Projects Gantt chart' => '',
// 'Start date: %s' => '',
// 'End date: %s' => '',
// 'Link type' => '',
// 'Change task color when using a specific task link' => '',
// 'Task link creation or modification' => '',
// 'Login with my Gitlab Account' => '',
// 'Milestone' => '',
// 'Gitlab Authentication' => '',
// 'Help on Gitlab authentication' => '',
// 'Gitlab Id' => '',
// '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' => '',
); );

View file

@ -35,7 +35,7 @@ return array(
'Unassigned' => 'No asignado', 'Unassigned' => 'No asignado',
'View this task' => 'Ver esta tarea', 'View this task' => 'Ver esta tarea',
'Remove user' => 'Eliminar un usuario', 'Remove user' => 'Eliminar un usuario',
'Do you really want to remove this user: "%s"?' => '¿De verdad que deseas suprimir a este usuario: « %s » ?', 'Do you really want to remove this user: "%s"?' => '¿De verdad que desea suprimir a este usuario: « %s » ?',
'New user' => 'Añadir un usuario', 'New user' => 'Añadir un usuario',
'All users' => 'Todos los usuarios', 'All users' => 'Todos los usuarios',
'Username' => 'Nombre de usuario', 'Username' => 'Nombre de usuario',
@ -68,19 +68,19 @@ return array(
'Disable' => 'Desactivar', 'Disable' => 'Desactivar',
'Enable' => 'Activar', 'Enable' => 'Activar',
'New project' => 'Nuevo proyecto', 'New project' => 'Nuevo proyecto',
'Do you really want to remove this project: "%s"?' => '¿De verdad que deseas eliminar este proyecto: « %s » ?', 'Do you really want to remove this project: "%s"?' => '¿De verdad que desea eliminar este proyecto: « %s » ?',
'Remove project' => 'Suprimir el proyecto', 'Remove project' => 'Suprimir el proyecto',
'Edit the board for "%s"' => 'Modificar el tablero para « %s »', 'Edit the board for "%s"' => 'Modificar el tablero para « %s »',
'All projects' => 'Todos los proyectos', 'All projects' => 'Todos los proyectos',
'Change columns' => 'Cambiar las columnas', 'Change columns' => 'Cambiar las columnas',
'Add a new column' => 'Añadir una nueva columna', 'Add a new column' => 'Añadir una nueva columna',
'Title' => 'Titulo', 'Title' => 'Título',
'Nobody assigned' => 'Nadie asignado', 'Nobody assigned' => 'Nadie asignado',
'Assigned to %s' => 'Asignada a %s', 'Assigned to %s' => 'Asignada a %s',
'Remove a column' => 'Suprimir esta columna', 'Remove a column' => 'Suprimir esta columna',
'Remove a column from a board' => 'Suprimir una columna de un tablero', 'Remove a column from a board' => 'Suprimir una columna de un tablero',
'Unable to remove this column.' => 'No se puede suprimir esta columna.', 'Unable to remove this column.' => 'No se puede suprimir esta columna.',
'Do you really want to remove this column: "%s"?' => '¿De vedad que deseas eliminar esta columna : « %s » ?', 'Do you really want to remove this column: "%s"?' => '¿De vedad que desea eliminar esta columna : « %s » ?',
'This action will REMOVE ALL TASKS associated to this column!' => '¡Esta acción SUPRIMIRÁ TODAS LAS TAREAS asociadas a esta columna!', 'This action will REMOVE ALL TASKS associated to this column!' => '¡Esta acción SUPRIMIRÁ TODAS LAS TAREAS asociadas a esta columna!',
'Settings' => 'Preferencias', 'Settings' => 'Preferencias',
'Application settings' => 'Parámetros de la aplicación', 'Application settings' => 'Parámetros de la aplicación',
@ -96,13 +96,13 @@ return array(
'Edit a task' => 'Editar una tarea', 'Edit a task' => 'Editar una tarea',
'Column' => 'Columna', 'Column' => 'Columna',
'Color' => 'Color', 'Color' => 'Color',
'Assignee' => 'Persona asignada', 'Assignee' => 'Concesionario',
'Create another task' => 'Crear una nueva tarea', 'Create another task' => 'Crear una nueva tarea',
'New task' => 'Nueva tarea', 'New task' => 'Nueva tarea',
'Open a task' => 'Abrir una tarea', 'Open a task' => 'Abrir una tarea',
'Do you really want to open this task: "%s"?' => '¿Realmente desea abrir esta tarea: « %s » ?', 'Do you really want to open this task: "%s"?' => '¿Realmente desea abrir esta tarea: « %s » ?',
'Back to the board' => 'Volver al tablero', 'Back to the board' => 'Volver al tablero',
'Created on %B %e, %Y at %k:%M %p' => 'Creado el %d/%m/%Y a las %H:%M', 'Created on %B %e, %Y at %k:%M %p' => 'Creado el %e de %B de %Y a las %k:%M %p',
'There is nobody assigned' => 'No hay nadie asignado a esta tarea', 'There is nobody assigned' => 'No hay nadie asignado a esta tarea',
'Column on the board:' => 'Columna en el tablero: ', 'Column on the board:' => 'Columna en el tablero: ',
'Status is open' => 'Estado abierto', 'Status is open' => 'Estado abierto',
@ -111,12 +111,12 @@ return array(
'Open this task' => 'Abrir esta tarea', 'Open this task' => 'Abrir esta tarea',
'There is no description.' => 'No hay descripción.', 'There is no description.' => 'No hay descripción.',
'Add a new task' => 'Añadir una nueva tarea', 'Add a new task' => 'Añadir una nueva tarea',
'The username is required' => 'El nombre de usuario es obligatorio', 'The username is required' => 'El nombre del usuario es obligatorio',
'The maximum length is %d characters' => 'La longitud máxima es de %d caracteres', 'The maximum length is %d characters' => 'La longitud máxima es de %d caracteres',
'The minimum length is %d characters' => 'La longitud mínima es de %d caracteres', 'The minimum length is %d characters' => 'La longitud mínima es de %d caracteres',
'The password is required' => 'La contraseña es obligatoria', 'The password is required' => 'La contraseña es obligatoria',
'This value must be an integer' => 'Este valor debe ser un entero', 'This value must be an integer' => 'Este valor debe ser un entero',
'The username must be unique' => 'El nombre de usuario debe ser único', 'The username must be unique' => 'El nombre del usuario debe ser único',
'The user id is required' => 'El identificador del usuario es obligatorio', 'The user id is required' => 'El identificador del usuario es obligatorio',
'Passwords don\'t match' => 'Las contraseñas no coinciden', 'Passwords don\'t match' => 'Las contraseñas no coinciden',
'The confirmation is required' => 'La confirmación es obligatoria', 'The confirmation is required' => 'La confirmación es obligatoria',
@ -125,7 +125,7 @@ return array(
'The project id is required' => 'El identificador del proyecto es obligatorio', 'The project id is required' => 'El identificador del proyecto es obligatorio',
'The project name is required' => 'El nombre del proyecto es obligatorio', 'The project name is required' => 'El nombre del proyecto es obligatorio',
'This project must be unique' => 'El nombre del proyecto debe ser único', 'This project must be unique' => 'El nombre del proyecto debe ser único',
'The title is required' => 'El titulo es obligatorio', 'The title is required' => 'El título es obligatorio',
'Settings saved successfully.' => 'Parámetros guardados correctamente.', 'Settings saved successfully.' => 'Parámetros guardados correctamente.',
'Unable to save your settings.' => 'No se pueden guardar sus parámetros.', 'Unable to save your settings.' => 'No se pueden guardar sus parámetros.',
'Database optimization done.' => 'Optimización de la base de datos terminada.', 'Database optimization done.' => 'Optimización de la base de datos terminada.',
@ -159,8 +159,8 @@ return array(
'Work in progress' => 'En curso', 'Work in progress' => 'En curso',
'Done' => 'Hecho', 'Done' => 'Hecho',
'Application version:' => 'Versión de la aplicación:', 'Application version:' => 'Versión de la aplicación:',
'Completed on %B %e, %Y at %k:%M %p' => 'Completado el %d/%m/%Y a las %H:%M', 'Completed on %B %e, %Y at %k:%M %p' => 'Completado el %e de %B de %Y a las %k:%M %p',
'%B %e, %Y at %k:%M %p' => '%d/%m/%Y a las %H:%M', '%B %e, %Y at %k:%M %p' => '%e de %B de %Y a las %k:%M %p',
'Date created' => 'Fecha de creación', 'Date created' => 'Fecha de creación',
'Date completed' => 'Fecha de terminación', 'Date completed' => 'Fecha de terminación',
'Id' => 'Identificador', 'Id' => 'Identificador',
@ -168,16 +168,16 @@ return array(
'No task for this project' => 'Ninguna tarea para este proyecto', 'No task for this project' => 'Ninguna tarea para este proyecto',
'Public link' => 'Vinculación pública', 'Public link' => 'Vinculación pública',
'There is no column in your project!' => '¡No hay ninguna columna para este proyecto!', 'There is no column in your project!' => '¡No hay ninguna columna para este proyecto!',
'Change assignee' => 'Cambiar la persona asignada', 'Change assignee' => 'Cambiar concesionario',
'Change assignee for the task "%s"' => 'Cambiar la persona asignada por la tarea « %s »', 'Change assignee for the task "%s"' => 'Cambiar el concesionario para la tarea « %s »',
'Timezone' => 'Zona horaria', 'Timezone' => 'Zona horaria',
'Sorry, I didn\'t find this information in my database!' => 'Lo siento no he encontrado información en la base de datos!', 'Sorry, I didn\'t find this information in my database!' => '¡Lo siento no he encontrado esta información en mi base de datos!',
'Page not found' => 'Página no encontrada', 'Page not found' => 'Página no encontrada',
'Complexity' => 'Complejidad', 'Complexity' => 'Complejidad',
'Task limit' => 'Número máximo de tareas', 'Task limit' => 'Número máximo de tareas',
'Task count' => 'Contador de tareas', 'Task count' => 'Contador de tareas',
'Edit project access list' => 'Editar los permisos del proyecto', 'Edit project access list' => 'Editar los permisos del proyecto',
'Allow this user' => 'Autorizar este usuario', 'Allow this user' => 'Autorizar a este usuario',
'Don\'t forget that administrators have access to everything.' => 'No olvide que los administradores tienen acceso a todo.', 'Don\'t forget that administrators have access to everything.' => 'No olvide que los administradores tienen acceso a todo.',
'Revoke' => 'Revocar', 'Revoke' => 'Revocar',
'List of authorized users' => 'Lista de los usuarios autorizados', 'List of authorized users' => 'Lista de los usuarios autorizados',
@ -193,9 +193,9 @@ return array(
'Edit this task' => 'Editar esta tarea', 'Edit this task' => 'Editar esta tarea',
'Due Date' => 'Fecha límite', 'Due Date' => 'Fecha límite',
'Invalid date' => 'Fecha no válida', 'Invalid date' => 'Fecha no válida',
'Must be done before %B %e, %Y' => 'Debe de estar hecho antes del %d/%m/%Y', 'Must be done before %B %e, %Y' => 'Debe de estar hecho antes del %e de %B de %Y',
'%B %e, %Y' => '%d/%m/%Y', '%B %e, %Y' => '%e de %B de %Y',
// '%b %e, %Y' => '', '%b %e, %Y' => '%e de %B de %Y',
'Automatic actions' => 'Acciones automatizadas', 'Automatic actions' => 'Acciones automatizadas',
'Your automatic action have been created successfully.' => 'La acción automatizada ha sido creada correctamente.', 'Your automatic action have been created successfully.' => 'La acción automatizada ha sido creada correctamente.',
'Unable to create your automatic action.' => 'No se puede crear esta acción automatizada.', 'Unable to create your automatic action.' => 'No se puede crear esta acción automatizada.',
@ -264,13 +264,13 @@ return array(
'%d comment' => '%d comentario', '%d comment' => '%d comentario',
'Email address invalid' => 'Dirección de correo inválida', 'Email address invalid' => 'Dirección de correo inválida',
'Your external account is not linked anymore to your profile.' => 'Su cuenta externa se ha desvinculado de su perfil.', 'Your external account is not linked anymore to your profile.' => 'Su cuenta externa se ha desvinculado de su perfil.',
'Unable to unlink your external account.' => 'Imposible desvincular cuenta externa.', 'Unable to unlink your external account.' => 'Imposible desvincular su cuenta externa.',
'External authentication failed' => 'Falló la autenticación externa', 'External authentication failed' => 'Falló la autenticación externa',
'Your external account is linked to your profile successfully.' => 'Su cuenta externa se ha vinculado exitosamente con su perfil.', 'Your external account is linked to your profile successfully.' => 'Su cuenta externa se ha vinculado exitosamente con su perfil.',
'Email' => 'Correo', 'Email' => 'Correo',
'Link my Google Account' => 'Vincular con mi Cuenta en Google', 'Link my Google Account' => 'Vincular con mi Cuenta en Google',
'Unlink my Google Account' => 'Desvincular de mi Cuenta en Google', 'Unlink my Google Account' => 'Desvincular de mi Cuenta en Google',
'Login with my Google Account' => 'Ingresar con mi Cuenta en Google', 'Login with my Google Account' => 'Ingresar con mi Cuenta de Google',
'Project not found.' => 'Proyecto no hallado.', 'Project not found.' => 'Proyecto no hallado.',
'Task removed successfully.' => 'Tarea suprimida correctamente.', 'Task removed successfully.' => 'Tarea suprimida correctamente.',
'Unable to remove this task.' => 'No pude suprimir esta tarea.', 'Unable to remove this task.' => 'No pude suprimir esta tarea.',
@ -283,10 +283,10 @@ return array(
'Category:' => 'Categoría:', 'Category:' => 'Categoría:',
'Categories' => 'Categorías', 'Categories' => 'Categorías',
'Category not found.' => 'Categoría no hallada.', 'Category not found.' => 'Categoría no hallada.',
'Your category have been created successfully.' => 'Se ha creado tu categoría correctamente.', 'Your category have been created successfully.' => 'Se ha creado su categoría correctamente.',
'Unable to create your category.' => 'No pude crear tu categoría.', 'Unable to create your category.' => 'No pude crear su categoría.',
'Your category have been updated successfully.' => 'Se ha actualizado tu categoría correctamente.', 'Your category have been updated successfully.' => 'Se ha actualizado su categoría correctamente.',
'Unable to update your category.' => 'No pude actualizar tu categoría.', 'Unable to update your category.' => 'No pude actualizar su categoría.',
'Remove a category' => 'Suprimir una categoría', 'Remove a category' => 'Suprimir una categoría',
'Category removed successfully.' => 'Categoría suprimida correctamente.', 'Category removed successfully.' => 'Categoría suprimida correctamente.',
'Unable to remove this category.' => 'No pude suprimir esta categoría.', 'Unable to remove this category.' => 'No pude suprimir esta categoría.',
@ -301,7 +301,7 @@ return array(
'Unable to remove this file.' => 'No pude borrar este fichero.', 'Unable to remove this file.' => 'No pude borrar este fichero.',
'File removed successfully.' => 'Fichero borrado correctamente.', 'File removed successfully.' => 'Fichero borrado correctamente.',
'Attach a document' => 'Adjuntar un documento', 'Attach a document' => 'Adjuntar un documento',
'Do you really want to remove this file: "%s"?' => '¿De verdad que quieres borrar este fichero: "%s"?', 'Do you really want to remove this file: "%s"?' => '¿De verdad que quiere borrar este fichero: "%s"?',
'open' => 'abrir', 'open' => 'abrir',
'Attachments' => 'Adjuntos', 'Attachments' => 'Adjuntos',
'Edit the task' => 'Editar la tarea', 'Edit the task' => 'Editar la tarea',
@ -312,8 +312,8 @@ return array(
'Time tracking' => 'Seguimiento temporal', 'Time tracking' => 'Seguimiento temporal',
'Estimate:' => 'Estimado:', 'Estimate:' => 'Estimado:',
'Spent:' => 'Transcurrido:', 'Spent:' => 'Transcurrido:',
'Do you really want to remove this sub-task?' => '¿De verdad que quieres suprimir esta sub-tarea?', 'Do you really want to remove this sub-task?' => '¿De verdad que quiere suprimir esta sub-tarea?',
'Remaining:' => 'Quedando', 'Remaining:' => 'Restante:',
'hours' => 'horas', 'hours' => 'horas',
'spent' => 'transcurrido', 'spent' => 'transcurrido',
'estimated' => 'estimado', 'estimated' => 'estimado',
@ -330,8 +330,8 @@ return array(
'Sub-task removed successfully.' => 'Sub-tarea suprimida correctamente.', 'Sub-task removed successfully.' => 'Sub-tarea suprimida correctamente.',
'Unable to remove this sub-task.' => 'No pude suprimir esta sub-tarea.', 'Unable to remove this sub-task.' => 'No pude suprimir esta sub-tarea.',
'Sub-task updated successfully.' => 'Sub-tarea actualizada correctamente.', 'Sub-task updated successfully.' => 'Sub-tarea actualizada correctamente.',
'Unable to update your sub-task.' => 'No pude actualizar tu sub-tarea.', 'Unable to update your sub-task.' => 'No pude actualizar su sub-tarea.',
'Unable to create your sub-task.' => 'No pude crear tu sub-tarea.', 'Unable to create your sub-task.' => 'No pude crear su sub-tarea.',
'Sub-task added successfully.' => 'Sub-tarea añadida correctamente.', 'Sub-task added successfully.' => 'Sub-tarea añadida correctamente.',
'Maximum size: ' => 'Tamaño máximo', 'Maximum size: ' => 'Tamaño máximo',
'Unable to upload the file.' => 'No pude cargar el fichero.', 'Unable to upload the file.' => 'No pude cargar el fichero.',
@ -340,7 +340,7 @@ return array(
'Link my Github Account' => 'Vincular mi cuenta de Github', 'Link my Github Account' => 'Vincular mi cuenta de Github',
'Unlink my Github Account' => 'Desvincular mi cuenta de Github', 'Unlink my Github Account' => 'Desvincular mi cuenta de Github',
'Created by %s' => 'Creado por %s', 'Created by %s' => 'Creado por %s',
'Last modified on %B %e, %Y at %k:%M %p' => 'Última modificación %B %e, %Y a las %k:%M %p', 'Last modified on %B %e, %Y at %k:%M %p' => 'Última modificación %e de %B de %Y a las %k:%M %p',
'Tasks Export' => 'Exportar tareas', 'Tasks Export' => 'Exportar tareas',
'Tasks exportation for "%s"' => 'Exportación de tareas para "%s"', 'Tasks exportation for "%s"' => 'Exportación de tareas para "%s"',
'Start Date' => 'Fecha de inicio', 'Start Date' => 'Fecha de inicio',
@ -361,7 +361,7 @@ return array(
'Sub-task updated' => 'Subtarea actualizada', 'Sub-task updated' => 'Subtarea actualizada',
'Title:' => 'Título:', 'Title:' => 'Título:',
'Status:' => 'Estado:', 'Status:' => 'Estado:',
'Assignee:' => 'Asignada a:', 'Assignee:' => 'Concesionario:',
'Time tracking:' => 'Control de tiempo:', 'Time tracking:' => 'Control de tiempo:',
'New sub-task' => 'Nueva subtarea', 'New sub-task' => 'Nueva subtarea',
'New attachment added "%s"' => 'Nuevo adjunto agregado "%s"', 'New attachment added "%s"' => 'Nuevo adjunto agregado "%s"',
@ -382,19 +382,19 @@ return array(
'Disable public access' => 'Desactivar acceso público', 'Disable public access' => 'Desactivar acceso público',
'Enable public access' => 'Activar acceso público', 'Enable public access' => 'Activar acceso público',
'Public access disabled' => 'Acceso público desactivado', 'Public access disabled' => 'Acceso público desactivado',
'Do you really want to disable this project: "%s"?' => '¿Realmente deseas desactivar este proyecto: "%s"?', 'Do you really want to disable this project: "%s"?' => '¿Realmente desea desactivar este proyecto: "%s"?',
'Do you really want to enable this project: "%s"?' => '¿Realmente deseas activar este proyecto: "%s"?', 'Do you really want to enable this project: "%s"?' => '¿Realmente desea activar este proyecto: "%s"?',
'Project activation' => 'Activación de Proyecto', 'Project activation' => 'Activación de Proyecto',
'Move the task to another project' => 'Mover la tarea a otro proyecto', 'Move the task to another project' => 'Mover la tarea a otro proyecto',
'Move to another project' => 'Mover a otro proyecto', 'Move to another project' => 'Mover a otro proyecto',
'Do you really want to duplicate this task?' => '¿Realmente deseas duplicar esta tarea?', 'Do you really want to duplicate this task?' => '¿Realmente desea duplicar esta tarea?',
'Duplicate a task' => 'Duplicar una tarea', 'Duplicate a task' => 'Duplicar una tarea',
'External accounts' => 'Cuentas externas', 'External accounts' => 'Cuentas externas',
'Account type' => 'Tipo de Cuenta', 'Account type' => 'Tipo de Cuenta',
'Local' => 'Local', 'Local' => 'Local',
'Remote' => 'Remota', 'Remote' => 'Remota',
'Enabled' => 'Activada', 'Enabled' => 'Activada',
'Disabled' => 'Deactivada', 'Disabled' => 'Desactivada',
'Google account linked' => 'Vinculada con Cuenta de Google', 'Google account linked' => 'Vinculada con Cuenta de Google',
'Github account linked' => 'Vinculada con Cuenta de Gitgub', 'Github account linked' => 'Vinculada con Cuenta de Gitgub',
'Username:' => 'Nombre de Usuario:', 'Username:' => 'Nombre de Usuario:',
@ -432,7 +432,7 @@ return array(
'%s updated a comment on the task %s' => '%s actualizó un comentario de la tarea %s', '%s updated a comment on the task %s' => '%s actualizó un comentario de la tarea %s',
'%s commented the task %s' => '%s comentó la tarea %s', '%s commented the task %s' => '%s comentó la tarea %s',
'%s\'s activity' => 'Actividad de %s', '%s\'s activity' => 'Actividad de %s',
'RSS feed' => 'Fichero RSS', 'RSS feed' => 'Fuentes RSS',
'%s updated a comment on the task #%d' => '%s actualizó un comentario de la tarea #%d', '%s updated a comment on the task #%d' => '%s actualizó un comentario de la tarea #%d',
'%s commented on the task #%d' => '%s comentó la tarea #%d', '%s commented on the task #%d' => '%s comentó la tarea #%d',
'%s updated a subtask for the task #%d' => '%s actualizó una subtarea de la tarea #%d', '%s updated a subtask for the task #%d' => '%s actualizó una subtarea de la tarea #%d',
@ -446,41 +446,41 @@ return array(
'Activity' => 'Actividad', 'Activity' => 'Actividad',
'Default values are "%s"' => 'Los valores por defecto son "%s"', 'Default values are "%s"' => 'Los valores por defecto son "%s"',
'Default columns for new projects (Comma-separated)' => 'Columnas por defecto de los nuevos proyectos (Separadas mediante comas)', 'Default columns for new projects (Comma-separated)' => 'Columnas por defecto de los nuevos proyectos (Separadas mediante comas)',
'Task assignee change' => 'Cambiar persona asignada a la tarea', 'Task assignee change' => 'Cambiar concesionario de la tarea',
'%s change the assignee of the task #%d to %s' => '%s cambió el asignado de la tarea #%d por %s', '%s change the assignee of the task #%d to %s' => '%s cambió el concesionario de la tarea #%d por %s',
'%s changed the assignee of the task %s to %s' => '%s cambió el asignado de la tarea %s por %s', '%s changed the assignee of the task %s to %s' => '%s cambió el concesionario de la tarea %s por %s',
'New password for the user "%s"' => 'Nueva contraseña para el usuario "%s"', 'New password for the user "%s"' => 'Nueva contraseña para el usuario "%s"',
'Choose an event' => 'Escoga un evento', 'Choose an event' => 'Seleccione un evento',
'Github commit received' => 'Envío a Github recibido', 'Github commit received' => 'Envío a Github recibido',
'Github issue opened' => 'Problema en Github abierto', 'Github issue opened' => 'Abierto asunto en Github',
'Github issue closed' => 'Problema en Github cerrado', 'Github issue closed' => 'Cerrado asunto en Github',
'Github issue reopened' => 'Problema en Github reabierto', 'Github issue reopened' => 'Reabierto asunto en Github',
'Github issue assignee change' => 'Cambio en signación de problema en Github', 'Github issue assignee change' => 'Cambio en concesionario de asunto de Github',
'Github issue label change' => 'Cambio en etiqueta del problema', 'Github issue label change' => 'Cambio en etiqueta de asunto de Github',
'Create a task from an external provider' => 'Crear una tarea a partir de un proveedor externo', 'Create a task from an external provider' => 'Crear una tarea a partir de un proveedor externo',
'Change the assignee based on an external username' => 'Cambiar la asignación basado en un nombre de usuario externo', 'Change the assignee based on an external username' => 'Cambiar el concesionario basado en un nombre de usuario externo',
'Change the category based on an external label' => 'Cambiar la categoría basado en una etiqueta externa', 'Change the category based on an external label' => 'Cambiar la categoría basado en una etiqueta externa',
'Reference' => 'Referencia', 'Reference' => 'Referencia',
'Reference: %s' => 'Referencia: %s', 'Reference: %s' => 'Referencia: %s',
'Label' => 'Etiqueta', 'Label' => 'Etiqueta',
'Database' => 'Base de Datos', 'Database' => 'Base de Datos',
'About' => 'Acerca de', 'About' => 'Acerca de',
'Database driver:' => 'Driver de la base de datos', 'Database driver:' => 'Controlador (Driver) de la base de datos',
'Board settings' => 'Configuraciones del Tablero', 'Board settings' => 'Configuraciones del Tablero',
'URL and token' => 'URL y token', 'URL and token' => 'URL y ficha',
'Webhook settings' => 'Configuraciones del Disparador Web (Webhook)', 'Webhook settings' => 'Configuraciones del Disparador Web (Webhook)',
'URL for task creation:' => 'URL para la creación de tareas', 'URL for task creation:' => 'URL para la creación de tareas',
'Reset token' => 'Resetear token', 'Reset token' => 'Limpiar ficha',
'API endpoint:' => 'Punto final del API', 'API endpoint:' => 'Punto final del API',
'Refresh interval for private board' => 'Intervalo de refrescamiento del tablero privado', 'Refresh interval for private board' => 'Intervalo de refresco del tablero privado',
'Refresh interval for public board' => 'Intervalo de refrescamiento del tablero público', 'Refresh interval for public board' => 'Intervalo de refresco del tablero público',
'Task highlight period' => 'Periodo del realce de la tarea', 'Task highlight period' => 'Periodo de realce de la tarea',
'Period (in second) to consider a task was modified recently (0 to disable, 2 days by default)' => 'Periodo (en segundos) para considerar que una tarea fué modificada recientemente (0 para deshabilitar, 2 días por defecto)', 'Period (in second) to consider a task was modified recently (0 to disable, 2 days by default)' => 'Periodo (en segundos) para considerar que una tarea fué modificada recientemente (0 para deshabilitar, 2 días por defecto)',
'Frequency in second (60 seconds by default)' => 'Frecuencia en segundos (60 segundos por defecto)', 'Frequency in second (60 seconds by default)' => 'Frecuencia en segundos (60 segundos por defecto)',
'Frequency in second (0 to disable this feature, 10 seconds by default)' => 'Frecuencia en segundos (0 para deshabilitar esta característica, 10 segundos por defecto)', 'Frequency in second (0 to disable this feature, 10 seconds by default)' => 'Frecuencia en segundos (0 para deshabilitar esta característica, 10 segundos por defecto)',
'Application URL' => 'URL de la aplicación', 'Application URL' => 'URL de la aplicación',
'Example: http://example.kanboard.net/ (used by email notifications)' => 'Ejemplo: http://ejemplo.kanboard.net/ (usado por las notificaciones de correo)', 'Example: http://example.kanboard.net/ (used by email notifications)' => 'Ejemplo: http://ejemplo.kanboard.net/ (usado por las notificaciones de correo)',
'Token regenerated.' => 'Token regenerado', 'Token regenerated.' => 'Ficha regenerada.',
'Date format' => 'Formato de la fecha', 'Date format' => 'Formato de la fecha',
'ISO format is always accepted, example: "%s" and "%s"' => 'El formato ISO siempre es aceptado, ejemplo: "%s" y "%s"', 'ISO format is always accepted, example: "%s" and "%s"' => 'El formato ISO siempre es aceptado, ejemplo: "%s" y "%s"',
'New private project' => 'Nuevo proyecto privado', 'New private project' => 'Nuevo proyecto privado',
@ -489,16 +489,16 @@ return array(
'Add' => 'Añadir', 'Add' => 'Añadir',
'Estimated time: %s hours' => 'Tiempo estimado: %s horas', 'Estimated time: %s hours' => 'Tiempo estimado: %s horas',
'Time spent: %s hours' => 'Tiempo invertido: %s horas', 'Time spent: %s hours' => 'Tiempo invertido: %s horas',
'Started on %B %e, %Y' => 'Iniciado en %B %e, %Y', 'Started on %B %e, %Y' => 'Iniciado el %e de %B de %Y',
'Start date' => 'Fecha de inicio', 'Start date' => 'Fecha de inicio',
'Time estimated' => 'Tiempo estimado', 'Time estimated' => 'Tiempo estimado',
'There is nothing assigned to you.' => 'Esto no le está asignado', 'There is nothing assigned to you.' => 'No tiene nada asignado.',
'My tasks' => 'Mis tareas', 'My tasks' => 'Mis tareas',
'Activity stream' => 'Flujo de actividad', 'Activity stream' => 'Flujo de actividad',
'Dashboard' => 'Tablero', 'Dashboard' => 'Tablero',
'Confirmation' => 'Confirmación', 'Confirmation' => 'Confirmación',
'Allow everybody to access to this project' => 'Permitir a cualquier acceder a este proyecto', 'Allow everybody to access to this project' => 'Permitir a cualquiera acceder a este proyecto',
'Everybody have access to this project.' => 'Cualquier tiene acceso a este proyecto', 'Everybody have access to this project.' => 'Cualquiera tiene acceso a este proyecto',
'Webhooks' => 'Disparadores Web (Webhooks)', 'Webhooks' => 'Disparadores Web (Webhooks)',
'API' => 'API', 'API' => 'API',
'Github webhooks' => 'Disparadores Web (Webhooks) de Github', 'Github webhooks' => 'Disparadores Web (Webhooks) de Github',
@ -513,7 +513,7 @@ return array(
'Percentage' => 'Porcentaje', 'Percentage' => 'Porcentaje',
'Number of tasks' => 'Número de tareas', 'Number of tasks' => 'Número de tareas',
'Task distribution' => 'Distribución de tareas', 'Task distribution' => 'Distribución de tareas',
'Reportings' => 'Reportes', 'Reportings' => 'Informes',
'Task repartition for "%s"' => 'Repartición de tareas para "%s"', 'Task repartition for "%s"' => 'Repartición de tareas para "%s"',
'Analytics' => 'Analítica', 'Analytics' => 'Analítica',
'Subtask' => 'Subtarea', 'Subtask' => 'Subtarea',
@ -533,7 +533,7 @@ return array(
'The task id is required' => 'El id de la tarea es requerido', 'The task id is required' => 'El id de la tarea es requerido',
'The task id must be an integer' => 'El id de la tarea debe ser un entero', 'The task id must be an integer' => 'El id de la tarea debe ser un entero',
'The user id must be an integer' => 'El id del usuario debe ser un entero', 'The user id must be an integer' => 'El id del usuario debe ser un entero',
'This value is required' => 'El valor es requerido', 'This value is required' => 'Este valor es requerido',
'This value must be numeric' => 'Este valor debe ser numérico', 'This value must be numeric' => 'Este valor debe ser numérico',
'Unable to create this task.' => 'Imposible crear esta tarea', 'Unable to create this task.' => 'Imposible crear esta tarea',
'Cumulative flow diagram' => 'Diagrama de flujo acumulativo', 'Cumulative flow diagram' => 'Diagrama de flujo acumulativo',
@ -541,32 +541,32 @@ return array(
'Daily project summary' => 'Sumario diario del proyecto', 'Daily project summary' => 'Sumario diario del proyecto',
'Daily project summary export' => 'Exportar sumario diario del proyecto', 'Daily project summary export' => 'Exportar sumario diario del proyecto',
'Daily project summary export for "%s"' => 'Exportar sumario diario del proyecto para "%s"', 'Daily project summary export for "%s"' => 'Exportar sumario diario del proyecto para "%s"',
'Exports' => 'Exportar', 'Exports' => 'Exportaciones',
'This export contains the number of tasks per column grouped per day.' => 'Esta exportación contiene el número de tereas por columna agrupada por día', 'This export contains the number of tasks per column grouped per day.' => 'Esta exportación contiene el número de tereas por columna agrupada por día.',
'Nothing to preview...' => 'Nada que previsualizar...', 'Nothing to preview...' => 'Nada que previsualizar...',
'Preview' => 'Previsualizar', 'Preview' => 'Previsualizar',
'Write' => 'Escribir', 'Write' => 'Grabar',
'Active swimlanes' => 'Carriles activos', 'Active swimlanes' => 'Calles activas',
'Add a new swimlane' => 'Añadir nuevo carril', 'Add a new swimlane' => 'Añadir nueva calle',
'Change default swimlane' => 'Cambiar el carril por defecto', 'Change default swimlane' => 'Cambiar la calle por defecto',
'Default swimlane' => 'Carril por defecto', 'Default swimlane' => 'Calle por defecto',
'Do you really want to remove this swimlane: "%s"?' => '¿Realmente quiere remover este carril: "%s"?', 'Do you really want to remove this swimlane: "%s"?' => '¿Realmente quiere quitar esta calle: "%s"?',
'Inactive swimlanes' => 'Carriles inactivos', 'Inactive swimlanes' => 'Calles inactivas',
'Set project manager' => 'Asignar administrador del proyecto', 'Set project manager' => 'Asignar administrador del proyecto',
'Set project member' => 'Asignar miembro del proyecto', 'Set project member' => 'Asignar miembro del proyecto',
'Remove a swimlane' => 'Remover un carril', 'Remove a swimlane' => 'Quitar un calle',
'Rename' => 'Renombrar', 'Rename' => 'Renombrar',
'Show default swimlane' => 'Mostrar carril por defecto', 'Show default swimlane' => 'Mostrar calle por defecto',
'Swimlane modification for the project "%s"' => 'Modificación del carril para el proyecto "%s"', 'Swimlane modification for the project "%s"' => 'Modificación de la calle para el proyecto "%s"',
'Swimlane not found.' => 'Carril no encontrado', 'Swimlane not found.' => 'Calle no encontrada',
'Swimlane removed successfully.' => 'Carril eliminado correctamente', 'Swimlane removed successfully.' => 'Caalle eliminada correctamente',
'Swimlanes' => 'Carriles', 'Swimlanes' => 'Calles',
'Swimlane updated successfully.' => 'Carril actualizado correctamente', 'Swimlane updated successfully.' => 'Calle actualizada correctamente',
'The default swimlane have been updated successfully.' => 'El carril por defecto ha sido actualizado correctamente', 'The default swimlane have been updated successfully.' => 'La calle por defecto ha sido actualizada correctamente',
'Unable to create your swimlane.' => 'Imposible crear su carril', 'Unable to create your swimlane.' => 'Imposible crear su calle',
'Unable to remove this swimlane.' => 'Imposible remover este carril', 'Unable to remove this swimlane.' => 'Imposible de quitar esta calle',
'Unable to update this swimlane.' => 'Imposible actualizar este carril', 'Unable to update this swimlane.' => 'Imposible de actualizar esta calle',
'Your swimlane have been created successfully.' => 'Su carril ha sido creado correctamente', 'Your swimlane have been created successfully.' => 'Su calle ha sido creada correctamente',
'Example: "Bug, Feature Request, Improvement"' => 'Ejemplo: "Error, Solicitud de característica, Mejora', 'Example: "Bug, Feature Request, Improvement"' => 'Ejemplo: "Error, Solicitud de característica, Mejora',
'Default categories for new projects (Comma-separated)' => 'Categorías por defecto para nuevos proyectos (separadas por comas)', 'Default categories for new projects (Comma-separated)' => 'Categorías por defecto para nuevos proyectos (separadas por comas)',
'Gitlab commit received' => 'Recibido envío desde Gitlab', 'Gitlab commit received' => 'Recibido envío desde Gitlab',
@ -577,9 +577,9 @@ return array(
'Integrations' => 'Integraciones', 'Integrations' => 'Integraciones',
'Integration with third-party services' => 'Integración con servicios de terceros', 'Integration with third-party services' => 'Integración con servicios de terceros',
'Role for this project' => 'Papel de este proyecto', 'Role for this project' => 'Papel de este proyecto',
'Project manager' => 'Gestor de proyecto', 'Project manager' => 'Administrador de proyecto',
'Project member' => 'Miembro de proyecto', 'Project member' => 'Miembro de proyecto',
'A project manager can change the settings of the project and have more privileges than a standard user.' => 'Un gestor de proyecto puede cambiar sus valores y tener más privilegios que un usuario estándar.', 'A project manager can change the settings of the project and have more privileges than a standard user.' => 'Un administrador de proyecto puede cambiar sus valores y tener más privilegios que un usuario estándar.',
'Gitlab Issue' => 'Asunto Gitlab', 'Gitlab Issue' => 'Asunto Gitlab',
'Subtask Id' => 'Id de Subtarea', 'Subtask Id' => 'Id de Subtarea',
'Subtasks' => 'Subtareas', 'Subtasks' => 'Subtareas',
@ -593,8 +593,8 @@ return array(
'All columns' => 'Todas las columnas', 'All columns' => 'Todas las columnas',
'Calendar' => 'Calendario', 'Calendar' => 'Calendario',
'Next' => 'Siguiente', 'Next' => 'Siguiente',
// '#%d' => '', '#%d' => '#%d',
'All swimlanes' => 'Todos los carriles', 'All swimlanes' => 'Todas las calles',
'All colors' => 'Todos los colores', 'All colors' => 'Todos los colores',
'All status' => 'Todos los estados', 'All status' => 'Todos los estados',
'Moved to column %s' => 'Movido a columna %s', 'Moved to column %s' => 'Movido a columna %s',
@ -607,20 +607,20 @@ return array(
'There is nothing to show.' => 'Nada que mostrar', 'There is nothing to show.' => 'Nada que mostrar',
'Time Tracking' => 'Seguimiento Temporal', 'Time Tracking' => 'Seguimiento Temporal',
'You already have one subtask in progress' => 'Ya dispones de una subtarea en progreso', 'You already have one subtask in progress' => 'Ya dispones de una subtarea en progreso',
'Which parts of the project do you want to duplicate?' => '¿Qué partes del proyecto deseas duplicar?', 'Which parts of the project do you want to duplicate?' => '¿Qué partes del proyecto desea duplicar?',
'Disallow login form' => 'Deshabilitar formulario de ingreso', 'Disallow login form' => 'Deshabilitar formulario de ingreso',
'Bitbucket commit received' => 'Recibida envío desde Bitbucket', 'Bitbucket commit received' => 'Recibido envío desde Bitbucket',
'Bitbucket webhooks' => 'Disparadores Web (webhooks) de Bitbucket', 'Bitbucket webhooks' => 'Disparadores Web (webhooks) de Bitbucket',
'Help on Bitbucket webhooks' => 'Ayuda sobre disparadores web (webhooks) de Bitbucket', 'Help on Bitbucket webhooks' => 'Ayuda sobre disparadores web (webhooks) de Bitbucket',
'Start' => 'Inicio', 'Start' => 'Inicio',
'End' => 'Fin', 'End' => 'Fin',
'Task age in days' => 'Edad de la tarea en días', 'Task age in days' => 'Edad de la tarea en días',
'Days in this column' => 'Días en esta columna', 'Days in this column' => 'Días en esta columna',
// '%dd' => '', '%dd' => '%dd',
'Add a link' => 'Añadir enlace', 'Add a link' => 'Añadir enlace',
'Add a new link' => 'Añadir nuevo enlace', 'Add a new link' => 'Añadir nuevo enlace',
'Do you really want to remove this link: "%s"?' => '¿Realmente quieres quitar este enlace: "%s"?', 'Do you really want to remove this link: "%s"?' => '¿Realmente quiere quitar este enlace: "%s"?',
'Do you really want to remove this link with task #%d?' => '¿Realmente quieres quitar este enlace con esta tarea: #%d?', 'Do you really want to remove this link with task #%d?' => '¿Realmente quiere quitar este enlace con esta tarea: #%d?',
'Field required' => 'Es necesario el campo', 'Field required' => 'Es necesario el campo',
'Link added successfully.' => 'Enlace añadido con éxito.', 'Link added successfully.' => 'Enlace añadido con éxito.',
'Link updated successfully.' => 'Enlace actualizado con éxito', 'Link updated successfully.' => 'Enlace actualizado con éxito',
@ -650,9 +650,9 @@ return array(
'fixes' => 'arregla', 'fixes' => 'arregla',
'is fixed by' => 'arreglado por', 'is fixed by' => 'arreglado por',
'This task' => 'Esta tarea', 'This task' => 'Esta tarea',
// '<1h' => '', '<1h' => '<1h',
// '%dh' => '', '%dh' => '%dh',
// '%b %e' => '', '%b %e' => '%e de %b',
'Expand tasks' => 'Espande tareas', 'Expand tasks' => 'Espande tareas',
'Collapse tasks' => 'Colapsa tareas', 'Collapse tasks' => 'Colapsa tareas',
'Expand/collapse tasks' => 'Expande/colapasa tareas', 'Expand/collapse tasks' => 'Expande/colapasa tareas',
@ -662,13 +662,13 @@ return array(
'Keyboard shortcuts' => 'Atajos de teclado', 'Keyboard shortcuts' => 'Atajos de teclado',
'Open board switcher' => 'Abrir conmutador de tablero', 'Open board switcher' => 'Abrir conmutador de tablero',
'Application' => 'Aplicación', 'Application' => 'Aplicación',
'since %B %e, %Y at %k:%M %p' => 'desde %B %e, %Y a las %k:%M %p', 'since %B %e, %Y at %k:%M %p' => 'desde %e de %B de %Y a las %k:%M %p',
'Compact view' => 'Compactar vista', 'Compact view' => 'Compactar vista',
'Horizontal scrolling' => 'Desplazamiento horizontal', 'Horizontal scrolling' => 'Desplazamiento horizontal',
'Compact/wide view' => 'Vista compacta/amplia', 'Compact/wide view' => 'Vista compacta/amplia',
'No results match:' => 'No hay resultados coincidentes:', 'No results match:' => 'No hay resultados coincidentes:',
'Remove hourly rate' => 'Quitar cobro horario', 'Remove hourly rate' => 'Quitar cobro horario',
'Do you really want to remove this hourly rate?' => '¿Realmente quires quitar el cobro horario?', 'Do you really want to remove this hourly rate?' => '¿Realmente quire quitar el cobro horario?',
'Hourly rates' => 'Cobros horarios', 'Hourly rates' => 'Cobros horarios',
'Hourly rate' => 'Cobro horario', 'Hourly rate' => 'Cobro horario',
'Currency' => 'Moneda', 'Currency' => 'Moneda',
@ -690,17 +690,17 @@ return array(
'Work timetable' => 'Horario de trabajo', 'Work timetable' => 'Horario de trabajo',
'Week timetable' => 'Horario semanal', 'Week timetable' => 'Horario semanal',
'Day timetable' => 'Horario diario', 'Day timetable' => 'Horario diario',
'From' => 'Desde', 'From' => 'De',
'To' => 'Hasta', 'To' => 'Para',
'Time slot created successfully.' => 'Tiempo asignado creado correctamente.', 'Time slot created successfully.' => 'Intervalo de tiempo creado correctamente.',
'Unable to save this time slot.' => 'No pude grabar este tiempo asignado.', 'Unable to save this time slot.' => 'No pude grabar este intervalo de tiempo.',
'Time slot removed successfully.' => 'Tiempo asignado quitado correctamente.', 'Time slot removed successfully.' => 'Intervalo de tiempo quitado correctamente.',
'Unable to remove this time slot.' => 'No pude quitar este tiempo asignado.', 'Unable to remove this time slot.' => 'No pude quitar este intervalo de tiempo.',
'Do you really want to remove this time slot?' => '¿Realmente quieres quitar este tiempo asignado?', 'Do you really want to remove this time slot?' => '¿Realmente quiere quitar este intervalo de tiempo?',
'Remove time slot' => 'Quitar tiempo asignado', 'Remove time slot' => 'Quitar intervalo de tiempo',
'Add new time slot' => 'Añadir nuevo tiempo asignado', 'Add new time slot' => 'Añadir nuevo intervalo de tiempo',
'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => 'Este horario se usa cuando se marca la casilla "todos los días" para calendario de tiempo libre y horas extras.', 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => 'Este horario se usa cuando se marca la casilla "todos los días" para calendario de tiempo libre y horas extras.',
'Files' => 'Archivos', 'Files' => 'Ficheros',
'Images' => 'Imágenes', 'Images' => 'Imágenes',
'Private project' => 'Proyecto privado', 'Private project' => 'Proyecto privado',
'Amount' => 'Cantidad', 'Amount' => 'Cantidad',
@ -715,7 +715,7 @@ return array(
'Cost breakdown' => 'Desglose de costes', 'Cost breakdown' => 'Desglose de costes',
'Custom Stylesheet' => 'Hoja de estilo Personalizada', 'Custom Stylesheet' => 'Hoja de estilo Personalizada',
'download' => 'descargar', 'download' => 'descargar',
'Do you really want to remove this budget line?' => '¿Realmente quieres quitar esta línea de presupuesto?', 'Do you really want to remove this budget line?' => '¿Realmente quiere quitar esta línea de presupuesto?',
'EUR - Euro' => 'EUR - Euro', 'EUR - Euro' => 'EUR - Euro',
'Expenses' => 'Gastos', 'Expenses' => 'Gastos',
'GBP - British Pound' => 'GBP - Libra británica', 'GBP - British Pound' => 'GBP - Libra británica',
@ -733,9 +733,9 @@ return array(
'Remaining' => 'Restante', 'Remaining' => 'Restante',
'Destination column' => 'Columna destino', 'Destination column' => 'Columna destino',
'Move the task to another column when assigned to a user' => 'Mover la tarea a otra columna al asignarse al usuario', 'Move the task to another column when assigned to a user' => 'Mover la tarea a otra columna al asignarse al usuario',
'Move the task to another column when assignee is cleared' => 'Mover la tarea a otra columna al quitar el asignado', 'Move the task to another column when assignee is cleared' => 'Mover la tarea a otra columna al quitar el concesionario',
'Source column' => 'Columna fuente', 'Source column' => 'Columna fuente',
'Show subtask estimates (forecast of future work)' => 'Mostrar estimado para la subtarea (pronóstico de trabajo futuro)', 'Show subtask estimates (forecast of future work)' => 'Mostrar estimaciones para la subtarea (pronóstico de trabajo futuro)',
'Transitions' => 'Transiciones', 'Transitions' => 'Transiciones',
'Executer' => 'Ejecutor', 'Executer' => 'Ejecutor',
'Time spent in the column' => 'Tiempo transcurrido en la columna', 'Time spent in the column' => 'Tiempo transcurrido en la columna',
@ -753,7 +753,7 @@ return array(
'Send notifications to a Slack channel' => 'Enviar notificaciones a un canal Desatendido', 'Send notifications to a Slack channel' => 'Enviar notificaciones a un canal Desatendido',
'Webhook URL' => 'URL de Disparador Web (webhook)', 'Webhook URL' => 'URL de Disparador Web (webhook)',
'Help on Slack integration' => 'Ayuda sobre integración Desatendida', 'Help on Slack integration' => 'Ayuda sobre integración Desatendida',
'%s remove the assignee of the task %s' => '%s quita el asignado de la tarea %s', '%s remove the assignee of the task %s' => '%s quita el concesionario de la tarea %s',
'Send notifications to Hipchat' => 'Enviar notificaciones a Hipchat', 'Send notifications to Hipchat' => 'Enviar notificaciones a Hipchat',
'API URL' => 'URL de API', 'API URL' => 'URL de API',
'Room API ID or name' => 'ID de API de habitación o nombre', 'Room API ID or name' => 'ID de API de habitación o nombre',
@ -768,10 +768,10 @@ return array(
'Two factor authentication' => 'Autenticación de dos factores', 'Two factor authentication' => 'Autenticación de dos factores',
'Enable/disable two factor authentication' => 'Activar/desactivar autenticación de dos factores', 'Enable/disable two factor authentication' => 'Activar/desactivar autenticación de dos factores',
'This QR code contains the key URI: ' => 'Este código QR contiene la clave URI: ', 'This QR code contains the key URI: ' => 'Este código QR contiene la clave URI: ',
'Save the secret key in your TOTP software (by example Google Authenticator or FreeOTP).' => 'Guarda la clave secreta en tu software TOTP (por ejemplo Autenticación Google o FreeOTP).', 'Save the secret key in your TOTP software (by example Google Authenticator or FreeOTP).' => 'Guarda la clave secreta en su software TOTP (por ejemplo Autenticación de Google o FreeOTP).',
'Check my code' => 'Revisar mi código', 'Check my code' => 'Revisar mi código',
'Secret key: ' => 'Clave secreta: ', 'Secret key: ' => 'Clave secreta: ',
'Test your device' => 'Probar tu dispositivo', 'Test your device' => 'Probar su dispositivo',
'Assign a color when the task is moved to a specific column' => 'Asignar un color al mover la tarea a una columna específica', 'Assign a color when the task is moved to a specific column' => 'Asignar un color al mover la tarea a una columna específica',
'%s via Kanboard' => '%s vía Kanboard', '%s via Kanboard' => '%s vía Kanboard',
'uploaded by: %s' => 'cargado por: %s', 'uploaded by: %s' => 'cargado por: %s',
@ -785,7 +785,7 @@ return array(
'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => 'Capture un patallazo y pulse CTRL+V o ⌘+V para pegar aquí.', 'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => 'Capture un patallazo y pulse CTRL+V o ⌘+V para pegar aquí.',
'Screenshot uploaded successfully.' => 'Pantallazo cargado con éxito', 'Screenshot uploaded successfully.' => 'Pantallazo cargado con éxito',
'SEK - Swedish Krona' => 'SEK - Corona sueca', 'SEK - Swedish Krona' => 'SEK - Corona sueca',
'The project identifier is an optional alphanumeric code used to identify your project.' => 'El identificador del proyecto us un código opcional alfanumérico que se usa para identificar tu proyecto.', 'The project identifier is an optional alphanumeric code used to identify your project.' => 'El identificador del proyecto us un código opcional alfanumérico que se usa para identificar su proyecto.',
'Identifier' => 'Identificador', 'Identifier' => 'Identificador',
'Postmark (incoming emails)' => 'Matasellos (emails entrantes)', 'Postmark (incoming emails)' => 'Matasellos (emails entrantes)',
'Help on Postmark integration' => 'Ayuda sobre la integración de Matasellos', 'Help on Postmark integration' => 'Ayuda sobre la integración de Matasellos',
@ -794,37 +794,37 @@ return array(
'Sendgrid (incoming emails)' => 'Sendgrid (emails entrantes)', 'Sendgrid (incoming emails)' => 'Sendgrid (emails entrantes)',
'Help on Sendgrid integration' => 'Ayuda sobre la integración con Sendgrid', 'Help on Sendgrid integration' => 'Ayuda sobre la integración con Sendgrid',
'Disable two factor authentication' => 'Desactivar la autenticación de dos factores', 'Disable two factor authentication' => 'Desactivar la autenticación de dos factores',
'Do you really want to disable the two factor authentication for this user: "%s"?' => '¿Realmentes quieres desactuvar la autenticación de dos factores para este usuario: "%s?"', 'Do you really want to disable the two factor authentication for this user: "%s"?' => '¿Realmentes quiere desactuvar la autenticación de dos factores para este usuario: "%s?"',
'Edit link' => 'Editar enlace', 'Edit link' => 'Editar enlace',
'Start to type task title...' => 'Empiece a escribir el título de la tarea...', 'Start to type task title...' => 'Empiece a escribir el título de la tarea...',
'A task cannot be linked to itself' => 'Una tarea no puede se enlazada con sí misma', 'A task cannot be linked to itself' => 'Una tarea no puede se enlazada con sigo misma',
'The exact same link already exists' => 'El mismo enlace ya existe', 'The exact same link already exists' => 'El mismo enlace ya existe',
'Recurrent task is scheduled to be generated' => 'Tarea recurrente programada para ser generada', 'Recurrent task is scheduled to be generated' => 'Tarea recurrente programada para ser generada',
'Recurring information' => 'Información recurrente', 'Recurring information' => 'Información recurrente',
'Score' => 'Puntaje', 'Score' => 'Puntuación',
'The identifier must be unique' => 'El identificador debe ser único', 'The identifier must be unique' => 'El identificador debe ser único',
'This linked task id doesn\'t exists' => 'El id de tarea no existe', 'This linked task id doesn\'t exists' => 'El id de tarea no existe',
'This value must be alphanumeric' => 'Este valor debe ser alfanumérico', 'This value must be alphanumeric' => 'Este valor debe ser alfanumérico',
'Edit recurrence' => 'Editar recurrencia', 'Edit recurrence' => 'Editar repetición',
'Generate recurrent task' => 'Generar tarea recurrente', 'Generate recurrent task' => 'Generar tarea recurrente',
'Trigger to generate recurrent task' => 'Disparador para generar tarea recurrente', 'Trigger to generate recurrent task' => 'Disparador para generar tarea recurrente',
'Factor to calculate new due date' => 'Factor para calcular la nueva fecha de vencimiento', 'Factor to calculate new due date' => 'Factor para calcular la nueva fecha de entrega',
'Timeframe to calculate new due date' => 'Calendario para calcular la nueva fecha de vencimiento', 'Timeframe to calculate new due date' => 'Calendario para calcular la nueva fecha de entrega',
'Base date to calculate new due date' => 'Fecha base para calcular la nueva fecha de vencimiento', 'Base date to calculate new due date' => 'Fecha base para calcular la nueva fecha de entrega',
'Action date' => 'Fecha de acción', 'Action date' => 'Fecha de la acción',
'Base date to calculate new due date: ' => 'Fecha base para calcular la nueva fecha de vencimiento:', 'Base date to calculate new due date: ' => 'Fecha base para calcular la nueva fecha de entrega:',
'This task has created this child task: ' => 'Esta tarea ha cerado esta tarea hija:', 'This task has created this child task: ' => 'Esta tarea ha cerado esta tarea hija:',
'Day(s)' => 'Día(s)', 'Day(s)' => 'Día(s)',
'Existing due date' => 'Fecha de vencimiento existente', 'Existing due date' => 'Fecha de entrega existente',
'Factor to calculate new due date: ' => 'Factor para calcular la nueva fecha de vencimiento:', 'Factor to calculate new due date: ' => 'Factor para calcular la nueva fecha de entrega:',
'Month(s)' => 'Mes(es)', 'Month(s)' => 'Mes(es)',
'Recurrence' => 'Recurrencia', 'Recurrence' => 'Repetición',
'This task has been created by: ' => 'Esta tarea ha sido creada por: ', 'This task has been created by: ' => 'Esta tarea ha sido creada por: ',
'Recurrent task has been generated:' => 'Tarea recurrente generada:', 'Recurrent task has been generated:' => 'Tarea recurrente generada:',
'Timeframe to calculate new due date: ' => 'Calendario para calcular la nueva fecha de vencimiento:', 'Timeframe to calculate new due date: ' => 'Calendario para calcular la nueva fecha de entrega:',
'Trigger to generate recurrent task: ' => 'Disparador para generar tarea recurrente', 'Trigger to generate recurrent task: ' => 'Disparador para generar tarea recurrente',
'When task is closed' => 'Cuando la tarea es cerrada', 'When task is closed' => 'Cuando la tarea es cerrada',
'When task is moved from first column' => 'Cuando la tarea es movida a la primer columna', 'When task is moved from first column' => 'Cuando la tarea es movida desde la primera columna',
'When task is moved to last column' => 'Cuando la tarea es movida a la última columna', 'When task is moved to last column' => 'Cuando la tarea es movida a la última columna',
'Year(s)' => 'Año(s)', 'Year(s)' => 'Año(s)',
'Jabber (XMPP)' => 'Jabber (XMPP)', 'Jabber (XMPP)' => 'Jabber (XMPP)',
@ -847,172 +847,224 @@ return array(
'iCal feed' => 'Fuente iCal', 'iCal feed' => 'Fuente iCal',
'Preferences' => 'Preferencias', 'Preferences' => 'Preferencias',
'Security' => 'Seguridad', 'Security' => 'Seguridad',
'Two factor authentication disabled' => 'Autenticación de dos factores deshabilitado', 'Two factor authentication disabled' => 'Autenticación de dos factores deshabilitada',
'Two factor authentication enabled' => 'Autenticación de dos factores habilitado', 'Two factor authentication enabled' => 'Autenticación de dos factores habilitada',
'Unable to update this user.' => 'Imposible actualizar este usuario.', 'Unable to update this user.' => 'Imposible actualizar este usuario.',
'There is no user management for private projects.' => 'No hay gestión de usuarios para proyectos privados.', 'There is no user management for private projects.' => 'No hay gestión de usuarios para proyectos privados.',
'User that will receive the email' => 'Usuario que recibirá el correo', 'User that will receive the email' => 'Usuario que recibirá el correo',
'Email subject' => 'Asunto del correo', 'Email subject' => 'Asunto del correo',
'Date' => 'Fecha', 'Date' => 'Fecha',
// 'By @%s on Bitbucket' => '', 'By @%s on Bitbucket' => 'Mediante @%s en Bitbucket',
// 'Bitbucket Issue' => '', 'Bitbucket Issue' => 'Asunto de Bitbucket',
// 'Commit made by @%s on Bitbucket' => '', 'Commit made by @%s on Bitbucket' => 'Envío realizado por @%s en Bitbucket',
// 'Commit made by @%s on Github' => '', 'Commit made by @%s on Github' => 'Envío realizado por @%s en Github',
// 'By @%s on Github' => '', 'By @%s on Github' => 'Por @%s en Github',
// 'Commit made by @%s on Gitlab' => '', 'Commit made by @%s on Gitlab' => 'Envío realizado por @%s en Gitlab',
// 'Add a comment log when moving the task between columns' => '', 'Add a comment log when moving the task between columns' => 'Añadir un comentario al mover la tarea entre columnas',
'Move the task to another column when the category is changed' => 'Mover la tarea a otra columna cuando cambia la categoría', 'Move the task to another column when the category is changed' => 'Mover la tarea a otra columna cuando cambia la categoría',
'Send a task by email to someone' => 'Enviar una tarea a alguien por correo', 'Send a task by email to someone' => 'Enviar una tarea a alguien por correo',
'Reopen a task' => 'Reabrir tarea', 'Reopen a task' => 'Reabrir tarea',
// 'Bitbucket issue opened' => '', 'Bitbucket issue opened' => 'Abierto asunto de Bitbucket',
// 'Bitbucket issue closed' => '', 'Bitbucket issue closed' => 'Cerrado asunto de Bitbucket',
// 'Bitbucket issue reopened' => '', 'Bitbucket issue reopened' => 'Reabierto asunto de Bitbucket',
// 'Bitbucket issue assignee change' => '', 'Bitbucket issue assignee change' => 'Cambiado concesionario de asunto de Bitbucket',
// 'Bitbucket issue comment created' => '', 'Bitbucket issue comment created' => 'Creado comentario de asunto de Bitbucket',
'Column change' => 'Cambio de columna', 'Column change' => 'Cambio de columna',
'Position change' => 'Cambio de posición', 'Position change' => 'Cambio de posición',
'Swimlane change' => 'Cambio de carril', 'Swimlane change' => 'Cambio de calle',
'Assignee change' => 'Cambio de usuario asignado', 'Assignee change' => 'Cambio de concesionario',
'[%s] Overdue tasks' => '[%s] Tareas vencidas', '[%s] Overdue tasks' => '[%s] Tareas vencidas',
'Notification' => 'Notificación', 'Notification' => 'Notificación',
// '%s moved the task #%d to the first swimlane' => '', '%s moved the task #%d to the first swimlane' => '%s movió la tarea #%d a la primera calle',
// '%s moved the task #%d to the swimlane "%s"' => '', '%s moved the task #%d to the swimlane "%s"' => '%s movió la tarea #%d a la calle "%s"',
'Swimlane' => 'Carril', 'Swimlane' => 'Calle',
// 'Budget overview' => '', 'Budget overview' => 'Resumen del Presupuesto',
'Type' => 'Tipo', 'Type' => 'Tipo',
// 'There is not enough data to show something.' => '', 'There is not enough data to show something.' => 'No hay datos suficientes como para mostrar algo.',
// 'Gravatar' => '', 'Gravatar' => 'Gravatar',
// 'Hipchat' => '', 'Hipchat' => 'Hipchat',
// 'Slack' => '', 'Slack' => 'Desatendida',
// '%s moved the task %s to the first swimlane' => '', '%s moved the task %s to the first swimlane' => '%s movió la tarea %s a la primera calle',
// '%s moved the task %s to the swimlane "%s"' => '', '%s moved the task %s to the swimlane "%s"' => '%s movió la tarea %s a la calle "%s"',
// 'This report contains all subtasks information for the given date range.' => '', 'This report contains all subtasks information for the given date range.' => 'Este informe contiene todas la información de las subtareas para el rango proporcionado de fechas.',
// 'This report contains all tasks information for the given date range.' => '', 'This report contains all tasks information for the given date range.' => 'Este informe contiene todas la información de las tareas para el rango proporcionado de fechas.',
// 'Project activities for %s' => '', 'Project activities for %s' => 'Actividades del proyecto para %s',
// 'view the board on Kanboard' => '', 'view the board on Kanboard' => 'ver el tablero en Kanboard',
// 'The task have been moved to the first swimlane' => '', 'The task have been moved to the first swimlane' => 'Se ha movido la tarea a la primera calle',
// 'The task have been moved to another swimlane:' => '', 'The task have been moved to another swimlane:' => 'Se ha movido la tarea a otra calle',
// 'Overdue tasks for the project "%s"' => '', 'Overdue tasks for the project "%s"' => 'Tareas atrasadas para el proyecto "%s"',
// 'New title: %s' => '', 'New title: %s' => 'Nuevo título: %s',
// 'The task is not assigned anymore' => '', 'The task is not assigned anymore' => 'La tarea ya no está asignada',
// 'New assignee: %s' => '', 'New assignee: %s' => 'Nuevo concesionario: %s',
// 'There is no category now' => '', 'There is no category now' => 'En este momento no hay categorías',
// 'New category: %s' => '', 'New category: %s' => 'Nueva categoría: %s',
// 'New color: %s' => '', 'New color: %s' => 'Nuevo color: %s',
// 'New complexity: %d' => '', 'New complexity: %d' => 'Nueva complejidad: %d',
// 'The due date have been removed' => '', 'The due date have been removed' => 'Se ha quitado la fecha de entrega',
// 'There is no description anymore' => '', 'There is no description anymore' => 'Ya no hay descripción',
// 'Recurrence settings have been modified' => '', 'Recurrence settings have been modified' => 'Se han modificado los valores recurrentes',
// 'Time spent changed: %sh' => '', 'Time spent changed: %sh' => 'Se ha cambiado el tiempo empleado: %sh',
// 'Time estimated changed: %sh' => '', 'Time estimated changed: %sh' => 'Se ha cambiado el tiempo estimado: %sh',
// 'The field "%s" have been updated' => '', 'The field "%s" have been updated' => 'Se ha actualizado el campo "%s"',
// 'The description have been modified' => '', 'The description have been modified' => 'Se ha modificado la descripción',
// 'Do you really want to close the task "%s" as well as all subtasks?' => '', 'Do you really want to close the task "%s" as well as all subtasks?' => '¿De verdad que quiere cerra la tarea "%s" así como todas las subtareas?',
// 'Swimlane: %s' => '', 'Swimlane: %s' => 'Calle: %s',
// 'I want to receive notifications for:' => '', 'I want to receive notifications for:' => 'Deseo recibir notificaciones para:',
// 'All tasks' => '', 'All tasks' => 'Todas las tareas',
// 'Only for tasks assigned to me' => '', 'Only for tasks assigned to me' => 'Sólo para las tareas que me han sido asignadas',
// 'Only for tasks created by me' => '', 'Only for tasks created by me' => 'Sólo para las taread creadas por mí',
// 'Only for tasks created by me and assigned to me' => '', 'Only for tasks created by me and assigned to me' => 'Sólo para las tareas credas por mí y que me han sido asignadas',
// '%A' => '', '%A' => '%A',
// '%b %e, %Y, %k:%M %p' => '', '%b %e, %Y, %k:%M %p' => '%e de %B de %Y a las %k:%M %p',
// 'New due date: %B %e, %Y' => '', 'New due date: %B %e, %Y' => 'Nueva fecha de entrega: %B %e, %Y',
// 'Start date changed: %B %e, %Y' => '', 'Start date changed: %B %e, %Y' => 'Cambiadad fecha de inicio: %B %e, %Y',
// '%k:%M %p' => '', '%k:%M %p' => '%k:%M %p',
// '%%Y-%%m-%%d' => '', '%%Y-%%m-%%d' => '%%d/%%M/%%Y',
// 'Total for all columns' => '', 'Total for all columns' => 'Total para todas las columnas',
// 'You need at least 2 days of data to show the chart.' => '', 'You need at least 2 days of data to show the chart.' => 'Necesitas al menos 2 días de datos para mostrar el gráfico.',
// '<15m' => '', '<15m' => '<15m',
// '<30m' => '', '<30m' => '<30m',
// 'Stop timer' => '', 'Stop timer' => 'Parar temporizador',
// 'Start timer' => '', 'Start timer' => 'Arrancar temporizador',
// 'Add project member' => '', 'Add project member' => 'Añadir miembro al proyecto',
// 'Enable notifications' => '', 'Enable notifications' => 'Activar notificaciones',
// 'My activity stream' => '', 'My activity stream' => 'Mi flujo de actividad',
// 'My calendar' => '', 'My calendar' => 'Mi calendario',
// 'Search tasks' => '', 'Search tasks' => 'Buscar tareas',
// 'Back to the calendar' => '', 'Back to the calendar' => 'Volver al calendario',
// 'Filters' => '', 'Filters' => 'Filtros',
// 'Reset filters' => '', 'Reset filters' => 'Limpiar filtros',
// 'My tasks due tomorrow' => '', 'My tasks due tomorrow' => 'Mis tareas a entregar mañana',
// 'Tasks due today' => '', 'Tasks due today' => 'Tareas a antregar hoy',
// 'Tasks due tomorrow' => '', 'Tasks due tomorrow' => 'Taraes a entregar mañana',
// 'Tasks due yesterday' => '', 'Tasks due yesterday' => 'Tareas a entregar ayer',
// 'Closed tasks' => '', 'Closed tasks' => 'Tareas cerradas',
// 'Open tasks' => '', 'Open tasks' => 'Tareas abiertas',
// 'Not assigned' => '', 'Not assigned' => 'No asignada',
// 'View advanced search syntax' => '', 'View advanced search syntax' => 'Ver sintáxis avanzada de búsqueda',
// 'Overview' => '', 'Overview' => 'Resumen',
// '%b %e %Y' => '', '%b %e %Y' => '%e de %B de %Y',
// 'Board/Calendar/List view' => '', 'Board/Calendar/List view' => 'Vista de Tablero/Calendario/Lista',
// 'Switch to the board view' => '', 'Switch to the board view' => 'Cambiar a vista de tablero',
// 'Switch to the calendar view' => '', 'Switch to the calendar view' => 'Cambiar a vista de calendario',
// 'Switch to the list view' => '', 'Switch to the list view' => 'Cambiar a vista de lista',
// 'Go to the search/filter box' => '', 'Go to the search/filter box' => 'Ir a caja de buscar/filtrar',
// 'There is no activity yet.' => '', 'There is no activity yet.' => 'Aún no hay actividades.',
// 'No tasks found.' => '', 'No tasks found.' => 'No se ha hallado tarea alguna.',
// 'Keyboard shortcut: "%s"' => '', 'Keyboard shortcut: "%s"' => 'Atajo de teclado: %s',
'List' => 'Lista', 'List' => 'Lista',
'Filter' => 'Filtro', 'Filter' => 'Filtro',
'Advanced search' => 'Búsqueda avanzada', 'Advanced search' => 'Búsqueda avanzada',
// 'Example of query: ' => '', 'Example of query: ' => 'Ejemplo de query: ',
// 'Search by project: ' => '', 'Search by project: ' => 'Buscar por proyecto: ',
// 'Search by column: ' => '', 'Search by column: ' => 'Buscar por columna: ',
// 'Search by assignee: ' => '', 'Search by assignee: ' => 'Buscar por concesionario: ',
// 'Search by color: ' => '', 'Search by color: ' => 'Buscar por color: ',
// 'Search by category: ' => '', 'Search by category: ' => 'Buscar por categoría: ',
// 'Search by description: ' => '', 'Search by description: ' => 'Buscar por descripción: ',
// 'Search by due date: ' => '', 'Search by due date: ' => 'Buscar por fecha de entrega: ',
// 'Lead and Cycle time for "%s"' => '', 'Lead and Cycle time for "%s"' => 'Plazo de Entrega y Ciclo para "%s"',
// 'Average time spent into each column for "%s"' => '', 'Average time spent into each column for "%s"' => 'Tiempo medio empleado en cada columna para "%s"',
// 'Average time spent into each column' => '', 'Average time spent into each column' => 'Tiempo medio empleado en cada columna',
// 'Average time spent' => '', 'Average time spent' => 'Tiempo medio empleado',
// 'This chart show the average time spent into each column for the last %d tasks.' => '', 'This chart show the average time spent into each column for the last %d tasks.' => 'Esta gráfica muestra el tiempo medio empleado en cada columna para las últimas %d tareas.',
// 'Average Lead and Cycle time' => '', 'Average Lead and Cycle time' => 'Plazo Medio de Entrega y de Ciclo',
// 'Average lead time: ' => '', 'Average lead time: ' => 'Plazo Medio de entrega: ',
// 'Average cycle time: ' => '', 'Average cycle time: ' => 'Tiempo Medio de Ciclo: ',
// 'Cycle Time' => '', 'Cycle Time' => 'Tiempo de Ciclo',
// 'Lead Time' => '', 'Lead Time' => 'Plazo de Entrega',
// 'This chart show the average lead and cycle time for the last %d tasks over the time.' => '', 'This chart show the average lead and cycle time for the last %d tasks over the time.' => 'Esta gráfica muestra el plazo medio de entrega y de ciclo para las %d últimas tareas transcurridas.',
// 'Average time into each column' => '', 'Average time into each column' => 'Tiempo medio en cada columna',
// 'Lead and cycle time' => '', 'Lead and cycle time' => 'Plazo de entrega y de ciclo',
// 'Google Authentication' => '', 'Google Authentication' => 'Autenticación de Google',
// 'Help on Google authentication' => '', 'Help on Google authentication' => 'Ayuda con la aAutenticación de Google',
// 'Github Authentication' => '', 'Github Authentication' => 'Autenticación de Github',
// 'Help on Github authentication' => '', 'Help on Github authentication' => 'Ayuda con la autenticación de Github',
// 'Channel/Group/User (Optional)' => '', 'Channel/Group/User (Optional)' => 'Canal/Grupo/Usuario (Opcional)',
// 'Lead time: ' => '', 'Lead time: ' => 'Plazo de entrega: ',
// 'Cycle time: ' => '', 'Cycle time: ' => 'Tiempo de Ciclo: ',
// 'Time spent into each column' => '', 'Time spent into each column' => 'Tiempo empleado en cada columna',
// 'The lead time is the duration between the task creation and the completion.' => '', 'The lead time is the duration between the task creation and the completion.' => 'El plazo de entrega es la duración entre la creación de la tarea su terminación.',
// 'The cycle time is the duration between the start date and the completion.' => '', 'The cycle time is the duration between the start date and the completion.' => 'El tiempo de ciclo es la duración entre la fecha de inicio y su terminación.',
// 'If the task is not closed the current time is used instead of the completion date.' => '', 'If the task is not closed the current time is used instead of the completion date.' => 'Si la tarea no se cierra, se usa la fecha actual en lugar de la de terminación.',
// 'Set automatically the start date' => '', 'Set automatically the start date' => 'Poner la fecha de inicio de forma automática',
'Edit Authentication' => 'Editar autenticación', 'Edit Authentication' => 'Editar autenticación',
// 'Google Id' => '', 'Google Id' => 'Id de Google',
// 'Github Id' => '', 'Github Id' => 'Id de Github',
'Remote user' => 'Usuario remoto', 'Remote user' => 'Usuario remoto',
// 'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => '', 'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => 'Los usuarios remotos no almacenan sus contraseñas en la base de datos Kanboard, por ejemplo: cuentas de LDAP, Google y Github',
// 'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => '', 'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => 'Si marcas la caja de edición "Desactivar formulario de ingreso", se ignoran las credenciales entradas en el formulario de ingreso.',
// 'By @%s on Gitlab' => '', 'By @%s on Gitlab' => 'Por @%s en Gitlab',
// 'Gitlab issue comment created' => '', 'Gitlab issue comment created' => 'Creado comentario de asunto de Gitlab',
// 'New remote user' => '', 'New remote user' => 'Nuevo usuario remoto',
// 'New local user' => '', 'New local user' => 'Nuevo usuario local',
// 'Default task color' => '', 'Default task color' => 'Color por defecto de tarea',
// 'Hide sidebar' => '', 'Hide sidebar' => 'Ocultar barra lateral',
// 'Expand sidebar' => '', 'Expand sidebar' => 'Expandir barra lateral',
// 'This feature does not work with all browsers.' => '', 'This feature does not work with all browsers.' => 'Esta característica no funciona con todos los navegadores',
// 'There is no destination project available.' => '', 'There is no destination project available.' => 'No está disponible proyecto destino',
// 'Trigger automatically subtask time tracking' => '', 'Trigger automatically subtask time tracking' => 'Disparar de forma automática seguimiento temporal de subtarea',
// 'Include closed tasks in the cumulative flow diagram' => '', 'Include closed tasks in the cumulative flow diagram' => 'Incluir tareas cerradas en el diagrama de flujo acumulado',
// 'Current swimlane: %s' => '', 'Current swimlane: %s' => 'Calle en curso: %s',
// 'Current column: %s' => '', 'Current column: %s' => 'Columna en curso: %s',
// 'Current category: %s' => '', 'Current category: %s' => 'Categoría en curso: %s',
// 'no category' => '', 'no category' => 'no hay categoría',
// 'Current assignee: %s' => '', 'Current assignee: %s' => 'Concesionario en curso: %s',
// 'not assigned' => '', 'not assigned' => 'sin asignar',
// 'Author:' => '', 'Author:' => 'Autor:',
// 'contributors' => '', 'contributors' => 'contribuyentes',
// 'License:' => '', 'License:' => 'Licencia:',
// 'License' => '', 'License' => 'Licencia',
'Project Administrator' => 'Administrador del Proyecto',
'Enter the text below' => 'Digita el texto de abajo',
'Gantt chart for %s' => 'Diagrama de Gantt para %s',
'Sort by position' => 'Clasificado mediante posición',
'Sort by date' => 'Clasificado mediante fecha',
'Add task' => 'Añadir tarea',
'Start date:' => 'Fecha de inicio:',
'Due date:' => 'Fecha de entrega:',
'There is no start date or due date for this task.' => 'No hay fecha de inicio o de entrega para esta tarea.',
'Moving or resizing a task will change the start and due date of the task.' => 'El mover o redimensionar una tarea cambiará la fecha inicio y de entrega de la misma.',
'There is no task in your project.' => 'No hay tareas en su proyecto.',
'Gantt chart' => 'Digrama de Gantt',
'People who are project managers' => 'Usuarios que son administradores de proyecto',
'People who are project members' => 'Usuarios que son miembros de proyecto',
'NOK - Norwegian Krone' => 'NOK - Coronoa Noruega',
'Show this column' => 'Mostrar esta columna',
'Hide this column' => 'Ocultar esta columna',
'open file' => 'abrir fichero',
'End date' => 'Fecha de fin',
'Users overview' => 'Resumen de usuarios',
'Managers' => 'Administradores',
'Members' => 'Miembros',
'Shared project' => 'Proyecto compartido',
'Project managers' => 'Administradores de proyecto',
'Project members' => 'Miembros de proyecto',
// 'Gantt chart for all projects' => '',
// 'Projects list' => '',
// 'Gantt chart for this project' => '',
// 'Project board' => '',
// 'End date:' => '',
// 'There is no start date or end date for this project.' => '',
// 'Projects Gantt chart' => '',
// 'Start date: %s' => '',
// 'End date: %s' => '',
// 'Link type' => '',
// 'Change task color when using a specific task link' => '',
// 'Task link creation or modification' => '',
// 'Login with my Gitlab Account' => '',
// 'Milestone' => '',
// 'Gitlab Authentication' => '',
// 'Help on Gitlab authentication' => '',
// 'Gitlab Id' => '',
// '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' => '',
); );

View file

@ -1015,4 +1015,56 @@ return array(
// 'contributors' => '', // 'contributors' => '',
// 'License:' => '', // 'License:' => '',
// 'License' => '', // 'License' => '',
// 'Project Administrator' => '',
// 'Enter the text below' => '',
// 'Gantt chart for %s' => '',
// 'Sort by position' => '',
// 'Sort by date' => '',
// 'Add task' => '',
// 'Start date:' => '',
// 'Due date:' => '',
// 'There is no start date or due date for this task.' => '',
// 'Moving or resizing a task will change the start and due date of the task.' => '',
// 'There is no task in your project.' => '',
// 'Gantt chart' => '',
// 'People who are project managers' => '',
// 'People who are project members' => '',
// 'NOK - Norwegian Krone' => '',
// 'Show this column' => '',
// 'Hide this column' => '',
// 'open file' => '',
// 'End date' => '',
// 'Users overview' => '',
// 'Managers' => '',
// 'Members' => '',
// 'Shared project' => '',
// 'Project managers' => '',
// 'Project members' => '',
// 'Gantt chart for all projects' => '',
// 'Projects list' => '',
// 'Gantt chart for this project' => '',
// 'Project board' => '',
// 'End date:' => '',
// 'There is no start date or end date for this project.' => '',
// 'Projects Gantt chart' => '',
// 'Start date: %s' => '',
// 'End date: %s' => '',
// 'Link type' => '',
// 'Change task color when using a specific task link' => '',
// 'Task link creation or modification' => '',
// 'Login with my Gitlab Account' => '',
// 'Milestone' => '',
// 'Gitlab Authentication' => '',
// 'Help on Gitlab authentication' => '',
// 'Gitlab Id' => '',
// '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' => '',
); );

View file

@ -163,7 +163,7 @@ return array(
'%B %e, %Y at %k:%M %p' => '%d/%m/%Y à %H:%M', '%B %e, %Y at %k:%M %p' => '%d/%m/%Y à %H:%M',
'Date created' => 'Date de création', 'Date created' => 'Date de création',
'Date completed' => 'Date de clôture', 'Date completed' => 'Date de clôture',
'Id' => 'Identifiant', 'Id' => 'Id.',
'%d closed tasks' => '%d tâches terminées', '%d closed tasks' => '%d tâches terminées',
'No task for this project' => 'Aucune tâche pour ce projet', 'No task for this project' => 'Aucune tâche pour ce projet',
'Public link' => 'Lien public', 'Public link' => 'Lien public',
@ -1017,4 +1017,56 @@ return array(
'contributors' => 'contributeurs', 'contributors' => 'contributeurs',
'License:' => 'Licence :', 'License:' => 'Licence :',
'License' => 'Licence', 'License' => 'Licence',
'Project Administrator' => 'Administrateur de projet',
'Enter the text below' => 'Entrez le texte ci-dessous',
'Gantt chart for %s' => 'Diagramme de Gantt pour %s',
'Sort by position' => 'Trier par position',
'Sort by date' => 'Trier par date',
'Add task' => 'Ajouter une tâche',
'Start date:' => 'Date de début :',
'Due date:' => 'Date d\'échéance :',
'There is no start date or due date for this task.' => 'Il n\'y a pas de date de début ou de date de fin pour cette tâche.',
'Moving or resizing a task will change the start and due date of the task.' => 'Déplacer ou redimensionner une tâche va changer la date de début et la date de fin de la tâche.',
'There is no task in your project.' => 'Il n\'y a aucun tâche dans votre projet.',
'Gantt chart' => 'Diagramme de Gantt',
'People who are project managers' => 'Personnes qui sont gestionnaire de projet',
'People who are project members' => 'Personnes qui sont membre de projet',
'NOK - Norwegian Krone' => 'NOK - Couronne norvégienne',
'Show this column' => 'Montrer cette colonne',
'Hide this column' => 'Cacher cette colonne',
'open file' => 'ouvrir un fichier',
'End date' => 'Date de fin',
'Users overview' => 'Vue d\'ensemble des utilisateurs',
'Managers' => 'Gérants',
'Members' => 'Membres',
'Shared project' => 'Projet partagé',
'Project managers' => 'Gestionnaires de projet',
'Project members' => 'Membres de projet',
'Gantt chart for all projects' => 'Diagramme de Gantt pour tous les projets',
'Projects list' => 'List des projets',
'Gantt chart for this project' => 'Diagramme de Gantt pour ce projet',
'Project board' => 'Tableau du projet',
'End date:' => 'Date de fin :',
'There is no start date or end date for this project.' => 'Il n\'y a pas de date de début ou de date de fin pour ce projet.',
'Projects Gantt chart' => 'Diagramme de Gantt des projets',
'Start date: %s' => 'Date de début : %s',
'End date: %s' => 'Date de fin : %s',
'Link type' => 'Type de lien',
'Change task color when using a specific task link' => 'Changer la couleur de la tâche lorsqu\'un lien spécifique est utilisé',
'Task link creation or modification' => 'Création ou modification d\'un lien sur une tâche',
'Login with my Gitlab Account' => 'Se connecter avec mon compte Gitlab',
'Milestone' => 'Étape importante',
'Gitlab Authentication' => 'Authentification Gitlab',
'Help on Gitlab authentication' => 'Aide sur l\'authentification Gitlab',
'Gitlab Id' => 'Identifiant Gitlab',
'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',
); );

View file

@ -1015,4 +1015,56 @@ return array(
// 'contributors' => '', // 'contributors' => '',
// 'License:' => '', // 'License:' => '',
// 'License' => '', // 'License' => '',
// 'Project Administrator' => '',
// 'Enter the text below' => '',
// 'Gantt chart for %s' => '',
// 'Sort by position' => '',
// 'Sort by date' => '',
// 'Add task' => '',
// 'Start date:' => '',
// 'Due date:' => '',
// 'There is no start date or due date for this task.' => '',
// 'Moving or resizing a task will change the start and due date of the task.' => '',
// 'There is no task in your project.' => '',
// 'Gantt chart' => '',
// 'People who are project managers' => '',
// 'People who are project members' => '',
// 'NOK - Norwegian Krone' => '',
// 'Show this column' => '',
// 'Hide this column' => '',
// 'open file' => '',
// 'End date' => '',
// 'Users overview' => '',
// 'Managers' => '',
// 'Members' => '',
// 'Shared project' => '',
// 'Project managers' => '',
// 'Project members' => '',
// 'Gantt chart for all projects' => '',
// 'Projects list' => '',
// 'Gantt chart for this project' => '',
// 'Project board' => '',
// 'End date:' => '',
// 'There is no start date or end date for this project.' => '',
// 'Projects Gantt chart' => '',
// 'Start date: %s' => '',
// 'End date: %s' => '',
// 'Link type' => '',
// 'Change task color when using a specific task link' => '',
// 'Task link creation or modification' => '',
// 'Login with my Gitlab Account' => '',
// 'Milestone' => '',
// 'Gitlab Authentication' => '',
// 'Help on Gitlab authentication' => '',
// 'Gitlab Id' => '',
// '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' => '',
); );

View file

@ -1015,4 +1015,56 @@ return array(
// 'contributors' => '', // 'contributors' => '',
// 'License:' => '', // 'License:' => '',
// 'License' => '', // 'License' => '',
// 'Project Administrator' => '',
// 'Enter the text below' => '',
// 'Gantt chart for %s' => '',
// 'Sort by position' => '',
// 'Sort by date' => '',
// 'Add task' => '',
// 'Start date:' => '',
// 'Due date:' => '',
// 'There is no start date or due date for this task.' => '',
// 'Moving or resizing a task will change the start and due date of the task.' => '',
// 'There is no task in your project.' => '',
// 'Gantt chart' => '',
// 'People who are project managers' => '',
// 'People who are project members' => '',
// 'NOK - Norwegian Krone' => '',
// 'Show this column' => '',
// 'Hide this column' => '',
// 'open file' => '',
// 'End date' => '',
// 'Users overview' => '',
// 'Managers' => '',
// 'Members' => '',
// 'Shared project' => '',
// 'Project managers' => '',
// 'Project members' => '',
// 'Gantt chart for all projects' => '',
// 'Projects list' => '',
// 'Gantt chart for this project' => '',
// 'Project board' => '',
// 'End date:' => '',
// 'There is no start date or end date for this project.' => '',
// 'Projects Gantt chart' => '',
// 'Start date: %s' => '',
// 'End date: %s' => '',
// 'Link type' => '',
// 'Change task color when using a specific task link' => '',
// 'Task link creation or modification' => '',
// 'Login with my Gitlab Account' => '',
// 'Milestone' => '',
// 'Gitlab Authentication' => '',
// 'Help on Gitlab authentication' => '',
// 'Gitlab Id' => '',
// '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' => '',
); );

View file

@ -1015,4 +1015,56 @@ return array(
// 'contributors' => '', // 'contributors' => '',
// 'License:' => '', // 'License:' => '',
// 'License' => '', // 'License' => '',
// 'Project Administrator' => '',
// 'Enter the text below' => '',
// 'Gantt chart for %s' => '',
// 'Sort by position' => '',
// 'Sort by date' => '',
// 'Add task' => '',
// 'Start date:' => '',
// 'Due date:' => '',
// 'There is no start date or due date for this task.' => '',
// 'Moving or resizing a task will change the start and due date of the task.' => '',
// 'There is no task in your project.' => '',
// 'Gantt chart' => '',
// 'People who are project managers' => '',
// 'People who are project members' => '',
// 'NOK - Norwegian Krone' => '',
// 'Show this column' => '',
// 'Hide this column' => '',
// 'open file' => '',
// 'End date' => '',
// 'Users overview' => '',
// 'Managers' => '',
// 'Members' => '',
// 'Shared project' => '',
// 'Project managers' => '',
// 'Project members' => '',
// 'Gantt chart for all projects' => '',
// 'Projects list' => '',
// 'Gantt chart for this project' => '',
// 'Project board' => '',
// 'End date:' => '',
// 'There is no start date or end date for this project.' => '',
// 'Projects Gantt chart' => '',
// 'Start date: %s' => '',
// 'End date: %s' => '',
// 'Link type' => '',
// 'Change task color when using a specific task link' => '',
// 'Task link creation or modification' => '',
// 'Login with my Gitlab Account' => '',
// 'Milestone' => '',
// 'Gitlab Authentication' => '',
// 'Help on Gitlab authentication' => '',
// 'Gitlab Id' => '',
// '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' => '',
); );

View file

@ -1015,4 +1015,56 @@ return array(
// 'contributors' => '', // 'contributors' => '',
// 'License:' => '', // 'License:' => '',
// 'License' => '', // 'License' => '',
// 'Project Administrator' => '',
// 'Enter the text below' => '',
// 'Gantt chart for %s' => '',
// 'Sort by position' => '',
// 'Sort by date' => '',
// 'Add task' => '',
// 'Start date:' => '',
// 'Due date:' => '',
// 'There is no start date or due date for this task.' => '',
// 'Moving or resizing a task will change the start and due date of the task.' => '',
// 'There is no task in your project.' => '',
// 'Gantt chart' => '',
// 'People who are project managers' => '',
// 'People who are project members' => '',
// 'NOK - Norwegian Krone' => '',
// 'Show this column' => '',
// 'Hide this column' => '',
// 'open file' => '',
// 'End date' => '',
// 'Users overview' => '',
// 'Managers' => '',
// 'Members' => '',
// 'Shared project' => '',
// 'Project managers' => '',
// 'Project members' => '',
// 'Gantt chart for all projects' => '',
// 'Projects list' => '',
// 'Gantt chart for this project' => '',
// 'Project board' => '',
// 'End date:' => '',
// 'There is no start date or end date for this project.' => '',
// 'Projects Gantt chart' => '',
// 'Start date: %s' => '',
// 'End date: %s' => '',
// 'Link type' => '',
// 'Change task color when using a specific task link' => '',
// 'Task link creation or modification' => '',
// 'Login with my Gitlab Account' => '',
// 'Milestone' => '',
// 'Gitlab Authentication' => '',
// 'Help on Gitlab authentication' => '',
// 'Gitlab Id' => '',
// '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' => '',
); );

View file

@ -1015,4 +1015,56 @@ return array(
// 'contributors' => '', // 'contributors' => '',
// 'License:' => '', // 'License:' => '',
// 'License' => '', // 'License' => '',
// 'Project Administrator' => '',
// 'Enter the text below' => '',
// 'Gantt chart for %s' => '',
// 'Sort by position' => '',
// 'Sort by date' => '',
// 'Add task' => '',
// 'Start date:' => '',
// 'Due date:' => '',
// 'There is no start date or due date for this task.' => '',
// 'Moving or resizing a task will change the start and due date of the task.' => '',
// 'There is no task in your project.' => '',
// 'Gantt chart' => '',
// 'People who are project managers' => '',
// 'People who are project members' => '',
// 'NOK - Norwegian Krone' => '',
// 'Show this column' => '',
// 'Hide this column' => '',
// 'open file' => '',
// 'End date' => '',
// 'Users overview' => '',
// 'Managers' => '',
// 'Members' => '',
// 'Shared project' => '',
// 'Project managers' => '',
// 'Project members' => '',
// 'Gantt chart for all projects' => '',
// 'Projects list' => '',
// 'Gantt chart for this project' => '',
// 'Project board' => '',
// 'End date:' => '',
// 'There is no start date or end date for this project.' => '',
// 'Projects Gantt chart' => '',
// 'Start date: %s' => '',
// 'End date: %s' => '',
// 'Link type' => '',
// 'Change task color when using a specific task link' => '',
// 'Task link creation or modification' => '',
// 'Login with my Gitlab Account' => '',
// 'Milestone' => '',
// 'Gitlab Authentication' => '',
// 'Help on Gitlab authentication' => '',
// 'Gitlab Id' => '',
// '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' => '',
); );

View file

@ -263,10 +263,10 @@ return array(
'%d comments' => '%d comentários', '%d comments' => '%d comentários',
'%d comment' => '%d comentário', '%d comment' => '%d comentário',
'Email address invalid' => 'Endereço de e-mail inválido', 'Email address invalid' => 'Endereço de e-mail inválido',
// 'Your external account is not linked anymore to your profile.' => '', 'Your external account is not linked anymore to your profile.' => 'Sua conta externa não está mais ligada ao seu perfil.',
// 'Unable to unlink your external account.' => '', 'Unable to unlink your external account.' => 'Impossível de remover a sua conta externa.',
// 'External authentication failed' => '', 'External authentication failed' => 'Autenticação externa falhou',
// 'Your external account is linked to your profile successfully.' => '', 'Your external account is linked to your profile successfully.' => 'Sua conta externa está agora ligada ao seu perfil.',
'Email' => 'E-mail', 'Email' => 'E-mail',
'Link my Google Account' => 'Vincular minha Conta do Google', 'Link my Google Account' => 'Vincular minha Conta do Google',
'Unlink my Google Account' => 'Desvincular minha Conta do Google', 'Unlink my Google Account' => 'Desvincular minha Conta do Google',
@ -608,7 +608,7 @@ return array(
'Time Tracking' => 'Gestão de tempo', 'Time Tracking' => 'Gestão de tempo',
'You already have one subtask in progress' => 'Você já tem um subtarefa em andamento', 'You already have one subtask in progress' => 'Você já tem um subtarefa em andamento',
'Which parts of the project do you want to duplicate?' => 'Quais as partes do projeto você deseja duplicar?', 'Which parts of the project do you want to duplicate?' => 'Quais as partes do projeto você deseja duplicar?',
// 'Disallow login form' => '', 'Disallow login form' => 'Proibir o formulário de login',
'Bitbucket commit received' => '"Commit" recebido via Bitbucket', 'Bitbucket commit received' => '"Commit" recebido via Bitbucket',
'Bitbucket webhooks' => 'Webhook Bitbucket', 'Bitbucket webhooks' => 'Webhook Bitbucket',
'Help on Bitbucket webhooks' => 'Ajuda sobre os webhooks Bitbucket', 'Help on Bitbucket webhooks' => 'Ajuda sobre os webhooks Bitbucket',
@ -963,56 +963,108 @@ return array(
'Search by category: ' => 'Pesquisar por categoria: ', 'Search by category: ' => 'Pesquisar por categoria: ',
'Search by description: ' => 'Pesquisar por descrição: ', 'Search by description: ' => 'Pesquisar por descrição: ',
'Search by due date: ' => 'Pesquisar por data de expiração: ', 'Search by due date: ' => 'Pesquisar por data de expiração: ',
// 'Lead and Cycle time for "%s"' => '', 'Lead and Cycle time for "%s"' => 'Lead and Cycle time para "%s"',
// 'Average time spent into each column for "%s"' => '', 'Average time spent into each column for "%s"' => 'Tempo médio gasto em cada coluna para "%s"',
// 'Average time spent into each column' => '', 'Average time spent into each column' => 'Tempo médio gasto em cada coluna',
// 'Average time spent' => '', 'Average time spent' => 'Tempo médio gasto',
// 'This chart show the average time spent into each column for the last %d tasks.' => '', 'This chart show the average time spent into each column for the last %d tasks.' => 'Este gráfico mostra o tempo médio gasto em cada coluna durante nas %d últimas tarefas.',
// 'Average Lead and Cycle time' => '', 'Average Lead and Cycle time' => 'Tempo médio do Lead and cycle time',
// 'Average lead time: ' => '', 'Average lead time: ' => 'Lead time medio: ',
// 'Average cycle time: ' => '', 'Average cycle time: ' => 'Cycle time medio: ',
// 'Cycle Time' => '', 'Cycle Time' => 'Cycle time',
// 'Lead Time' => '', 'Lead Time' => 'Lead time',
// 'This chart show the average lead and cycle time for the last %d tasks over the time.' => '', 'This chart show the average lead and cycle time for the last %d tasks over the time.' => 'Este gráfico mostra o tempo médio do Lead and cycle time das últimas %d tarefas.',
// 'Average time into each column' => '', 'Average time into each column' => 'Tempo médio de cada coluna',
// 'Lead and cycle time' => '', 'Lead and cycle time' => 'Lead and cycle time',
// 'Google Authentication' => '', 'Google Authentication' => 'Autenticação Google',
// 'Help on Google authentication' => '', 'Help on Google authentication' => 'Ajuda com a autenticação Google',
// 'Github Authentication' => '', 'Github Authentication' => 'Autenticação Github',
// 'Help on Github authentication' => '', 'Help on Github authentication' => 'Ajuda com a autenticação Github',
// 'Channel/Group/User (Optional)' => '', 'Channel/Group/User (Optional)' => 'Canal/Grupo/Utilizador (Opcional)',
// 'Lead time: ' => '', 'Lead time: ' => 'Lead time: ',
// 'Cycle time: ' => '', 'Cycle time: ' => 'Cycle time: ',
// 'Time spent into each column' => '', 'Time spent into each column' => 'Tempo gasto em cada coluna',
// 'The lead time is the duration between the task creation and the completion.' => '', 'The lead time is the duration between the task creation and the completion.' => 'O Lead time é o tempo gasto entre a criação da tarefa e a sua conclusão.',
// 'The cycle time is the duration between the start date and the completion.' => '', 'The cycle time is the duration between the start date and the completion.' => 'O Cycle time é o tempo gasto entre a data de início e a sua conclusão.',
// 'If the task is not closed the current time is used instead of the completion date.' => '', 'If the task is not closed the current time is used instead of the completion date.' => 'Se a tarefa não está fechada, a hora atual é usada no lugar da data de conclusão.',
// 'Set automatically the start date' => '', 'Set automatically the start date' => 'Definir automaticamente a data de início',
// 'Edit Authentication' => '', 'Edit Authentication' => 'Modificar a autenticação',
// 'Google Id' => '', 'Google Id' => 'Google ID',
// 'Github Id' => '', 'Github Id' => 'Github Id',
// 'Remote user' => '', 'Remote user' => 'Usuário remoto',
// 'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => '', 'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => 'Os usuários remotos não conservam as suas senhas no banco de dados Kanboard, exemplos: contas LDAP, Github ou Google.',
// 'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => '', 'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => 'Se você marcar "Interdir o formulário de autenticação", os identificadores entrados no formulário de login serão ignorado.',
// 'By @%s on Gitlab' => '', 'By @%s on Gitlab' => 'Por @%s no Gitlab',
// 'Gitlab issue comment created' => '', 'Gitlab issue comment created' => 'Comentário criado em um bilhete Gitlab',
// 'New remote user' => '', 'New remote user' => 'Criar um usuário remoto',
// 'New local user' => '', 'New local user' => 'Criar um usuário local',
// 'Default task color' => '', 'Default task color' => 'Cor padrão para as tarefas',
// 'Hide sidebar' => '', 'Hide sidebar' => 'Esconder a barra lateral',
// 'Expand sidebar' => '', 'Expand sidebar' => 'Expandir a barra lateral',
// 'This feature does not work with all browsers.' => '', 'This feature does not work with all browsers.' => 'Esta funcionalidade não é compatível com todos os navegadores',
// 'There is no destination project available.' => '', 'There is no destination project available.' => 'Não há nenhum projeto de destino disponível.',
// 'Trigger automatically subtask time tracking' => '', 'Trigger automatically subtask time tracking' => 'Ativar automaticamente o monitoramento do tempo para as subtarefas',
// 'Include closed tasks in the cumulative flow diagram' => '', 'Include closed tasks in the cumulative flow diagram' => 'Incluir as tarefas fechadas no diagrama de fluxo acumulado',
// 'Current swimlane: %s' => '', 'Current swimlane: %s' => 'Swimlane actual: %s',
// 'Current column: %s' => '', 'Current column: %s' => 'Coluna actual: %s',
// 'Current category: %s' => '', 'Current category: %s' => 'Categoria actual: %s',
// 'no category' => '', 'no category' => 'nenhuma categoria',
// 'Current assignee: %s' => '', 'Current assignee: %s' => 'Designado actual: %s',
// 'not assigned' => '', 'not assigned' => 'não designado',
// 'Author:' => '', 'Author:' => 'Autor:',
// 'contributors' => '', 'contributors' => 'contribuidores',
// 'License:' => '', 'License:' => 'Licença:',
// 'License' => '', 'License' => 'Licença',
'Project Administrator' => 'Administrador de Projecto',
'Enter the text below' => 'Entre o texto abaixo',
'Gantt chart for %s' => 'Gráfico de Gantt para %s',
'Sort by position' => 'Ordenar por Posição',
'Sort by date' => 'Ordenar por data',
'Add task' => 'Adicionar uma tarefa',
'Start date:' => 'Data de início:',
'Due date:' => 'Data de expiração:',
'There is no start date or due date for this task.' => 'Não existe data de inicio ou data de expiração para esta tarefa.',
'Moving or resizing a task will change the start and due date of the task.' => 'Mover ou redimensionar uma tarefa irá alterar a data de inicio e expiração da tarefa.',
'There is no task in your project.' => 'Não há nenhuma tarefa no seu projeto.',
'Gantt chart' => 'Gráfico de Gantt',
'People who are project managers' => 'Pessoas que são gerente de projeto',
'People who are project members' => 'Pessoas que são membro de projeto',
'NOK - Norwegian Krone' => 'NOK - Coroa Norueguesa',
'Show this column' => 'Mostrar esta coluna',
'Hide this column' => 'Esconder esta coluna',
'open file' => 'abrir um arquivo',
'End date' => 'Data de término',
'Users overview' => 'Visão geral dos usuários',
'Managers' => 'Gerentes',
'Members' => 'Membros',
'Shared project' => 'Projeto compartilhado',
'Project managers' => 'Gerentes de projeto',
'Project members' => 'Membros de projeto',
'Gantt chart for all projects' => 'Gráfico de Gantt para todos os projetos',
'Projects list' => 'Lista dos projetos',
'Gantt chart for this project' => 'Gráfico de Gantt para este projecto',
'Project board' => 'Painel do projeto',
'End date:' => 'Data de término:',
'There is no start date or end date for this project.' => 'Não há data de início ou data de término para este projeto.',
'Projects Gantt chart' => 'Gráfico de Gantt dos projetos',
'Start date: %s' => 'Data de início: %s',
'End date: %s' => 'Data de término: %s',
'Link type' => 'Tipo de link',
'Change task color when using a specific task link' => 'Mudar a cor da tarefa quando um link específico é utilizado',
'Task link creation or modification' => 'Criação ou modificação de um link em uma tarefa',
'Login with my Gitlab Account' => 'Login com a minha conta Gitlab',
'Milestone' => 'Milestone',
'Gitlab Authentication' => 'Autenticação Gitlab',
'Help on Gitlab authentication' => 'Ajuda com a autenticação Gitlab',
'Gitlab Id' => 'Gitlab Id',
'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' => '',
); );

View file

@ -1015,4 +1015,56 @@ return array(
// 'contributors' => '', // 'contributors' => '',
// 'License:' => '', // 'License:' => '',
// 'License' => '', // 'License' => '',
// 'Project Administrator' => '',
// 'Enter the text below' => '',
// 'Gantt chart for %s' => '',
// 'Sort by position' => '',
// 'Sort by date' => '',
// 'Add task' => '',
// 'Start date:' => '',
// 'Due date:' => '',
// 'There is no start date or due date for this task.' => '',
// 'Moving or resizing a task will change the start and due date of the task.' => '',
// 'There is no task in your project.' => '',
// 'Gantt chart' => '',
// 'People who are project managers' => '',
// 'People who are project members' => '',
// 'NOK - Norwegian Krone' => '',
// 'Show this column' => '',
// 'Hide this column' => '',
// 'open file' => '',
// 'End date' => '',
// 'Users overview' => '',
// 'Managers' => '',
// 'Members' => '',
// 'Shared project' => '',
// 'Project managers' => '',
// 'Project members' => '',
// 'Gantt chart for all projects' => '',
// 'Projects list' => '',
// 'Gantt chart for this project' => '',
// 'Project board' => '',
// 'End date:' => '',
// 'There is no start date or end date for this project.' => '',
// 'Projects Gantt chart' => '',
// 'Start date: %s' => '',
// 'End date: %s' => '',
// 'Link type' => '',
// 'Change task color when using a specific task link' => '',
// 'Task link creation or modification' => '',
// 'Login with my Gitlab Account' => '',
// 'Milestone' => '',
// 'Gitlab Authentication' => '',
// 'Help on Gitlab authentication' => '',
// 'Gitlab Id' => '',
// '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' => '',
); );

View file

@ -1015,4 +1015,56 @@ return array(
// 'contributors' => '', // 'contributors' => '',
// 'License:' => '', // 'License:' => '',
// 'License' => '', // 'License' => '',
// 'Project Administrator' => '',
// 'Enter the text below' => '',
// 'Gantt chart for %s' => '',
// 'Sort by position' => '',
// 'Sort by date' => '',
// 'Add task' => '',
// 'Start date:' => '',
// 'Due date:' => '',
// 'There is no start date or due date for this task.' => '',
// 'Moving or resizing a task will change the start and due date of the task.' => '',
// 'There is no task in your project.' => '',
// 'Gantt chart' => '',
// 'People who are project managers' => '',
// 'People who are project members' => '',
// 'NOK - Norwegian Krone' => '',
// 'Show this column' => '',
// 'Hide this column' => '',
// 'open file' => '',
// 'End date' => '',
// 'Users overview' => '',
// 'Managers' => '',
// 'Members' => '',
// 'Shared project' => '',
// 'Project managers' => '',
// 'Project members' => '',
// 'Gantt chart for all projects' => '',
// 'Projects list' => '',
// 'Gantt chart for this project' => '',
// 'Project board' => '',
// 'End date:' => '',
// 'There is no start date or end date for this project.' => '',
// 'Projects Gantt chart' => '',
// 'Start date: %s' => '',
// 'End date: %s' => '',
// 'Link type' => '',
// 'Change task color when using a specific task link' => '',
// 'Task link creation or modification' => '',
// 'Login with my Gitlab Account' => '',
// 'Milestone' => '',
// 'Gitlab Authentication' => '',
// 'Help on Gitlab authentication' => '',
// 'Gitlab Id' => '',
// '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' => '',
); );

View file

@ -263,10 +263,10 @@ return array(
'%d comments' => '%d kommentarer', '%d comments' => '%d kommentarer',
'%d comment' => '%d kommentar', '%d comment' => '%d kommentar',
'Email address invalid' => 'Epost-adressen ogiltig', 'Email address invalid' => 'Epost-adressen ogiltig',
// 'Your external account is not linked anymore to your profile.' => '', 'Your external account is not linked anymore to your profile.' => 'Ditt externa konto är inte längre länkad till din profil.',
// 'Unable to unlink your external account.' => '', 'Unable to unlink your external account.' => 'Kunde inte koppla från ditt externa konto.',
// 'External authentication failed' => '', 'External authentication failed' => 'Extern autentisering misslyckades',
// 'Your external account is linked to your profile successfully.' => '', 'Your external account is linked to your profile successfully.' => 'Ditt externa konto länkades till din profil.',
'Email' => 'Epost', 'Email' => 'Epost',
'Link my Google Account' => 'Länka till mitt Google-konto', 'Link my Google Account' => 'Länka till mitt Google-konto',
'Unlink my Google Account' => 'Ta bort länken till mitt Google-konto', 'Unlink my Google Account' => 'Ta bort länken till mitt Google-konto',
@ -791,7 +791,7 @@ return array(
'Help on Postmark integration' => 'Hjälp för Postmark integration', 'Help on Postmark integration' => 'Hjälp för Postmark integration',
'Mailgun (incoming emails)' => 'Mailgrun (inkommande e-post)', 'Mailgun (incoming emails)' => 'Mailgrun (inkommande e-post)',
'Help on Mailgun integration' => 'Hjälp för Mailgrun integration', 'Help on Mailgun integration' => 'Hjälp för Mailgrun integration',
// 'Sendgrid (incoming emails)' => '', 'Sendgrid (incoming emails)' => 'Sendgrid (inkommande e-post)',
'Help on Sendgrid integration' => 'Hjälp för Sendgrid integration', 'Help on Sendgrid integration' => 'Hjälp för Sendgrid integration',
'Disable two factor authentication' => 'Inaktivera två-faktors autentisering', 'Disable two factor authentication' => 'Inaktivera två-faktors autentisering',
'Do you really want to disable the two factor authentication for this user: "%s"?' => 'Vill du verkligen inaktivera två-faktors autentisering för denna användare: "%s"?', 'Do you really want to disable the two factor authentication for this user: "%s"?' => 'Vill du verkligen inaktivera två-faktors autentisering för denna användare: "%s"?',
@ -963,56 +963,108 @@ return array(
'Search by category: ' => 'Sök efter kategori:', 'Search by category: ' => 'Sök efter kategori:',
'Search by description: ' => 'Sök efter beskrivning', 'Search by description: ' => 'Sök efter beskrivning',
'Search by due date: ' => 'Sök efter förfallodatum', 'Search by due date: ' => 'Sök efter förfallodatum',
// 'Lead and Cycle time for "%s"' => '', 'Lead and Cycle time for "%s"' => 'Led- och cykeltid för "%s"',
// 'Average time spent into each column for "%s"' => '', 'Average time spent into each column for "%s"' => 'Medeltidsåtgång i varje kolumn för "%s"',
// 'Average time spent into each column' => '', 'Average time spent into each column' => 'Medeltidsåtgång i varje kolumn',
// 'Average time spent' => '', 'Average time spent' => 'Medeltidsåtgång',
// 'This chart show the average time spent into each column for the last %d tasks.' => '', 'This chart show the average time spent into each column for the last %d tasks.' => 'Diagramet visar medeltidsåtgång i varje kolumn för de senaste %d uppgifterna.',
// 'Average Lead and Cycle time' => '', 'Average Lead and Cycle time' => 'Medel av led och cykeltid',
// 'Average lead time: ' => '', 'Average lead time: ' => 'Medel av ledtid',
// 'Average cycle time: ' => '', 'Average cycle time: ' => 'Medel av cykeltid',
// 'Cycle Time' => '', 'Cycle Time' => 'Cykeltid',
// 'Lead Time' => '', 'Lead Time' => 'Ledtid',
// 'This chart show the average lead and cycle time for the last %d tasks over the time.' => '', 'This chart show the average lead and cycle time for the last %d tasks over the time.' => 'Diagramet visar medel av led och cykeltid för de senaste %d uppgifterna över tiden.',
// 'Average time into each column' => '', 'Average time into each column' => 'Medeltidsåtgång i varje kolumn',
// 'Lead and cycle time' => '', 'Lead and cycle time' => 'Led och cykeltid',
// 'Google Authentication' => '', 'Google Authentication' => 'Google autentisering',
// 'Help on Google authentication' => '', 'Help on Google authentication' => 'Hjälp för Google autentisering',
// 'Github Authentication' => '', 'Github Authentication' => 'Github autentisering',
// 'Help on Github authentication' => '', 'Help on Github authentication' => 'Hjälp för Github autentisering',
// 'Channel/Group/User (Optional)' => '', 'Channel/Group/User (Optional)' => 'Kanal/Grupp/Användare (valfri)',
// 'Lead time: ' => '', 'Lead time: ' => 'Ledtid',
// 'Cycle time: ' => '', 'Cycle time: ' => 'Cykeltid',
// 'Time spent into each column' => '', 'Time spent into each column' => 'Tidsåtgång per kolumn',
// 'The lead time is the duration between the task creation and the completion.' => '', 'The lead time is the duration between the task creation and the completion.' => 'Ledtiden är varaktigheten mellan uppgiftens skapande och slutförande.',
// 'The cycle time is the duration between the start date and the completion.' => '', 'The cycle time is the duration between the start date and the completion.' => 'Cykeltiden är varaktigheten mellan uppgiftens startdatum och slut.',
// 'If the task is not closed the current time is used instead of the completion date.' => '', 'If the task is not closed the current time is used instead of the completion date.' => 'Om uppgiften inte är stängd används nuvarande tid istället för slutförandedatum.',
// 'Set automatically the start date' => '', 'Set automatically the start date' => 'Sätt startdatum automatiskt',
// 'Edit Authentication' => '', 'Edit Authentication' => 'Ändra autentisering',
// 'Google Id' => '', 'Google Id' => 'Google Id',
// 'Github Id' => '', 'Github Id' => 'Github Id',
// 'Remote user' => '', 'Remote user' => 'Extern användare',
// 'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => '', 'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => 'Externa användares lösenord lagras inte i Kanboard-databasen, exempel: LDAP, Google och Github-konton.',
// 'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => '', 'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => 'Om du aktiverar boxen "Tillåt inte loginformulär" kommer inloggningsuppgifter i formuläret att ignoreras.',
// 'By @%s on Gitlab' => '', 'By @%s on Gitlab' => 'Av @%s på Gitlab',
// 'Gitlab issue comment created' => '', 'Gitlab issue comment created' => 'Gitlab frågekommentar skapad',
// 'New remote user' => '', 'New remote user' => 'Ny extern användare',
// 'New local user' => '', 'New local user' => 'Ny lokal användare',
// 'Default task color' => '', 'Default task color' => 'Standardfärg för uppgifter',
// 'Hide sidebar' => '', 'Hide sidebar' => 'Göm sidokolumn',
// 'Expand sidebar' => '', 'Expand sidebar' => 'Expandera sidokolumn',
// 'This feature does not work with all browsers.' => '', 'This feature does not work with all browsers.' => 'Denna funktion fungerar inte i alla webbläsare.',
// 'There is no destination project available.' => '', 'There is no destination project available.' => 'Det finns inget destinationsprojekt tillgängligt.',
// 'Trigger automatically subtask time tracking' => '', 'Trigger automatically subtask time tracking' => 'Aktivera automatisk tidsbevakning av deluppgifter',
// 'Include closed tasks in the cumulative flow diagram' => '', 'Include closed tasks in the cumulative flow diagram' => 'Inkludera stängda uppgifter i digrammet med kumulativt flöde',
// 'Current swimlane: %s' => '', 'Current swimlane: %s' => 'Nuvarande swimlane: %s',
// 'Current column: %s' => '', 'Current column: %s' => 'Nuvarande kolumn: %s',
// 'Current category: %s' => '', 'Current category: %s' => 'Nuvarande kategori: %s',
// 'no category' => '', 'no category' => 'ingen kategori',
// 'Current assignee: %s' => '', 'Current assignee: %s' => 'Nuvarande tilldelning: %s',
// 'not assigned' => '', 'not assigned' => 'inte tilldelad',
// 'Author:' => '', 'Author:' => 'Upphovsman:',
// 'contributors' => '', 'contributors' => 'bidragare:',
// 'License:' => '', 'License:' => 'Licens:',
// 'License' => '', 'License' => 'Licens',
'Project Administrator' => 'Projektadministratör',
'Enter the text below' => 'Fyll i texten nedan',
'Gantt chart for %s' => 'Gantt-schema för %s',
'Sort by position' => 'Sortera efter position',
'Sort by date' => 'Sortera efter datum',
'Add task' => 'Lägg till uppgift',
'Start date:' => 'Startdatum:',
'Due date:' => 'Slutdatum:',
'There is no start date or due date for this task.' => 'Det finns inget startdatum eller slutdatum för uppgiften.',
'Moving or resizing a task will change the start and due date of the task.' => 'Flytt eller storleksändring av uppgiften ändrar start och slutdatum för uppgiften',
'There is no task in your project.' => 'Det finns ingen uppgift i ditt projekt.',
'Gantt chart' => 'Gantt-schema',
// 'People who are project managers' => '',
// 'People who are project members' => '',
// 'NOK - Norwegian Krone' => '',
// 'Show this column' => '',
// 'Hide this column' => '',
// 'open file' => '',
// 'End date' => '',
// 'Users overview' => '',
// 'Managers' => '',
// 'Members' => '',
// 'Shared project' => '',
// 'Project managers' => '',
// 'Project members' => '',
// 'Gantt chart for all projects' => '',
// 'Projects list' => '',
// 'Gantt chart for this project' => '',
// 'Project board' => '',
// 'End date:' => '',
// 'There is no start date or end date for this project.' => '',
// 'Projects Gantt chart' => '',
// 'Start date: %s' => '',
// 'End date: %s' => '',
// 'Link type' => '',
// 'Change task color when using a specific task link' => '',
// 'Task link creation or modification' => '',
// 'Login with my Gitlab Account' => '',
// 'Milestone' => '',
// 'Gitlab Authentication' => '',
// 'Help on Gitlab authentication' => '',
// 'Gitlab Id' => '',
// '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' => '',
); );

View file

@ -1015,4 +1015,56 @@ return array(
// 'contributors' => '', // 'contributors' => '',
// 'License:' => '', // 'License:' => '',
// 'License' => '', // 'License' => '',
// 'Project Administrator' => '',
// 'Enter the text below' => '',
// 'Gantt chart for %s' => '',
// 'Sort by position' => '',
// 'Sort by date' => '',
// 'Add task' => '',
// 'Start date:' => '',
// 'Due date:' => '',
// 'There is no start date or due date for this task.' => '',
// 'Moving or resizing a task will change the start and due date of the task.' => '',
// 'There is no task in your project.' => '',
// 'Gantt chart' => '',
// 'People who are project managers' => '',
// 'People who are project members' => '',
// 'NOK - Norwegian Krone' => '',
// 'Show this column' => '',
// 'Hide this column' => '',
// 'open file' => '',
// 'End date' => '',
// 'Users overview' => '',
// 'Managers' => '',
// 'Members' => '',
// 'Shared project' => '',
// 'Project managers' => '',
// 'Project members' => '',
// 'Gantt chart for all projects' => '',
// 'Projects list' => '',
// 'Gantt chart for this project' => '',
// 'Project board' => '',
// 'End date:' => '',
// 'There is no start date or end date for this project.' => '',
// 'Projects Gantt chart' => '',
// 'Start date: %s' => '',
// 'End date: %s' => '',
// 'Link type' => '',
// 'Change task color when using a specific task link' => '',
// 'Task link creation or modification' => '',
// 'Login with my Gitlab Account' => '',
// 'Milestone' => '',
// 'Gitlab Authentication' => '',
// 'Help on Gitlab authentication' => '',
// 'Gitlab Id' => '',
// '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' => '',
); );

View file

@ -1015,4 +1015,56 @@ return array(
// 'contributors' => '', // 'contributors' => '',
// 'License:' => '', // 'License:' => '',
// 'License' => '', // 'License' => '',
// 'Project Administrator' => '',
// 'Enter the text below' => '',
// 'Gantt chart for %s' => '',
// 'Sort by position' => '',
// 'Sort by date' => '',
// 'Add task' => '',
// 'Start date:' => '',
// 'Due date:' => '',
// 'There is no start date or due date for this task.' => '',
// 'Moving or resizing a task will change the start and due date of the task.' => '',
// 'There is no task in your project.' => '',
// 'Gantt chart' => '',
// 'People who are project managers' => '',
// 'People who are project members' => '',
// 'NOK - Norwegian Krone' => '',
// 'Show this column' => '',
// 'Hide this column' => '',
// 'open file' => '',
// 'End date' => '',
// 'Users overview' => '',
// 'Managers' => '',
// 'Members' => '',
// 'Shared project' => '',
// 'Project managers' => '',
// 'Project members' => '',
// 'Gantt chart for all projects' => '',
// 'Projects list' => '',
// 'Gantt chart for this project' => '',
// 'Project board' => '',
// 'End date:' => '',
// 'There is no start date or end date for this project.' => '',
// 'Projects Gantt chart' => '',
// 'Start date: %s' => '',
// 'End date: %s' => '',
// 'Link type' => '',
// 'Change task color when using a specific task link' => '',
// 'Task link creation or modification' => '',
// 'Login with my Gitlab Account' => '',
// 'Milestone' => '',
// 'Gitlab Authentication' => '',
// 'Help on Gitlab authentication' => '',
// 'Gitlab Id' => '',
// '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' => '',
); );

View file

@ -773,14 +773,14 @@ return array(
'Secret key: ' => '密码:', 'Secret key: ' => '密码:',
'Test your device' => '测试设备', 'Test your device' => '测试设备',
'Assign a color when the task is moved to a specific column' => '任务移动到指定栏目时设置颜色', 'Assign a color when the task is moved to a specific column' => '任务移动到指定栏目时设置颜色',
// '%s via Kanboard' => '', '%s via Kanboard' => '%s 通过KanBoard',
// 'uploaded by: %s' => '', 'uploaded by: %s' => '由: %s 上传',
// 'uploaded on: %s' => '', // 'uploaded on: %s' => '',
// 'size: %s' => '', // 'size: %s' => '',
// 'Burndown chart for "%s"' => '', // 'Burndown chart for "%s"' => '',
// 'Burndown chart' => '', // 'Burndown chart' => '',
// 'This chart show the task complexity over the time (Work Remaining).' => '', // 'This chart show the task complexity over the time (Work Remaining).' => '',
// 'Screenshot taken %s' => '', 'Screenshot taken %s' => '已截图 %s',
// 'Add a screenshot' => '', // 'Add a screenshot' => '',
// 'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => '', // 'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => '',
// 'Screenshot uploaded successfully.' => '', // 'Screenshot uploaded successfully.' => '',
@ -795,7 +795,7 @@ return array(
// 'Help on Sendgrid integration' => '', // 'Help on Sendgrid integration' => '',
// 'Disable two factor authentication' => '', // 'Disable two factor authentication' => '',
// 'Do you really want to disable the two factor authentication for this user: "%s"?' => '', // 'Do you really want to disable the two factor authentication for this user: "%s"?' => '',
// 'Edit link' => '', 'Edit link' => '编辑链接',
// 'Start to type task title...' => '', // 'Start to type task title...' => '',
// 'A task cannot be linked to itself' => '', // 'A task cannot be linked to itself' => '',
// 'The exact same link already exists' => '', // 'The exact same link already exists' => '',
@ -832,28 +832,28 @@ return array(
// 'XMPP server address' => '', // 'XMPP server address' => '',
// 'Jabber domain' => '', // 'Jabber domain' => '',
// 'Jabber nickname' => '', // 'Jabber nickname' => '',
// 'Multi-user chat room' => '', 'Multi-user chat room' => '多用户聊天室',
// 'Help on Jabber integration' => '', // 'Help on Jabber integration' => '',
// 'The server address must use this format: "tcp://hostname:5222"' => '', // 'The server address must use this format: "tcp://hostname:5222"' => '',
// 'Calendar settings' => '', 'Calendar settings' => '日程设置',
// 'Project calendar view' => '', // 'Project calendar view' => '',
// 'Project settings' => '', 'Project settings' => '项目设置',
// 'Show subtasks based on the time tracking' => '', // 'Show subtasks based on the time tracking' => '',
// 'Show tasks based on the creation date' => '', // 'Show tasks based on the creation date' => '',
// 'Show tasks based on the start date' => '', // 'Show tasks based on the start date' => '',
// 'Subtasks time tracking' => '', // 'Subtasks time tracking' => '',
// 'User calendar view' => '', 'User calendar view' => '用户日程视图',
// 'Automatically update the start date' => '', 'Automatically update the start date' => '自动更新开始日期',
// 'iCal feed' => '', // 'iCal feed' => '',
// 'Preferences' => '', 'Preferences' => '偏好',
// 'Security' => '', 'Security' => '安全',
// 'Two factor authentication disabled' => '', // 'Two factor authentication disabled' => '',
// 'Two factor authentication enabled' => '', // 'Two factor authentication enabled' => '',
// 'Unable to update this user.' => '', // 'Unable to update this user.' => '',
// 'There is no user management for private projects.' => '', // 'There is no user management for private projects.' => '',
// 'User that will receive the email' => '', // 'User that will receive the email' => '',
// 'Email subject' => '', 'Email subject' => '邮件主题',
// 'Date' => '', 'Date' => '日期',
// 'By @%s on Bitbucket' => '', // 'By @%s on Bitbucket' => '',
// 'Bitbucket Issue' => '', // 'Bitbucket Issue' => '',
// 'Commit made by @%s on Bitbucket' => '', // 'Commit made by @%s on Bitbucket' => '',
@ -863,7 +863,7 @@ return array(
// 'Add a comment log when moving the task between columns' => '', // 'Add a comment log when moving the task between columns' => '',
// 'Move the task to another column when the category is changed' => '', // 'Move the task to another column when the category is changed' => '',
// 'Send a task by email to someone' => '', // 'Send a task by email to someone' => '',
// 'Reopen a task' => '', 'Reopen a task' => '重新开始一个任务',
// 'Bitbucket issue opened' => '', // 'Bitbucket issue opened' => '',
// 'Bitbucket issue closed' => '', // 'Bitbucket issue closed' => '',
// 'Bitbucket issue reopened' => '', // 'Bitbucket issue reopened' => '',
@ -874,12 +874,12 @@ return array(
// 'Swimlane change' => '', // 'Swimlane change' => '',
// 'Assignee change' => '', // 'Assignee change' => '',
// '[%s] Overdue tasks' => '', // '[%s] Overdue tasks' => '',
// 'Notification' => '', 'Notification' => '通知',
// '%s moved the task #%d to the first swimlane' => '', // '%s moved the task #%d to the first swimlane' => '',
// '%s moved the task #%d to the swimlane "%s"' => '', // '%s moved the task #%d to the swimlane "%s"' => '',
// 'Swimlane' => '', // 'Swimlane' => '',
// 'Budget overview' => '', 'Budget overview' => '预算概览',
// 'Type' => '', 'Type' => '类型',
// 'There is not enough data to show something.' => '', // 'There is not enough data to show something.' => '',
// 'Gravatar' => '', // 'Gravatar' => '',
// 'Hipchat' => '', // 'Hipchat' => '',
@ -924,42 +924,42 @@ return array(
// 'You need at least 2 days of data to show the chart.' => '', // 'You need at least 2 days of data to show the chart.' => '',
// '<15m' => '', // '<15m' => '',
// '<30m' => '', // '<30m' => '',
// 'Stop timer' => '', 'Stop timer' => '停止定时器',
// 'Start timer' => '', 'Start timer' => '开启定时器',
// 'Add project member' => '', 'Add project member' => '添加项目成员',
// 'Enable notifications' => '', 'Enable notifications' => '打开通知',
// 'My activity stream' => '', 'My activity stream' => '我的活动流',
// 'My calendar' => '', 'My calendar' => '我的日程表',
// 'Search tasks' => '', 'Search tasks' => '搜索任务',
// 'Back to the calendar' => '', 'Back to the calendar' => '返回日程',
// 'Filters' => '', 'Filters' => '过滤器',
// 'Reset filters' => '', 'Reset filters' => '重置过滤器',
// 'My tasks due tomorrow' => '', 'My tasks due tomorrow' => '我的明天到期的任务',
// 'Tasks due today' => '', 'Tasks due today' => '今天到期的任务',
// 'Tasks due tomorrow' => '', 'Tasks due tomorrow' => '明天到期的任务',
// 'Tasks due yesterday' => '', 'Tasks due yesterday' => '昨天到期的任务',
// 'Closed tasks' => '', 'Closed tasks' => '已关闭任务',
// 'Open tasks' => '', 'Open tasks' => '打开的任务',
// 'Not assigned' => '', 'Not assigned' => '未指派',
// 'View advanced search syntax' => '', 'View advanced search syntax' => '查看高级搜索语法',
// 'Overview' => '', 'Overview' => '概览',
// '%b %e %Y' => '', // '%b %e %Y' => '',
// 'Board/Calendar/List view' => '', 'Board/Calendar/List view' => '看板/日程/列表视图',
// 'Switch to the board view' => '', 'Switch to the board view' => '切换到看板视图',
// 'Switch to the calendar view' => '', 'Switch to the calendar view' => '切换到日程视图',
// 'Switch to the list view' => '', 'Switch to the list view' => '切换到列表视图',
// 'Go to the search/filter box' => '', 'Go to the search/filter box' => '前往搜索/过滤箱',
// 'There is no activity yet.' => '', 'There is no activity yet.' => '目前无任何活动.',
// 'No tasks found.' => '', 'No tasks found.' => '没有找人任何任务.',
// 'Keyboard shortcut: "%s"' => '', 'Keyboard shortcut: "%s"' => '快捷键: "%s"',
// 'List' => '', 'List' => '列表',
// 'Filter' => '', 'Filter' => '过滤器',
// 'Advanced search' => '', 'Advanced search' => '高级搜索',
// 'Example of query: ' => '', 'Example of query: ' => '查询示例: ',
// 'Search by project: ' => '', 'Search by project: ' => '按项目搜索: ',
// 'Search by column: ' => '', 'Search by column: ' => '按列搜索: ',
// 'Search by assignee: ' => '', 'Search by assignee: ' => '按被指派人搜索: ',
// 'Search by color: ' => '', 'Search by color: ' => '按颜色搜索: ',
// 'Search by category: ' => '', // 'Search by category: ' => '',
// 'Search by description: ' => '', // 'Search by description: ' => '',
// 'Search by due date: ' => '', // 'Search by due date: ' => '',
@ -998,21 +998,73 @@ return array(
// 'Gitlab issue comment created' => '', // 'Gitlab issue comment created' => '',
// 'New remote user' => '', // 'New remote user' => '',
// 'New local user' => '', // 'New local user' => '',
// 'Default task color' => '', 'Default task color' => '默认任务颜色',
// 'Hide sidebar' => '', // 'Hide sidebar' => '',
// 'Expand sidebar' => '', // 'Expand sidebar' => '',
// 'This feature does not work with all browsers.' => '', // 'This feature does not work with all browsers.' => '',
// 'There is no destination project available.' => '', // 'There is no destination project available.' => '',
// 'Trigger automatically subtask time tracking' => '', 'Trigger automatically subtask time tracking' => '自动跟踪子任务时间',
// 'Include closed tasks in the cumulative flow diagram' => '', 'Include closed tasks in the cumulative flow diagram' => '在累计流程图中包含已关闭任务',
// 'Current swimlane: %s' => '', // 'Current swimlane: %s' => '',
// 'Current column: %s' => '', // 'Current column: %s' => '',
// 'Current category: %s' => '', // 'Current category: %s' => '',
// 'no category' => '', 'no category' => '无分类',
// 'Current assignee: %s' => '', 'Current assignee: %s' => '当前被指派人: %s',
// 'not assigned' => '', 'not assigned' => '未指派',
// 'Author:' => '', 'Author:' => '作者',
// 'contributors' => '', 'contributors' => '贡献者',
// 'License:' => '', 'License:' => '授权许可:',
// 'License' => '', 'License' => '授权许可',
'Project Administrator' => '项目管理者',
'Enter the text below' => '输入下方的文本',
'Gantt chart for %s' => '%s的甘特图',
'Sort by position' => '按位置排序',
'Sort by date' => '按日期排序',
'Add task' => '添加任务',
'Start date:' => '开始日期',
'Due date:' => '到期日期',
// 'There is no start date or due date for this task.' => '',
// 'Moving or resizing a task will change the start and due date of the task.' => '',
// 'There is no task in your project.' => '',
'Gantt chart' => '甘特图',
// 'People who are project managers' => '',
// 'People who are project members' => '',
// 'NOK - Norwegian Krone' => '',
// 'Show this column' => '',
// 'Hide this column' => '',
// 'open file' => '',
'End date' => '结束日期',
'Users overview' => '用户概览',
// 'Managers' => '',
'Members' => '成员',
// 'Shared project' => '',
// 'Project managers' => '',
// 'Project members' => '',
// 'Gantt chart for all projects' => '',
// 'Projects list' => '',
// 'Gantt chart for this project' => '',
// 'Project board' => '',
// 'End date:' => '',
// 'There is no start date or end date for this project.' => '',
// 'Projects Gantt chart' => '',
// 'Start date: %s' => '',
// 'End date: %s' => '',
// 'Link type' => '',
// 'Change task color when using a specific task link' => '',
// 'Task link creation or modification' => '',
// 'Login with my Gitlab Account' => '',
// 'Milestone' => '',
// 'Gitlab Authentication' => '',
// 'Help on Gitlab authentication' => '',
// 'Gitlab Id' => '',
// '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' => '',
); );

View file

@ -17,13 +17,13 @@ class Acl extends Base
* @var array * @var array
*/ */
private $public_acl = array( private $public_acl = array(
'auth' => array('login', 'check'), 'auth' => array('login', 'check', 'captcha'),
'task' => array('readonly'), 'task' => array('readonly'),
'board' => array('readonly'), 'board' => array('readonly'),
'webhook' => '*', 'webhook' => '*',
'ical' => '*', 'ical' => '*',
'feed' => '*', 'feed' => '*',
'oauth' => array('google', 'github'), 'oauth' => array('google', 'github', 'gitlab'),
); );
/** /**
@ -32,7 +32,7 @@ class Acl extends Base
* @access private * @access private
* @var array * @var array
*/ */
private $member_acl = array( private $project_member_acl = array(
'board' => '*', 'board' => '*',
'comment' => '*', 'comment' => '*',
'file' => '*', 'file' => '*',
@ -56,15 +56,28 @@ class Acl extends Base
* @access private * @access private
* @var array * @var array
*/ */
private $manager_acl = array( private $project_manager_acl = array(
'action' => '*', 'action' => '*',
'analytic' => '*', 'analytic' => '*',
'category' => '*', 'category' => '*',
'column' => '*', 'column' => '*',
'export' => array('tasks', 'subtasks', 'summary'), 'export' => '*',
'project' => array('edit', 'update', 'share', 'integration', 'users', 'alloweverybody', 'allow', 'setowner', 'revoke', 'duplicate', 'disable', 'enable'), 'project' => array('edit', 'update', 'share', 'integration', 'users', 'alloweverybody', 'allow', 'setowner', 'revoke', 'duplicate', 'disable', 'enable'),
'swimlane' => '*', 'swimlane' => '*',
'budget' => '*', 'budget' => '*',
'gantt' => array('project', 'savetaskdate', 'task', 'savetask'),
);
/**
* Controllers and actions for project admins
*
* @access private
* @var array
*/
private $project_admin_acl = array(
'project' => array('remove'),
'projectuser' => '*',
'gantt' => array('projects', 'saveprojectdate'),
); );
/** /**
@ -77,8 +90,6 @@ class Acl extends Base
'user' => array('index', 'create', 'save', 'remove', 'authentication'), 'user' => array('index', 'create', 'save', 'remove', 'authentication'),
'config' => '*', 'config' => '*',
'link' => '*', 'link' => '*',
'project' => array('remove'),
'hourlyrate' => '*',
'currency' => '*', 'currency' => '*',
'twofactor' => array('disable'), 'twofactor' => array('disable'),
); );
@ -149,9 +160,22 @@ class Acl extends Base
* @param string $action Action name * @param string $action Action name
* @return bool * @return bool
*/ */
public function isManagerAction($controller, $action) public function isProjectManagerAction($controller, $action)
{ {
return $this->matchAcl($this->manager_acl, $controller, $action); return $this->matchAcl($this->project_manager_acl, $controller, $action);
}
/**
* Return true if the given action is for application managers
*
* @access public
* @param string $controller Controller name
* @param string $action Action name
* @return bool
*/
public function isProjectAdminAction($controller, $action)
{
return $this->matchAcl($this->project_admin_acl, $controller, $action);
} }
/** /**
@ -162,9 +186,9 @@ class Acl extends Base
* @param string $action Action name * @param string $action Action name
* @return bool * @return bool
*/ */
public function isMemberAction($controller, $action) public function isProjectMemberAction($controller, $action)
{ {
return $this->matchAcl($this->member_acl, $controller, $action); return $this->matchAcl($this->project_member_acl, $controller, $action);
} }
/** /**
@ -189,13 +213,18 @@ class Acl extends Base
return false; return false;
} }
// Check project admin permissions
if ($this->isProjectAdminAction($controller, $action)) {
return $this->handleProjectAdminPermissions($project_id);
}
// Check project manager permissions // Check project manager permissions
if ($this->isManagerAction($controller, $action)) { if ($this->isProjectManagerAction($controller, $action)) {
return $this->isManagerActionAllowed($project_id); return $this->handleProjectManagerPermissions($project_id);
} }
// Check project member permissions // Check project member permissions
if ($this->isMemberAction($controller, $action)) { if ($this->isProjectMemberAction($controller, $action)) {
return $project_id > 0 && $this->projectPermission->isMember($project_id, $this->userSession->getId()); return $project_id > 0 && $this->projectPermission->isMember($project_id, $this->userSession->getId());
} }
@ -203,12 +232,43 @@ class Acl extends Base
return true; return true;
} }
public function isManagerActionAllowed($project_id) /**
* Handle permission for project manager
*
* @access public
* @param integer $project_id
* @return boolean
*/
public function handleProjectManagerPermissions($project_id)
{ {
if ($this->userSession->isAdmin()) { if ($project_id > 0) {
return true; if ($this->userSession->isProjectAdmin()) {
return $this->projectPermission->isMember($project_id, $this->userSession->getId());
} }
return $project_id > 0 && $this->projectPermission->isManager($project_id, $this->userSession->getId()); return $this->projectPermission->isManager($project_id, $this->userSession->getId());
}
return false;
}
/**
* Handle permission for project admins
*
* @access public
* @param integer $project_id
* @return boolean
*/
public function handleProjectAdminPermissions($project_id)
{
if (! $this->userSession->isProjectAdmin()) {
return false;
}
if ($project_id > 0) {
return $this->projectPermission->isMember($project_id, $this->userSession->getId());
}
return true;
} }
} }

View file

@ -59,6 +59,7 @@ class Action extends Base
'TaskUpdateStartDate' => t('Automatically update the start date'), 'TaskUpdateStartDate' => t('Automatically update the start date'),
'TaskMoveColumnCategoryChange' => t('Move the task to another column when the category is changed'), 'TaskMoveColumnCategoryChange' => t('Move the task to another column when the category is changed'),
'TaskEmail' => t('Send a task by email to someone'), 'TaskEmail' => t('Send a task by email to someone'),
'TaskAssignColorLink' => t('Change task color when using a specific task link'),
); );
asort($values); asort($values);
@ -75,6 +76,7 @@ class Action extends Base
public function getAvailableEvents() public function getAvailableEvents()
{ {
$values = array( $values = array(
TaskLink::EVENT_CREATE_UPDATE => t('Task link creation or modification'),
Task::EVENT_MOVE_COLUMN => t('Move a task to another column'), Task::EVENT_MOVE_COLUMN => t('Move a task to another column'),
Task::EVENT_UPDATE => t('Task modification'), Task::EVENT_UPDATE => t('Task modification'),
Task::EVENT_CREATE => t('Task creation'), Task::EVENT_CREATE => t('Task creation'),

View file

@ -5,6 +5,7 @@ namespace Model;
use Core\Request; use Core\Request;
use SimpleValidator\Validator; use SimpleValidator\Validator;
use SimpleValidator\Validators; use SimpleValidator\Validators;
use Gregwar\Captcha\CaptchaBuilder;
/** /**
* Authentication model * Authentication model
@ -53,7 +54,7 @@ class Authentication extends Base
} }
// We try first with the RememberMe cookie // We try first with the RememberMe cookie
if ($this->backend('rememberMe')->authenticate()) { if (REMEMBER_ME_AUTH && $this->backend('rememberMe')->authenticate()) {
return true; return true;
} }
@ -75,17 +76,51 @@ class Authentication extends Base
*/ */
public function authenticate($username, $password) public function authenticate($username, $password)
{ {
// Try first the database auth and then LDAP if activated if ($this->user->isLocked($username)) {
if ($this->backend('database')->authenticate($username, $password)) { $this->container['logger']->error('Account locked: '.$username);
return false;
}
else if ($this->backend('database')->authenticate($username, $password)) {
$this->user->resetFailedLogin($username);
return true; return true;
} }
else if (LDAP_AUTH && $this->backend('ldap')->authenticate($username, $password)) { else if (LDAP_AUTH && $this->backend('ldap')->authenticate($username, $password)) {
$this->user->resetFailedLogin($username);
return true; return true;
} }
$this->handleFailedLogin($username);
return false; return false;
} }
/**
* Return true if the captcha must be shown
*
* @access public
* @param string $username
* @return boolean
*/
public function hasCaptcha($username)
{
return $this->user->getFailedLogin($username) >= BRUTEFORCE_CAPTCHA;
}
/**
* Handle failed login
*
* @access public
* @param string $username
*/
public function handleFailedLogin($username)
{
$this->user->incrementFailedLogin($username);
if ($this->user->getFailedLogin($username) >= BRUTEFORCE_LOCKDOWN) {
$this->container['logger']->critical('Locking account: '.$username);
$this->user->lock($username, BRUTEFORCE_LOCKDOWN_DURATION);
}
}
/** /**
* Validate user login form * Validate user login form
* *
@ -95,27 +130,12 @@ class Authentication extends Base
*/ */
public function validateForm(array $values) public function validateForm(array $values)
{ {
$v = new Validator($values, array( list($result, $errors) = $this->validateFormCredentials($values);
new Validators\Required('username', t('The username is required')),
new Validators\MaxLength('username', t('The maximum length is %d characters', 50), 50),
new Validators\Required('password', t('The password is required')),
));
$result = $v->execute();
$errors = $v->getErrors();
if ($result) { if ($result) {
if ($this->authenticate($values['username'], $values['password'])) { if ($this->validateFormCaptcha($values) && $this->authenticate($values['username'], $values['password'])) {
$this->createRememberMeSession($values);
// Setup the remember me feature
if (! empty($values['remember_me'])) {
$credentials = $this->backend('rememberMe')
->create($this->userSession->getId(), Request::getIpAddress(), Request::getUserAgent());
$this->backend('rememberMe')->writeCookie($credentials['token'], $credentials['sequence'], $credentials['expiration']);
}
} }
else { else {
$result = false; $result = false;
@ -123,9 +143,62 @@ class Authentication extends Base
} }
} }
return array($result, $errors);
}
/**
* Validate credentials syntax
*
* @access public
* @param array $values Form values
* @return array $valid, $errors [0] = Success or not, [1] = List of errors
*/
public function validateFormCredentials(array $values)
{
$v = new Validator($values, array(
new Validators\Required('username', t('The username is required')),
new Validators\MaxLength('username', t('The maximum length is %d characters', 50), 50),
new Validators\Required('password', t('The password is required')),
));
return array( return array(
$result, $v->execute(),
$errors $v->getErrors(),
); );
} }
/**
* Validate captcha
*
* @access public
* @param array $values Form values
* @return boolean
*/
public function validateFormCaptcha(array $values)
{
if ($this->hasCaptcha($values['username'])) {
$builder = new CaptchaBuilder;
$builder->setPhrase($this->session['captcha']);
return $builder->testPhrase(isset($values['captcha']) ? $values['captcha'] : '');
}
return true;
}
/**
* Create remember me session if necessary
*
* @access private
* @param array $values Form values
*/
private function createRememberMeSession(array $values)
{
if (REMEMBER_ME_AUTH && ! empty($values['remember_me'])) {
$credentials = $this->backend('rememberMe')
->create($this->userSession->getId(), Request::getIpAddress(), Request::getUserAgent());
$this->backend('rememberMe')->writeCookie($credentials['token'], $credentials['sequence'], $credentials['expiration']);
}
}
} }

View file

@ -122,6 +122,22 @@ class Color extends Base
return ''; return '';
} }
/**
* Get color properties
*
* @access public
* @param string $color_id
* @return array
*/
public function getColorProperties($color_id)
{
if (isset($this->default_colors[$color_id])) {
return $this->default_colors[$color_id];
}
return $this->default_colors[$this->getDefaultColor()];
}
/** /**
* Get available colors * Get available colors
* *
@ -150,6 +166,17 @@ class Color extends Base
return $this->config->get('default_color', 'yellow'); return $this->config->get('default_color', 'yellow');
} }
/**
* Get the default colors
*
* @access public
* @return array
*/
public function getDefaultColors()
{
return $this->default_colors;
}
/** /**
* Get Bordercolor from string * Get Bordercolor from string
* *
@ -159,11 +186,8 @@ class Color extends Base
*/ */
public function getBorderColor($color_id) public function getBorderColor($color_id)
{ {
if (isset($this->default_colors[$color_id])) { $color = $this->getColorProperties($color_id);
return $this->default_colors[$color_id]['border']; return $color['border'];
}
return $this->default_colors[$this->getDefaultColor()]['border'];
} }
/** /**
@ -175,11 +199,8 @@ class Color extends Base
*/ */
public function getBackgroundColor($color_id) public function getBackgroundColor($color_id)
{ {
if (isset($this->default_colors[$color_id])) { $color = $this->getColorProperties($color_id);
return $this->default_colors[$color_id]['background']; return $color['background'];
}
return $this->default_colors[$this->getDefaultColor()]['background'];
} }
/** /**

View file

@ -41,6 +41,7 @@ class Config extends Base
'JPY' => t('JPY - Japanese Yen'), 'JPY' => t('JPY - Japanese Yen'),
'RSD' => t('RSD - Serbian dinar'), 'RSD' => t('RSD - Serbian dinar'),
'SEK' => t('SEK - Swedish Krona'), 'SEK' => t('SEK - Swedish Krona'),
'NOK' => t('NOK - Norwegian Krone'),
); );
} }
@ -83,7 +84,9 @@ class Config extends Base
'it_IT' => 'Italiano', 'it_IT' => 'Italiano',
'hu_HU' => 'Magyar', 'hu_HU' => 'Magyar',
'nl_NL' => 'Nederlands', 'nl_NL' => 'Nederlands',
'nb_NO' => 'Norsk',
'pl_PL' => 'Polski', 'pl_PL' => 'Polski',
'pt_PT' => 'Português',
'pt_BR' => 'Português (Brasil)', 'pt_BR' => 'Português (Brasil)',
'ru_RU' => 'Русский', 'ru_RU' => 'Русский',
'sr_Latn_RS' => 'Srpski', 'sr_Latn_RS' => 'Srpski',
@ -120,7 +123,9 @@ class Config extends Base
'it_IT' => 'it', 'it_IT' => 'it',
'hu_HU' => 'hu', 'hu_HU' => 'hu',
'nl_NL' => 'nl', 'nl_NL' => 'nl',
'nb_NO' => 'nb',
'pl_PL' => 'pl', 'pl_PL' => 'pl',
'pt_PT' => 'pt',
'pt_BR' => 'pt-br', 'pt_BR' => 'pt-br',
'ru_RU' => 'ru', 'ru_RU' => 'ru',
'sr_Latn_RS' => 'sr', 'sr_Latn_RS' => 'sr',

View file

@ -77,7 +77,7 @@ class DateParser extends Base
} }
/** /**
* Parse a date ad return a unix timestamp, try different date formats * Parse a date and return a unix timestamp, try different date formats
* *
* @access public * @access public
* @param string $value Date to parse * @param string $value Date to parse
@ -96,6 +96,18 @@ class DateParser extends Base
return 0; return 0;
} }
/**
* Get ISO8601 date from user input
*
* @access public
* @param string $value Date to parse
* @return string
*/
public function getIsoDate($value)
{
return date('Y-m-d', ctype_digit($value) ? $value : $this->getTimestamp($value));
}
/** /**
* Get all combinations of date/time formats * Get all combinations of date/time formats
* *
@ -157,6 +169,7 @@ class DateParser extends Base
'm/d/Y' => date('m/d/Y'), 'm/d/Y' => date('m/d/Y'),
'd/m/Y' => date('d/m/Y'), 'd/m/Y' => date('d/m/Y'),
'Y/m/d' => date('Y/m/d'), 'Y/m/d' => date('Y/m/d'),
'd.m.Y' => date('d.m.Y'),
); );
} }

View file

@ -228,7 +228,7 @@ class File extends Base
if ($error == UPLOAD_ERR_OK && $_FILES[$form_name]['size'][$key] > 0) { if ($error == UPLOAD_ERR_OK && $_FILES[$form_name]['size'][$key] > 0) {
$original_filename = basename($_FILES[$form_name]['name'][$key]); $original_filename = $_FILES[$form_name]['name'][$key];
$uploaded_filename = $_FILES[$form_name]['tmp_name'][$key]; $uploaded_filename = $_FILES[$form_name]['tmp_name'][$key];
$destination_filename = $this->generatePath($project_id, $task_id, $original_filename); $destination_filename = $this->generatePath($project_id, $task_id, $original_filename);

View file

@ -114,6 +114,54 @@ class Project extends Base
return $this->db->table(self::TABLE)->eq('id', $project_id)->eq('is_private', 1)->exists(); return $this->db->table(self::TABLE)->eq('id', $project_id)->eq('is_private', 1)->exists();
} }
/**
* Get all projects to generate the Gantt chart
*
* @access public
* @param array $project_ids
* @return array
*/
public function getGanttBars(array $project_ids)
{
if (empty($project_ids)) {
return array();
}
$colors = $this->color->getDefaultColors();
$projects = $this->db->table(self::TABLE)->asc('start_date')->in('id', $project_ids)->eq('is_active', self::ACTIVE)->eq('is_private', 0)->findAll();
$bars = array();
foreach ($projects as $project) {
$start = empty($project['start_date']) ? time() : strtotime($project['start_date']);
$end = empty($project['end_date']) ? $start : strtotime($project['end_date']);
$color = next($colors) ?: reset($colors);
$bars[] = array(
'type' => 'project',
'id' => $project['id'],
'title' => $project['name'],
'start' => array(
(int) date('Y', $start),
(int) date('n', $start),
(int) date('j', $start),
),
'end' => array(
(int) date('Y', $end),
(int) date('n', $end),
(int) date('j', $end),
),
'link' => $this->helper->url->href('project', 'show', array('project_id' => $project['id'])),
'board_link' => $this->helper->url->href('board', 'show', array('project_id' => $project['id'])),
'gantt_link' => $this->helper->url->href('gantt', 'project', array('project_id' => $project['id'])),
'color' => $color,
'not_defined' => empty($project['start_date']) || empty($project['end_date']),
'users' => $this->projectPermission->getProjectUsers($project['id']),
);
}
return $bars;
}
/** /**
* Get all projects * Get all projects
* *
@ -260,6 +308,23 @@ class Project extends Base
return $projects; return $projects;
} }
/**
* Fetch more information for each project
*
* @access public
* @param array $projects
* @return array
*/
public function applyProjectDetails(array $projects)
{
foreach ($projects as &$project) {
$this->getColumnStats($project);
$project = array_merge($project, $this->projectPermission->getProjectUsers($project['id']));
}
return $projects;
}
/** /**
* Get project summary for a list of project * Get project summary for a list of project
* *
@ -279,6 +344,25 @@ class Project extends Base
->callback(array($this, 'applyColumnStats')); ->callback(array($this, 'applyColumnStats'));
} }
/**
* Get project details (users + columns) for a list of project
*
* @access public
* @param array $project_ids List of project id
* @return \PicoDb\Table
*/
public function getQueryProjectDetails(array $project_ids)
{
if (empty($project_ids)) {
return $this->db->table(Project::TABLE)->limit(0);
}
return $this->db
->table(Project::TABLE)
->in('id', $project_ids)
->callback(array($this, 'applyProjectDetails'));
}
/** /**
* Create a project * Create a project
* *
@ -472,6 +556,8 @@ class Project extends Base
new Validators\Required('name', t('The project name is required')), new Validators\Required('name', t('The project name is required')),
new Validators\MaxLength('name', t('The maximum length is %d characters', 50), 50), new Validators\MaxLength('name', t('The maximum length is %d characters', 50), 50),
new Validators\MaxLength('identifier', t('The maximum length is %d characters', 50), 50), new Validators\MaxLength('identifier', t('The maximum length is %d characters', 50), 50),
new Validators\MaxLength('start_date', t('The maximum length is %d characters', 10), 10),
new Validators\MaxLength('end_date', t('The maximum length is %d characters', 10), 10),
new Validators\AlphaNumeric('identifier', t('This value must be alphanumeric')) , new Validators\AlphaNumeric('identifier', t('This value must be alphanumeric')) ,
new Validators\Unique('name', t('This project must be unique'), $this->db->getConnection(), self::TABLE), new Validators\Unique('name', t('This project must be unique'), $this->db->getConnection(), self::TABLE),
new Validators\Unique('identifier', t('The identifier must be unique'), $this->db->getConnection(), self::TABLE), new Validators\Unique('identifier', t('The identifier must be unique'), $this->db->getConnection(), self::TABLE),

View file

@ -167,10 +167,12 @@ class ProjectAnalytic extends Base
$sums[$task['column_id']] += ($task['date_completed'] ?: time()) - $task['date_moved']; $sums[$task['column_id']] += ($task['date_completed'] ?: time()) - $task['date_moved'];
foreach ($sums as $column_id => $time_spent) { foreach ($sums as $column_id => $time_spent) {
if (isset($stats[$column_id])) {
$stats[$column_id]['count']++; $stats[$column_id]['count']++;
$stats[$column_id]['time_spent'] += $time_spent; $stats[$column_id]['time_spent'] += $time_spent;
} }
} }
}
// Calculate average for each column // Calculate average for each column
foreach ($columns as $column_id => $column_title) { foreach ($columns as $column_id => $column_title) {

View file

@ -49,6 +49,36 @@ class ProjectPermission extends Base
return $allowed_users; return $allowed_users;
} }
/**
* Get a list of members and managers with a single SQL query
*
* @access public
* @param integer $project_id Project id
* @return array
*/
public function getProjectUsers($project_id)
{
$result = array(
'managers' => array(),
'members' => array(),
);
$users = $this->db
->table(self::TABLE)
->join(User::TABLE, 'id', 'user_id')
->eq('project_id', $project_id)
->asc('username')
->columns(User::TABLE.'.id', User::TABLE.'.username', User::TABLE.'.name', self::TABLE.'.is_owner')
->findAll();
foreach ($users as $user) {
$key = $user['is_owner'] == 1 ? 'managers' : 'members';
$result[$key][$user['id']] = $user['name'] ?: $user['username'];
}
return $result;
}
/** /**
* Get a list of allowed people for a project * Get a list of allowed people for a project
* *
@ -65,26 +95,6 @@ class ProjectPermission extends Base
return $this->getAssociatedUsers($project_id); return $this->getAssociatedUsers($project_id);
} }
/**
* Get a list of people associated to the project
*
* @access public
* @param integer $project_id Project id
* @return array
*/
public function getAssociatedUsers($project_id)
{
$users = $this->db
->table(self::TABLE)
->join(User::TABLE, 'id', 'user_id')
->eq('project_id', $project_id)
->asc('username')
->columns(User::TABLE.'.id', User::TABLE.'.username', User::TABLE.'.name')
->findAll();
return $this->user->prepareList($users);
}
/** /**
* Get a list of owners for a project * Get a list of owners for a project
* *
@ -106,6 +116,57 @@ class ProjectPermission extends Base
return $this->user->prepareList($users); return $this->user->prepareList($users);
} }
/**
* Get query for project users overview
*
* @access public
* @param array $project_ids
* @param integer $is_owner
* @return \PicoDb\Table
*/
public function getQueryByRole(array $project_ids, $is_owner = 0)
{
if (empty($project_ids)) {
$project_ids = array(-1);
}
return $this
->db
->table(self::TABLE)
->join(User::TABLE, 'id', 'user_id')
->join(Project::TABLE, 'id', 'project_id')
->eq(self::TABLE.'.is_owner', $is_owner)
->eq(Project::TABLE.'.is_private', 0)
->in(Project::TABLE.'.id', $project_ids)
->columns(
User::TABLE.'.id',
User::TABLE.'.username',
User::TABLE.'.name',
Project::TABLE.'.name AS project_name',
Project::TABLE.'.id'
);
}
/**
* Get a list of people associated to the project
*
* @access public
* @param integer $project_id Project id
* @return array
*/
public function getAssociatedUsers($project_id)
{
$users = $this->db
->table(self::TABLE)
->join(User::TABLE, 'id', 'user_id')
->eq('project_id', $project_id)
->asc('username')
->columns(User::TABLE.'.id', User::TABLE.'.username', User::TABLE.'.name')
->findAll();
return $this->user->prepareList($users);
}
/** /**
* Get allowed and not allowed users for a project * Get allowed and not allowed users for a project
* *
@ -127,7 +188,6 @@ class ProjectPermission extends Base
$users['managers'] = $this->getManagers($project_id); $users['managers'] = $this->getManagers($project_id);
foreach ($all_users as $user_id => $username) { foreach ($all_users as $user_id => $username) {
if (! isset($users['allowed'][$user_id])) { if (! isset($users['allowed'][$user_id])) {
$users['not_allowed'][$user_id] = $username; $users['not_allowed'][$user_id] = $username;
} }
@ -269,26 +329,6 @@ class ProjectPermission extends Base
->exists(); ->exists();
} }
/**
* Filter a list of projects for a given user
*
* @access public
* @param array $projects Project list: ['project_id' => 'project_name']
* @param integer $user_id User id
* @param string $filter Method name to apply
* @return array
*/
public function filterProjects(array $projects, $user_id, $filter = 'isUserAllowed')
{
foreach ($projects as $project_id => $project_name) {
if (! $this->$filter($project_id, $user_id)) {
unset($projects[$project_id]);
}
}
return $projects;
}
/** /**
* Return a list of allowed active projects for a given user * Return a list of allowed active projects for a given user
* *

View file

@ -301,7 +301,6 @@ class SubtaskTimeTracking extends Base
->findOneColumn('start'); ->findOneColumn('start');
if ($start_time) { if ($start_time) {
$start = new DateTime; $start = new DateTime;
$start->setTimestamp($start_time); $start->setTimestamp($start_time);
@ -341,18 +340,24 @@ class SubtaskTimeTracking extends Base
public function updateTaskTimeTracking($task_id) public function updateTaskTimeTracking($task_id)
{ {
$result = $this->calculateSubtaskTime($task_id); $result = $this->calculateSubtaskTime($task_id);
$values = array();
if (empty($result['total_spent']) && empty($result['total_estimated'])) { if ($result['total_spent'] > 0) {
$values['time_spent'] = $result['total_spent'];
}
if ($result['total_estimated'] > 0) {
$values['time_estimated'] = $result['total_estimated'];
}
if (empty($values)) {
return true; return true;
} }
return $this->db return $this->db
->table(Task::TABLE) ->table(Task::TABLE)
->eq('id', $task_id) ->eq('id', $task_id)
->update(array( ->update($values);
'time_spent' => $result['total_spent'],
'time_estimated' => $result['total_estimated'],
));
} }
/** /**

View file

@ -121,7 +121,7 @@ class Task extends Base
*/ */
public function getRecurrenceStatusList() public function getRecurrenceStatusList()
{ {
return array ( return array(
Task::RECURRING_STATUS_NONE => t('No'), Task::RECURRING_STATUS_NONE => t('No'),
Task::RECURRING_STATUS_PENDING => t('Yes'), Task::RECURRING_STATUS_PENDING => t('Yes'),
); );
@ -135,7 +135,7 @@ class Task extends Base
*/ */
public function getRecurrenceTriggerList() public function getRecurrenceTriggerList()
{ {
return array ( return array(
Task::RECURRING_TRIGGER_FIRST_COLUMN => t('When task is moved from first column'), Task::RECURRING_TRIGGER_FIRST_COLUMN => t('When task is moved from first column'),
Task::RECURRING_TRIGGER_LAST_COLUMN => t('When task is moved to last column'), Task::RECURRING_TRIGGER_LAST_COLUMN => t('When task is moved to last column'),
Task::RECURRING_TRIGGER_CLOSE => t('When task is closed'), Task::RECURRING_TRIGGER_CLOSE => t('When task is closed'),
@ -150,7 +150,7 @@ class Task extends Base
*/ */
public function getRecurrenceBasedateList() public function getRecurrenceBasedateList()
{ {
return array ( return array(
Task::RECURRING_BASEDATE_DUEDATE => t('Existing due date'), Task::RECURRING_BASEDATE_DUEDATE => t('Existing due date'),
Task::RECURRING_BASEDATE_TRIGGERDATE => t('Action date'), Task::RECURRING_BASEDATE_TRIGGERDATE => t('Action date'),
); );
@ -164,10 +164,37 @@ class Task extends Base
*/ */
public function getRecurrenceTimeframeList() public function getRecurrenceTimeframeList()
{ {
return array ( return array(
Task::RECURRING_TIMEFRAME_DAYS => t('Day(s)'), Task::RECURRING_TIMEFRAME_DAYS => t('Day(s)'),
Task::RECURRING_TIMEFRAME_MONTHS => t('Month(s)'), Task::RECURRING_TIMEFRAME_MONTHS => t('Month(s)'),
Task::RECURRING_TIMEFRAME_YEARS => t('Year(s)'), Task::RECURRING_TIMEFRAME_YEARS => t('Year(s)'),
); );
} }
/**
* Get task progress based on the column position
*
* @access public
* @param array $task
* @param array $columns
* @return integer
*/
public function getProgress(array $task, array $columns)
{
if ($task['is_active'] == self::STATUS_CLOSED) {
return 100;
}
$position = 0;
foreach ($columns as $column_id => $column_title) {
if ($column_id == $task['column_id']) {
break;
}
$position++;
}
return round(($position * 100) / count($columns), 1);
}
} }

View file

@ -25,10 +25,17 @@ class TaskCreation extends Base
return 0; return 0;
} }
$position = empty($values['position']) ? 0 : $values['position'];
$this->prepare($values); $this->prepare($values);
$task_id = $this->persist(Task::TABLE, $values); $task_id = $this->persist(Task::TABLE, $values);
if ($task_id !== false) { if ($task_id !== false) {
if ($position > 0 && $values['position'] > 1) {
$this->taskPosition->movePosition($values['project_id'], $task_id, $values['column_id'], $position, $values['swimlane_id'], false);
}
$this->fireEvents($task_id, $values); $this->fireEvents($task_id, $values);
} }
@ -46,7 +53,7 @@ class TaskCreation extends Base
$this->dateParser->convert($values, array('date_due')); $this->dateParser->convert($values, array('date_due'));
$this->dateParser->convert($values, array('date_started'), true); $this->dateParser->convert($values, array('date_started'), true);
$this->removeFields($values, array('another_task')); $this->removeFields($values, array('another_task'));
$this->resetFields($values, array('creator_id', 'owner_id', 'swimlane_id', 'date_due', 'score', 'category_id', 'time_estimated')); $this->resetFields($values, array('date_started', 'creator_id', 'owner_id', 'swimlane_id', 'date_due', 'score', 'category_id', 'time_estimated'));
if (empty($values['column_id'])) { if (empty($values['column_id'])) {
$values['column_id'] = $this->board->getFirstColumn($values['project_id']); $values['column_id'] = $this->board->getFirstColumn($values['project_id']);

View file

@ -36,7 +36,7 @@ class TaskFilter extends Base
$this->query = $this->taskFinder->getExtendedQuery(); $this->query = $this->taskFinder->getExtendedQuery();
if (empty($tree)) { if (empty($tree)) {
$this->query->addCondition('1 = 0'); $this->filterByTitle($input);
} }
foreach ($tree as $filter => $value) { foreach ($tree as $filter => $value) {
@ -101,6 +101,7 @@ class TaskFilter extends Base
$this->query->columns( $this->query->columns(
Task::TABLE.'.*', Task::TABLE.'.*',
'ua.email AS assignee_email', 'ua.email AS assignee_email',
'ua.name AS assignee_name',
'ua.username AS assignee_username', 'ua.username AS assignee_username',
'uc.email AS creator_email', 'uc.email AS creator_email',
'uc.username AS creator_username' 'uc.username AS creator_username'
@ -209,11 +210,11 @@ class TaskFilter extends Base
*/ */
public function filterByTitle($title) public function filterByTitle($title)
{ {
if (strlen($title) > 1 && $title{0} === '#' && ctype_digit(substr($title, 1))) { if (ctype_digit($title) || (strlen($title) > 1 && $title{0} === '#' && ctype_digit(substr($title, 1)))) {
$this->query->eq(Task::TABLE.'.id', substr($title, 1)); $this->query->beginOr();
} $this->query->eq(Task::TABLE.'.id', str_replace('#', '', $title));
else if (ctype_digit($title)) { $this->query->ilike(Task::TABLE.'.title', '%'.$title.'%');
$this->query->eq(Task::TABLE.'.id', $title); $this->query->closeOr();
} }
else { else {
$this->query->ilike(Task::TABLE.'.title', '%'.$title.'%'); $this->query->ilike(Task::TABLE.'.title', '%'.$title.'%');
@ -673,6 +674,51 @@ class TaskFilter extends Base
}); });
} }
/**
* Format tasks to be displayed in the Gantt chart
*
* @access public
* @return array
*/
public function toGanttBars()
{
$bars = array();
$columns = array();
foreach ($this->query->findAll() as $task) {
if (! isset($column_count[$task['project_id']])) {
$columns[$task['project_id']] = $this->board->getColumnsList($task['project_id']);
}
$start = $task['date_started'] ?: time();
$end = $task['date_due'] ?: $start;
$bars[] = array(
'type' => 'task',
'id' => $task['id'],
'title' => $task['title'],
'start' => array(
(int) date('Y', $start),
(int) date('n', $start),
(int) date('j', $start),
),
'end' => array(
(int) date('Y', $end),
(int) date('n', $end),
(int) date('j', $end),
),
'column_title' => $task['column_name'],
'assignee' => $task['assignee_name'] ?: $task['assignee_username'],
'progress' => $this->task->getProgress($task, $columns[$task['project_id']]).'%',
'link' => $this->helper->url->href('task', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id'])),
'color' => $this->color->getColorProperties($task['color_id']),
'not_defined' => empty($task['date_due']) || empty($task['date_started']),
);
}
return $bars;
}
/** /**
* Format the results to the ajax autocompletion * Format the results to the ajax autocompletion
* *
@ -833,7 +879,7 @@ class TaskFilter extends Base
$vEvent->setUrl($this->helper->url->base().$this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']))); $vEvent->setUrl($this->helper->url->base().$this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])));
if (! empty($task['owner_id'])) { if (! empty($task['owner_id'])) {
$vEvent->setOrganizer('MAILTO:'.($task['assignee_email'] ?: $task['assignee_username'].'@kanboard.local')); $vEvent->setOrganizer($task['assignee_name'] ?: $task['assignee_username'], $task['assignee_email']);
} }
if (! empty($task['creator_id'])) { if (! empty($task['creator_id'])) {

View file

@ -12,6 +12,43 @@ use PDO;
*/ */
class TaskFinder extends Base class TaskFinder extends Base
{ {
/**
* Get query for project user overview
*
* @access public
* @param array $project_ids
* @param integer $is_active
* @return \PicoDb\Table
*/
public function getProjectUserOverviewQuery(array $project_ids, $is_active)
{
if (empty($project_ids)) {
$project_ids = array(-1);
}
return $this->db
->table(Task::TABLE)
->columns(
Task::TABLE.'.id',
Task::TABLE.'.title',
Task::TABLE.'.date_due',
Task::TABLE.'.date_started',
Task::TABLE.'.project_id',
Task::TABLE.'.color_id',
Task::TABLE.'.time_spent',
Task::TABLE.'.time_estimated',
Project::TABLE.'.name AS project_name',
Board::TABLE.'.title AS column_name',
User::TABLE.'.username AS assignee_username',
User::TABLE.'.name AS assignee_name'
)
->eq(Task::TABLE.'.is_active', $is_active)
->in(Project::TABLE.'.id', $project_ids)
->join(Project::TABLE, 'id', 'project_id')
->join(Board::TABLE, 'id', 'column_id', Task::TABLE)
->join(User::TABLE, 'id', 'owner_id', Task::TABLE);
}
/** /**
* Get query for assigned user tasks * Get query for assigned user tasks
* *
@ -56,6 +93,7 @@ class TaskFinder extends Base
'(SELECT count(*) FROM '.Subtask::TABLE.' WHERE '.Subtask::TABLE.'.task_id=tasks.id) AS nb_subtasks', '(SELECT count(*) FROM '.Subtask::TABLE.' WHERE '.Subtask::TABLE.'.task_id=tasks.id) AS nb_subtasks',
'(SELECT count(*) FROM '.Subtask::TABLE.' WHERE '.Subtask::TABLE.'.task_id=tasks.id AND status=2) AS nb_completed_subtasks', '(SELECT count(*) FROM '.Subtask::TABLE.' WHERE '.Subtask::TABLE.'.task_id=tasks.id AND status=2) AS nb_completed_subtasks',
'(SELECT count(*) FROM '.TaskLink::TABLE.' WHERE '.TaskLink::TABLE.'.task_id = tasks.id) AS nb_links', '(SELECT count(*) FROM '.TaskLink::TABLE.' WHERE '.TaskLink::TABLE.'.task_id = tasks.id) AS nb_links',
'(SELECT 1 FROM '.TaskLink::TABLE.' WHERE '.TaskLink::TABLE.'.task_id = tasks.id AND '.TaskLink::TABLE.'.link_id = 9) AS is_milestone',
'tasks.id', 'tasks.id',
'tasks.reference', 'tasks.reference',
'tasks.title', 'tasks.title',
@ -89,6 +127,7 @@ class TaskFinder extends Base
Category::TABLE.'.name AS category_name', Category::TABLE.'.name AS category_name',
Category::TABLE.'.description AS category_description', Category::TABLE.'.description AS category_description',
Board::TABLE.'.title AS column_name', Board::TABLE.'.title AS column_name',
Board::TABLE.'.position AS column_position',
Swimlane::TABLE.'.name AS swimlane_name', Swimlane::TABLE.'.name AS swimlane_name',
Project::TABLE.'.default_swimlane', Project::TABLE.'.default_swimlane',
Project::TABLE.'.name AS project_name' Project::TABLE.'.name AS project_name'

View file

@ -4,6 +4,7 @@ namespace Model;
use SimpleValidator\Validator; use SimpleValidator\Validator;
use SimpleValidator\Validators; use SimpleValidator\Validators;
use Event\TaskLinkEvent;
/** /**
* TaskLink model * TaskLink model
@ -21,6 +22,13 @@ class TaskLink extends Base
*/ */
const TABLE = 'task_has_links'; const TABLE = 'task_has_links';
/**
* Events
*
* @var string
*/
const EVENT_CREATE_UPDATE = 'tasklink.create_update';
/** /**
* Get a task link * Get a task link
* *
@ -113,6 +121,20 @@ class TaskLink extends Base
return $result; return $result;
} }
/**
* Publish events
*
* @access private
* @param array $events
*/
private function fireEvents(array $events)
{
foreach ($events as $event) {
$event['project_id'] = $this->taskFinder->getProjectId($event['task_id']);
$this->container['dispatcher']->dispatch(self::EVENT_CREATE_UPDATE, new TaskLinkEvent($event));
}
}
/** /**
* Create a new link * Create a new link
* *
@ -124,29 +146,37 @@ class TaskLink extends Base
*/ */
public function create($task_id, $opposite_task_id, $link_id) public function create($task_id, $opposite_task_id, $link_id)
{ {
$events = array();
$this->db->startTransaction(); $this->db->startTransaction();
// Get opposite link // Get opposite link
$opposite_link_id = $this->link->getOppositeLinkId($link_id); $opposite_link_id = $this->link->getOppositeLinkId($link_id);
// Create the original task link $values = array(
$this->db->table(self::TABLE)->insert(array(
'task_id' => $task_id, 'task_id' => $task_id,
'opposite_task_id' => $opposite_task_id, 'opposite_task_id' => $opposite_task_id,
'link_id' => $link_id, 'link_id' => $link_id,
)); );
// Create the original task link
$this->db->table(self::TABLE)->insert($values);
$task_link_id = $this->db->getLastId(); $task_link_id = $this->db->getLastId();
$events[] = $values;
// Create the opposite task link // Create the opposite task link
$this->db->table(self::TABLE)->insert(array( $values = array(
'task_id' => $opposite_task_id, 'task_id' => $opposite_task_id,
'opposite_task_id' => $task_id, 'opposite_task_id' => $task_id,
'link_id' => $opposite_link_id, 'link_id' => $opposite_link_id,
)); );
$this->db->table(self::TABLE)->insert($values);
$events[] = $values;
$this->db->closeTransaction(); $this->db->closeTransaction();
$this->fireEvents($events);
return (int) $task_link_id; return (int) $task_link_id;
} }
@ -162,6 +192,7 @@ class TaskLink extends Base
*/ */
public function update($task_link_id, $task_id, $opposite_task_id, $link_id) public function update($task_link_id, $task_id, $opposite_task_id, $link_id)
{ {
$events = array();
$this->db->startTransaction(); $this->db->startTransaction();
// Get original task link // Get original task link
@ -174,22 +205,33 @@ class TaskLink extends Base
$opposite_link_id = $this->link->getOppositeLinkId($link_id); $opposite_link_id = $this->link->getOppositeLinkId($link_id);
// Update the original task link // Update the original task link
$rs1 = $this->db->table(self::TABLE)->eq('id', $task_link_id)->update(array( $values = array(
'task_id' => $task_id, 'task_id' => $task_id,
'opposite_task_id' => $opposite_task_id, 'opposite_task_id' => $opposite_task_id,
'link_id' => $link_id, 'link_id' => $link_id,
)); );
$rs1 = $this->db->table(self::TABLE)->eq('id', $task_link_id)->update($values);
$events[] = $values;
// Update the opposite link // Update the opposite link
$rs2 = $this->db->table(self::TABLE)->eq('id', $opposite_task_link['id'])->update(array( $values = array(
'task_id' => $opposite_task_id, 'task_id' => $opposite_task_id,
'opposite_task_id' => $task_id, 'opposite_task_id' => $task_id,
'link_id' => $opposite_link_id, 'link_id' => $opposite_link_id,
)); );
$rs2 = $this->db->table(self::TABLE)->eq('id', $opposite_task_link['id'])->update($values);
$events[] = $values;
$this->db->closeTransaction(); $this->db->closeTransaction();
return $rs1 && $rs2; if ($rs1 && $rs2) {
$this->fireEvents($events);
return true;
}
return false;
} }
/** /**

View file

@ -57,6 +57,7 @@ class User extends Base
'name', 'name',
'email', 'email',
'is_admin', 'is_admin',
'is_project_admin',
'is_ldap_user', 'is_ldap_user',
'notifications_enabled', 'notifications_enabled',
'google_id', 'google_id',
@ -137,6 +138,22 @@ class User extends Base
return $this->db->table(self::TABLE)->eq('github_id', $github_id)->findOne(); return $this->db->table(self::TABLE)->eq('github_id', $github_id)->findOne();
} }
/**
* Get a specific user by the Gitlab id
*
* @access public
* @param string $gitlab_id Gitlab user id
* @return array|boolean
*/
public function getByGitlabId($gitlab_id)
{
if (empty($gitlab_id)) {
return false;
}
return $this->db->table(self::TABLE)->eq('gitlab_id', $gitlab_id)->findOne();
}
/** /**
* Get a specific user by the username * Get a specific user by the username
* *
@ -207,12 +224,19 @@ class User extends Base
* List all users (key-value pairs with id/username) * List all users (key-value pairs with id/username)
* *
* @access public * @access public
* @param boolean $prepend Prepend "All users"
* @return array * @return array
*/ */
public function getList() public function getList($prepend = false)
{ {
$users = $this->db->table(self::TABLE)->columns('id', 'username', 'name')->findAll(); $users = $this->db->table(self::TABLE)->columns('id', 'username', 'name')->findAll();
return $this->prepareList($users); $listing = $this->prepareList($users);
if ($prepend) {
return array(User::EVERYBODY_ID => t('Everybody')) + $listing;
}
return $listing;
} }
/** /**
@ -254,7 +278,7 @@ class User extends Base
} }
$this->removeFields($values, array('confirmation', 'current_password')); $this->removeFields($values, array('confirmation', 'current_password'));
$this->resetFields($values, array('is_admin', 'is_ldap_user')); $this->resetFields($values, array('is_admin', 'is_ldap_user', 'is_project_admin'));
} }
/** /**
@ -364,6 +388,71 @@ class User extends Base
->save(array('token' => '')); ->save(array('token' => ''));
} }
/**
* Get the number of failed login for the user
*
* @access public
* @param string $username
* @return integer
*/
public function getFailedLogin($username)
{
return (int) $this->db->table(self::TABLE)->eq('username', $username)->findOneColumn('nb_failed_login');
}
/**
* Reset to 0 the counter of failed login
*
* @access public
* @param string $username
* @return boolean
*/
public function resetFailedLogin($username)
{
return $this->db->table(self::TABLE)->eq('username', $username)->update(array('nb_failed_login' => 0, 'lock_expiration_date' => 0));
}
/**
* Increment failed login counter
*
* @access public
* @param string $username
* @return boolean
*/
public function incrementFailedLogin($username)
{
return $this->db->execute('UPDATE '.self::TABLE.' SET nb_failed_login=nb_failed_login+1 WHERE username=?', array($username)) !== false;
}
/**
* Check if the account is locked
*
* @access public
* @param string $username
* @return boolean
*/
public function isLocked($username)
{
return $this->db->table(self::TABLE)
->eq('username', $username)
->neq('lock_expiration_date', 0)
->gte('lock_expiration_date', time())
->exists();
}
/**
* Lock the account for the specified duration
*
* @access public
* @param string $username Username
* @param integer $duration Duration in minutes
* @return boolean
*/
public function lock($username, $duration = 15)
{
return $this->db->table(self::TABLE)->eq('username', $username)->update(array('lock_expiration_date' => time() + $duration * 60));
}
/** /**
* Common validation rules * Common validation rules
* *
@ -377,6 +466,7 @@ class User extends Base
new Validators\Unique('username', t('The username must be unique'), $this->db->getConnection(), self::TABLE, 'id'), new Validators\Unique('username', t('The username must be unique'), $this->db->getConnection(), self::TABLE, 'id'),
new Validators\Email('email', t('Email address invalid')), new Validators\Email('email', t('Email address invalid')),
new Validators\Integer('is_admin', t('This value must be an integer')), new Validators\Integer('is_admin', t('This value must be an integer')),
new Validators\Integer('is_project_admin', t('This value must be an integer')),
new Validators\Integer('is_ldap_user', t('This value must be an integer')), new Validators\Integer('is_ldap_user', t('This value must be an integer')),
); );
} }

View file

@ -34,6 +34,7 @@ class UserSession extends Base
$user['id'] = (int) $user['id']; $user['id'] = (int) $user['id'];
$user['is_admin'] = (bool) $user['is_admin']; $user['is_admin'] = (bool) $user['is_admin'];
$user['is_project_admin'] = (bool) $user['is_project_admin'];
$user['is_ldap_user'] = (bool) $user['is_ldap_user']; $user['is_ldap_user'] = (bool) $user['is_ldap_user'];
$user['twofactor_activated'] = (bool) $user['twofactor_activated']; $user['twofactor_activated'] = (bool) $user['twofactor_activated'];
@ -73,6 +74,17 @@ class UserSession extends Base
return isset($this->session['user']['is_admin']) && $this->session['user']['is_admin'] === true; return isset($this->session['user']['is_admin']) && $this->session['user']['is_admin'] === true;
} }
/**
* Return true if the logged user is project admin
*
* @access public
* @return bool
*/
public function isProjectAdmin()
{
return isset($this->session['user']['is_project_admin']) && $this->session['user']['is_project_admin'] === true;
}
/** /**
* Get the connected user id * Get the connected user id
* *

View file

@ -6,7 +6,29 @@ use PDO;
use Core\Security; use Core\Security;
use Model\Link; use Model\Link;
const VERSION = 81; const VERSION = 85;
function version_85($pdo)
{
$pdo->exec("ALTER TABLE users ADD COLUMN gitlab_id INT");
}
function version_84($pdo)
{
$pdo->exec("ALTER TABLE projects ADD COLUMN start_date VARCHAR(10) DEFAULT ''");
$pdo->exec("ALTER TABLE projects ADD COLUMN end_date VARCHAR(10) DEFAULT ''");
}
function version_83($pdo)
{
$pdo->exec("ALTER TABLE users ADD COLUMN is_project_admin INT DEFAULT 0");
}
function version_82($pdo)
{
$pdo->exec("ALTER TABLE users ADD COLUMN nb_failed_login INT DEFAULT 0");
$pdo->exec("ALTER TABLE users ADD COLUMN lock_expiration_date INT DEFAULT 0");
}
function version_81($pdo) function version_81($pdo)
{ {

View file

@ -6,7 +6,29 @@ use PDO;
use Core\Security; use Core\Security;
use Model\Link; use Model\Link;
const VERSION = 61; const VERSION = 65;
function version_65($pdo)
{
$pdo->exec("ALTER TABLE users ADD COLUMN gitlab_id INTEGER");
}
function version_64($pdo)
{
$pdo->exec("ALTER TABLE projects ADD COLUMN start_date VARCHAR(10) DEFAULT ''");
$pdo->exec("ALTER TABLE projects ADD COLUMN end_date VARCHAR(10) DEFAULT ''");
}
function version_63($pdo)
{
$pdo->exec("ALTER TABLE users ADD COLUMN is_project_admin BOOLEAN DEFAULT '0'");
}
function version_62($pdo)
{
$pdo->exec("ALTER TABLE users ADD COLUMN nb_failed_login INTEGER DEFAULT 0");
$pdo->exec("ALTER TABLE users ADD COLUMN lock_expiration_date INTEGER DEFAULT 0");
}
function version_61($pdo) function version_61($pdo)
{ {

View file

@ -6,7 +6,29 @@ use Core\Security;
use PDO; use PDO;
use Model\Link; use Model\Link;
const VERSION = 77; const VERSION = 81;
function version_81($pdo)
{
$pdo->exec("ALTER TABLE users ADD COLUMN gitlab_id INTEGER");
}
function version_80($pdo)
{
$pdo->exec("ALTER TABLE projects ADD COLUMN start_date TEXT DEFAULT ''");
$pdo->exec("ALTER TABLE projects ADD COLUMN end_date TEXT DEFAULT ''");
}
function version_79($pdo)
{
$pdo->exec("ALTER TABLE users ADD COLUMN is_project_admin INTEGER DEFAULT 0");
}
function version_78($pdo)
{
$pdo->exec("ALTER TABLE users ADD COLUMN nb_failed_login INTEGER DEFAULT 0");
$pdo->exec("ALTER TABLE users ADD COLUMN lock_expiration_date INTEGER DEFAULT 0");
}
function version_77($pdo) function version_77($pdo)
{ {

View file

@ -42,6 +42,8 @@
<?= $this->text->in($param['value'], $colors_list) ?> <?= $this->text->in($param['value'], $colors_list) ?>
<?php elseif ($this->text->contains($param['name'], 'category_id')): ?> <?php elseif ($this->text->contains($param['name'], 'category_id')): ?>
<?= $this->text->in($param['value'], $categories_list) ?> <?= $this->text->in($param['value'], $categories_list) ?>
<?php elseif ($this->text->contains($param['name'], 'link_id')): ?>
<?= $this->text->in($param['value'], $links_list) ?>
<?php else: ?> <?php else: ?>
<?= $this->e($param['value']) ?> <?= $this->e($param['value']) ?>
<?php endif ?> <?php endif ?>

View file

@ -28,6 +28,9 @@
<?php elseif ($this->text->contains($param_name, 'category_id')): ?> <?php elseif ($this->text->contains($param_name, 'category_id')): ?>
<?= $this->form->label($param_desc, $param_name) ?> <?= $this->form->label($param_desc, $param_name) ?>
<?= $this->form->select('params['.$param_name.']', $categories_list, $values) ?><br/> <?= $this->form->select('params['.$param_name.']', $categories_list, $values) ?><br/>
<?php elseif ($this->text->contains($param_name, 'link_id')): ?>
<?= $this->form->label($param_desc, $param_name) ?>
<?= $this->form->select('params['.$param_name.']', $links_list, $values) ?><br/>
<?php else: ?> <?php else: ?>
<?= $this->form->label($param_desc, $param_name) ?> <?= $this->form->label($param_desc, $param_name) ?>
<?= $this->form->text('params['.$param_name.']', $values) ?> <?= $this->form->text('params['.$param_name.']', $values) ?>

View file

@ -6,7 +6,7 @@
<p class="alert"><?= t('You need at least 2 days of data to show the chart.') ?></p> <p class="alert"><?= t('You need at least 2 days of data to show the chart.') ?></p>
<?php else: ?> <?php else: ?>
<section id="analytic-cfd"> <section id="analytic-cfd">
<div id="chart" data-metrics='<?= json_encode($metrics) ?>' data-date-format="<?= e('%%Y-%%m-%%d') ?>"></div> <div id="chart" data-metrics='<?= json_encode($metrics, JSON_HEX_APOS) ?>' data-date-format="<?= e('%%Y-%%m-%%d') ?>"></div>
</section> </section>
<?php endif ?> <?php endif ?>

View file

@ -19,7 +19,7 @@
<i class="fa fa-calendar fa-fw"></i> <i class="fa fa-calendar fa-fw"></i>
<?= $this->url->link(t('Back to the calendar'), 'calendar', 'show', array('project_id' => $project['id'])) ?> <?= $this->url->link(t('Back to the calendar'), 'calendar', 'show', array('project_id' => $project['id'])) ?>
</li> </li>
<?php if ($this->user->isManager($project['id'])): ?> <?php if ($this->user->isProjectManagementAllowed($project['id'])): ?>
<li> <li>
<i class="fa fa-cog fa-fw"></i> <i class="fa fa-cog fa-fw"></i>
<?= $this->url->link(t('Project settings'), 'project', 'show', array('project_id' => $project['id'])) ?> <?= $this->url->link(t('Project settings'), 'project', 'show', array('project_id' => $project['id'])) ?>

View file

@ -1,22 +1,22 @@
<div class="sidebar"> <div class="sidebar">
<h2><?= t('Reportings') ?></h2> <h2><?= t('Reportings') ?></h2>
<ul> <ul>
<li> <li <?= $this->app->getRouterAction() === 'tasks' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Task distribution'), 'analytic', 'tasks', array('project_id' => $project['id'])) ?> <?= $this->url->link(t('Task distribution'), 'analytic', 'tasks', array('project_id' => $project['id'])) ?>
</li> </li>
<li> <li <?= $this->app->getRouterAction() === 'users' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('User repartition'), 'analytic', 'users', array('project_id' => $project['id'])) ?> <?= $this->url->link(t('User repartition'), 'analytic', 'users', array('project_id' => $project['id'])) ?>
</li> </li>
<li> <li <?= $this->app->getRouterAction() === 'cfd' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Cumulative flow diagram'), 'analytic', 'cfd', array('project_id' => $project['id'])) ?> <?= $this->url->link(t('Cumulative flow diagram'), 'analytic', 'cfd', array('project_id' => $project['id'])) ?>
</li> </li>
<li> <li <?= $this->app->getRouterAction() === 'burndown' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Burndown chart'), 'analytic', 'burndown', array('project_id' => $project['id'])) ?> <?= $this->url->link(t('Burndown chart'), 'analytic', 'burndown', array('project_id' => $project['id'])) ?>
</li> </li>
<li> <li <?= $this->app->getRouterAction() === 'averagetimebycolumn' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Average time into each column'), 'analytic', 'averageTimeByColumn', array('project_id' => $project['id'])) ?> <?= $this->url->link(t('Average time into each column'), 'analytic', 'averageTimeByColumn', array('project_id' => $project['id'])) ?>
</li> </li>
<li> <li <?= $this->app->getRouterAction() === 'leadandcycletime' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Lead and cycle time'), 'analytic', 'leadAndCycleTime', array('project_id' => $project['id'])) ?> <?= $this->url->link(t('Lead and cycle time'), 'analytic', 'leadAndCycleTime', array('project_id' => $project['id'])) ?>
</li> </li>
</ul> </ul>

View file

@ -7,7 +7,7 @@
<?php else: ?> <?php else: ?>
<section id="analytic-task-repartition"> <section id="analytic-task-repartition">
<div id="chart" data-metrics='<?= json_encode($metrics) ?>'></div> <div id="chart" data-metrics='<?= json_encode($metrics, JSON_HEX_APOS) ?>'></div>
<table> <table>
<tr> <tr>

View file

@ -7,7 +7,7 @@
<?php else: ?> <?php else: ?>
<section id="analytic-user-repartition"> <section id="analytic-user-repartition">
<div id="chart" data-metrics='<?= json_encode($metrics) ?>'></div> <div id="chart" data-metrics='<?= json_encode($metrics, JSON_HEX_APOS) ?>'></div>
<table> <table>
<tr> <tr>

View file

@ -16,7 +16,7 @@
<?= $this->url->link('#'.$project['id'], 'board', 'show', array('project_id' => $project['id']), false, 'dashboard-table-link') ?> <?= $this->url->link('#'.$project['id'], 'board', 'show', array('project_id' => $project['id']), false, 'dashboard-table-link') ?>
</td> </td>
<td> <td>
<?php if ($this->user->isManager($project['id'])): ?> <?php if ($this->user->isProjectManagementAllowed($project['id'])): ?>
<?= $this->url->link('<i class="fa fa-cog"></i>', 'project', 'show', array('project_id' => $project['id']), false, 'dashboard-table-link', t('Settings')) ?>&nbsp; <?= $this->url->link('<i class="fa fa-cog"></i>', 'project', 'show', array('project_id' => $project['id']), false, 'dashboard-table-link', t('Settings')) ?>&nbsp;
<?php endif ?> <?php endif ?>

View file

@ -10,7 +10,7 @@
'changeCategory', 'changeCategory',
array('task_id' => $task['id'], 'project_id' => $task['project_id']), array('task_id' => $task['id'], 'project_id' => $task['project_id']),
false, false,
'task-board-popover' . (! empty($task['category_description']) ? ' tooltip' : ''), 'popover' . (! empty($task['category_description']) ? ' tooltip' : ''),
! empty($task['category_description']) ? $this->text->markdown($task['category_description']) : t('Change category') ! empty($task['category_description']) ? $this->text->markdown($task['category_description']) : t('Change category')
) ?> ) ?>
<?php endif ?> <?php endif ?>
@ -27,31 +27,31 @@
<?php endif ?> <?php endif ?>
<?php if ($task['recurrence_status'] == \Model\Task::RECURRING_STATUS_PENDING): ?> <?php if ($task['recurrence_status'] == \Model\Task::RECURRING_STATUS_PENDING): ?>
<span title="<?= t('Recurrence') ?>" class="task-board-tooltip" data-href="<?= $this->url->href('board', 'recurrence', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><i class="fa fa-refresh fa-rotate-90"></i></span> <span title="<?= t('Recurrence') ?>" class="tooltip" data-href="<?= $this->url->href('board', 'recurrence', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><i class="fa fa-refresh fa-rotate-90"></i></span>
<?php endif ?> <?php endif ?>
<?php if ($task['recurrence_status'] == \Model\Task::RECURRING_STATUS_PROCESSED): ?> <?php if ($task['recurrence_status'] == \Model\Task::RECURRING_STATUS_PROCESSED): ?>
<span title="<?= t('Recurrence') ?>" class="task-board-tooltip" data-href="<?= $this->url->href('board', 'recurrence', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><i class="fa fa-refresh fa-rotate-90 fa-inverse"></i></span> <span title="<?= t('Recurrence') ?>" class="tooltip" data-href="<?= $this->url->href('board', 'recurrence', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><i class="fa fa-refresh fa-rotate-90 fa-inverse"></i></span>
<?php endif ?> <?php endif ?>
<?php if (! empty($task['nb_links'])): ?> <?php if (! empty($task['nb_links'])): ?>
<span title="<?= t('Links') ?>" class="task-board-tooltip" data-href="<?= $this->url->href('board', 'tasklinks', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><i class="fa fa-code-fork"></i>&nbsp;<?= $task['nb_links'] ?></span> <span title="<?= t('Links') ?>" class="tooltip" data-href="<?= $this->url->href('board', 'tasklinks', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><i class="fa fa-code-fork"></i>&nbsp;<?= $task['nb_links'] ?></span>
<?php endif ?> <?php endif ?>
<?php if (! empty($task['nb_subtasks'])): ?> <?php if (! empty($task['nb_subtasks'])): ?>
<span title="<?= t('Sub-Tasks') ?>" class="task-board-tooltip" data-href="<?= $this->url->href('board', 'subtasks', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><i class="fa fa-bars"></i>&nbsp;<?= round($task['nb_completed_subtasks']/$task['nb_subtasks']*100, 0).'%' ?></span> <span title="<?= t('Sub-Tasks') ?>" class="tooltip" data-href="<?= $this->url->href('board', 'subtasks', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><i class="fa fa-bars"></i>&nbsp;<?= round($task['nb_completed_subtasks']/$task['nb_subtasks']*100, 0).'%' ?></span>
<?php endif ?> <?php endif ?>
<?php if (! empty($task['nb_files'])): ?> <?php if (! empty($task['nb_files'])): ?>
<span title="<?= t('Attachments') ?>" class="task-board-tooltip" data-href="<?= $this->url->href('board', 'attachments', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><i class="fa fa-paperclip"></i>&nbsp;<?= $task['nb_files'] ?></span> <span title="<?= t('Attachments') ?>" class="tooltip" data-href="<?= $this->url->href('board', 'attachments', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><i class="fa fa-paperclip"></i>&nbsp;<?= $task['nb_files'] ?></span>
<?php endif ?> <?php endif ?>
<?php if (! empty($task['nb_comments'])): ?> <?php if (! empty($task['nb_comments'])): ?>
<span title="<?= p($task['nb_comments'], t('%d comment', $task['nb_comments']), t('%d comments', $task['nb_comments'])) ?>" class="task-board-tooltip" data-href="<?= $this->url->href('board', 'comments', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><i class="fa fa-comment-o"></i>&nbsp;<?= $task['nb_comments'] ?></span> <span title="<?= p($task['nb_comments'], t('%d comment', $task['nb_comments']), t('%d comments', $task['nb_comments'])) ?>" class="tooltip" data-href="<?= $this->url->href('board', 'comments', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><i class="fa fa-comment-o"></i>&nbsp;<?= $task['nb_comments'] ?></span>
<?php endif ?> <?php endif ?>
<?php if (! empty($task['description'])): ?> <?php if (! empty($task['description'])): ?>
<span title="<?= t('Description') ?>" class="task-board-tooltip" data-href="<?= $this->url->href('board', 'description', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"> <span title="<?= t('Description') ?>" class="tooltip" data-href="<?= $this->url->href('board', 'description', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>">
<i class="fa fa-file-text-o"></i> <i class="fa fa-file-text-o"></i>
</span> </span>
<?php endif ?> <?php endif ?>
@ -63,4 +63,10 @@
<?php if (! empty($task['time_estimated'])): ?> <?php if (! empty($task['time_estimated'])): ?>
<span class="task-time-estimated" title="<?= t('Time estimated') ?>"><?= $this->e($task['time_estimated']).'h' ?></span> <span class="task-time-estimated" title="<?= t('Time estimated') ?>"><?= $this->e($task['time_estimated']).'h' ?></span>
<?php endif ?> <?php endif ?>
<?php if ($task['is_milestone'] == 1): ?>
<span title="<?= t('Milestone') ?>">
<i class="fa fa-flag flag-milestone"></i>
</span>
<?php endif ?>
</div> </div>

View file

@ -1,15 +1,13 @@
<span class="dropdown"> <span class="dropdown">
<span>
<a href="#" class="dropdown-menu"><?= '#'.$task['id'] ?></a> <a href="#" class="dropdown-menu"><?= '#'.$task['id'] ?></a>
<ul> <ul>
<li><i class="fa fa-user"></i> <?= $this->url->link(t('Change assignee'), 'board', 'changeAssignee', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'task-board-popover') ?></li> <li><i class="fa fa-user"></i> <?= $this->url->link(t('Change assignee'), 'board', 'changeAssignee', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?></li>
<li><i class="fa fa-tag"></i> <?= $this->url->link(t('Change category'), 'board', 'changeCategory', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'task-board-popover') ?></li> <li><i class="fa fa-tag"></i> <?= $this->url->link(t('Change category'), 'board', 'changeCategory', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?></li>
<li><i class="fa fa-align-left"></i> <?= $this->url->link(t('Change description'), 'taskmodification', 'description', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'task-board-popover') ?></li> <li><i class="fa fa-align-left"></i> <?= $this->url->link(t('Change description'), 'taskmodification', 'description', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?></li>
<li><i class="fa fa-pencil-square-o"></i> <?= $this->url->link(t('Edit this task'), 'taskmodification', 'edit', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'task-board-popover') ?></li> <li><i class="fa fa-pencil-square-o"></i> <?= $this->url->link(t('Edit this task'), 'taskmodification', 'edit', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?></li>
<li><i class="fa fa-comment-o"></i> <?= $this->url->link(t('Add a comment'), 'comment', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'task-board-popover') ?></li> <li><i class="fa fa-comment-o"></i> <?= $this->url->link(t('Add a comment'), 'comment', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?></li>
<li><i class="fa fa-code-fork"></i> <?= $this->url->link(t('Add a link'), 'tasklink', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'task-board-popover') ?></li> <li><i class="fa fa-code-fork"></i> <?= $this->url->link(t('Add a link'), 'tasklink', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?></li>
<li><i class="fa fa-camera"></i> <?= $this->url->link(t('Add a screenshot'), 'board', 'screenshot', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'task-board-popover') ?></li> <li><i class="fa fa-camera"></i> <?= $this->url->link(t('Add a screenshot'), 'board', 'screenshot', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?></li>
<li><i class="fa fa-close"></i> <?= $this->url->link(t('Close this task'), 'taskstatus', 'close', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'redirect' => 'board'), false, 'task-board-popover') ?></li> <li><i class="fa fa-close"></i> <?= $this->url->link(t('Close this task'), 'taskstatus', 'close', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'redirect' => 'board'), false, 'popover') ?></li>
</ul> </ul>
</span>
</span> </span>

View file

@ -8,6 +8,7 @@
data-due-date="<?= $task['date_due'] ?>" data-due-date="<?= $task['date_due'] ?>"
data-task-url="<?= $this->url->href('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"> data-task-url="<?= $this->url->href('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>">
<div class="task-board-sort-handle" style="display: none;"><i class="fa fa-arrows-alt"></i></div>
<?= $this->render('board/task_menu', array('task' => $task)) ?> <?= $this->render('board/task_menu', array('task' => $task)) ?>
<?php if ($this->board->isCollapsed($project['id'])): ?> <?php if ($this->board->isCollapsed($project['id'])): ?>
@ -17,9 +18,7 @@
<?= $this->e($this->user->getInitials($task['assignee_name'] ?: $task['assignee_username'])) ?> <?= $this->e($this->user->getInitials($task['assignee_name'] ?: $task['assignee_username'])) ?>
</span> - </span> -
<?php endif ?> <?php endif ?>
<span class="tooltip" title="<?= $this->e($task['title']) ?>" <?= $this->url->link($this->e($task['title']), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'task-board-collapsed-title tooltip', $this->e($task['title'])) ?>
<?= $this->url->link($this->e($task['title']), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'task-board-collapsed-title') ?>
</span>
</div> </div>
<?php else: ?> <?php else: ?>
<div class="task-board-expanded"> <div class="task-board-expanded">
@ -37,7 +36,7 @@
'changeAssignee', 'changeAssignee',
array('task_id' => $task['id'], 'project_id' => $task['project_id']), array('task_id' => $task['id'], 'project_id' => $task['project_id']),
false, false,
'task-board-popover', 'popover',
t('Change assignee') t('Change assignee')
) ?> ) ?>
</span> </span>

View file

@ -6,8 +6,8 @@
<div id="budget-chart"> <div id="budget-chart">
<div id="chart" <div id="chart"
data-date-format="<?= e('%%Y-%%m-%%d') ?>" data-date-format="<?= e('%%Y-%%m-%%d') ?>"
data-metrics='<?= json_encode($daily_budget) ?>' data-metrics='<?= json_encode($daily_budget, JSON_HEX_APOS) ?>'
data-labels='<?= json_encode(array('in' => t('Budget line'), 'out' => t('Expenses'), 'left' => t('Remaining'), 'value' => t('Amount'), 'date' => t('Date'), 'type' => t('Type'))) ?>'></div> data-labels='<?= json_encode(array('in' => t('Budget line'), 'out' => t('Expenses'), 'left' => t('Remaining'), 'value' => t('Amount'), 'date' => t('Date'), 'type' => t('Type')), JSON_HEX_APOS) ?>'></div>
</div> </div>
<hr/> <hr/>
<table class="table-fixed table-stripped"> <table class="table-fixed table-stripped">

View file

@ -30,9 +30,11 @@
</li> </li>
</ul> </ul>
</div> </div>
<div class="form-help"><a href="http://kanboard.net/documentation/syntax-guide" target="_blank" rel="noreferrer"><?= t('Write your text in Markdown') ?></a></div> <div class="form-help"><?= $this->url->doc(t('Write your text in Markdown'), 'syntax-guide') ?></div>
<div class="form-actions"> <div class="form-actions">
<input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/> <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/>
<?= t('or') ?>
<?= $this->url->link(t('cancel'), 'category', 'index', array('project_id' => $project['id'])) ?>
</div> </div>
</form> </form>

View file

@ -24,7 +24,7 @@
</div> </div>
</div> </div>
<div class="form-help"><a href="http://kanboard.net/documentation/syntax-guide" target="_blank" rel="noreferrer"><?= t('Write your text in Markdown') ?></a></div> <div class="form-help"><?= $this->url->doc(t('Write your text in Markdown'), 'syntax-guide') ?></div>
<div class="form-actions"> <div class="form-actions">
<input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/> <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/>

View file

@ -26,7 +26,7 @@
</div> </div>
</div> </div>
<div class="form-help"><a href="http://kanboard.net/documentation/syntax-guide" target="_blank" rel="noreferrer"><?= t('Write your text in Markdown') ?></a></div> <div class="form-help"><?= $this->url->doc(t('Write your text in Markdown'), 'syntax-guide') ?></div>
<div class="form-actions"> <div class="form-actions">
<input type="submit" value="<?= t('Update') ?>" class="btn btn-blue"/> <input type="submit" value="<?= t('Update') ?>" class="btn btn-blue"/>

View file

@ -57,6 +57,7 @@
<li><?= t('Switch to the board view') ?> = <strong>v b</strong></li> <li><?= t('Switch to the board view') ?> = <strong>v b</strong></li>
<li><?= t('Switch to the calendar view') ?> = <strong>v c</strong></li> <li><?= t('Switch to the calendar view') ?> = <strong>v c</strong></li>
<li><?= t('Switch to the list view') ?> = <strong>v l</strong></li> <li><?= t('Switch to the list view') ?> = <strong>v l</strong></li>
<li><?= t('Switch to the Gantt chart view') ?> = <strong>v g</strong></li>
</ul> </ul>
<h3><?= t('Board view') ?></h3> <h3><?= t('Board view') ?></h3>
<ul> <ul>
@ -68,6 +69,7 @@
<ul> <ul>
<li><?= t('Open board switcher') ?> = <strong>b</strong></li> <li><?= t('Open board switcher') ?> = <strong>b</strong></li>
<li><?= t('Go to the search/filter box') ?> = <strong>f</strong></li> <li><?= t('Go to the search/filter box') ?> = <strong>f</strong></li>
<li><?= t('Reset the search/filter box') ?> = <strong>r</strong></li>
<li><?= t('Close dialog box') ?> = <strong>ESC</strong></li> <li><?= t('Close dialog box') ?> = <strong>ESC</strong></li>
<li><?= t('Submit a form') ?> = <strong>CTRL+ENTER</strong> <?= t('or') ?> <strong>⌘+ENTER</strong></li> <li><?= t('Submit a form') ?> = <strong>CTRL+ENTER</strong> <?= t('or') ?> <strong>⌘+ENTER</strong></li>
</ul> </ul>

View file

@ -9,31 +9,37 @@
<h3><i class="fa fa-google"></i> <?= t('Google Authentication') ?></h3> <h3><i class="fa fa-google"></i> <?= t('Google Authentication') ?></h3>
<div class="listing"> <div class="listing">
<input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->href('oauth', 'google', array(), false, '', true) ?>"/><br/> <input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->href('oauth', 'google', array(), false, '', true) ?>"/><br/>
<p class="form-help"><a href="http://kanboard.net/documentation/google-authentication" target="_blank"><?= t('Help on Google authentication') ?></a></p> <p class="form-help"><?= $this->url->doc(t('Help on Google authentication'), 'google-authentication') ?></p>
</div> </div>
<h3><i class="fa fa-github"></i> <?= t('Github Authentication') ?></h3> <h3><i class="fa fa-github"></i> <?= t('Github Authentication') ?></h3>
<div class="listing"> <div class="listing">
<input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->href('oauth', 'github', array(), false, '', true) ?>"/><br/> <input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->href('oauth', 'github', array(), false, '', true) ?>"/><br/>
<p class="form-help"><a href="http://kanboard.net/documentation/github-authentication" target="_blank"><?= t('Help on Github authentication') ?></a></p> <p class="form-help"><?= $this->url->doc(t('Help on Github authentication'), 'github-authentication') ?></p>
</div>
<h3><img src="<?= $this->url->dir() ?>assets/img/gitlab-icon.png"/>&nbsp;<?= t('Gitlab Authentication') ?></h3>
<div class="listing">
<input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->href('oauth', 'gitlab', array(), false, '', true) ?>"/><br/>
<p class="form-help"><?= $this->url->doc(t('Help on Gitlab authentication'), 'gitlab-authentication') ?></p>
</div> </div>
<h3><img src="<?= $this->url->dir() ?>assets/img/mailgun-icon.png"/>&nbsp;<?= t('Mailgun (incoming emails)') ?></h3> <h3><img src="<?= $this->url->dir() ?>assets/img/mailgun-icon.png"/>&nbsp;<?= t('Mailgun (incoming emails)') ?></h3>
<div class="listing"> <div class="listing">
<input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->href('webhook', 'mailgun', array('token' => $values['webhook_token']), false, '', true) ?>"/><br/> <input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->href('webhook', 'mailgun', array('token' => $values['webhook_token']), false, '', true) ?>"/><br/>
<p class="form-help"><a href="http://kanboard.net/documentation/mailgun" target="_blank"><?= t('Help on Mailgun integration') ?></a></p> <p class="form-help"><?= $this->url->doc(t('Help on Mailgun integration'), 'mailgun') ?></p>
</div> </div>
<h3><img src="<?= $this->url->dir() ?>assets/img/sendgrid-icon.png"/>&nbsp;<?= t('Sendgrid (incoming emails)') ?></h3> <h3><img src="<?= $this->url->dir() ?>assets/img/sendgrid-icon.png"/>&nbsp;<?= t('Sendgrid (incoming emails)') ?></h3>
<div class="listing"> <div class="listing">
<input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->href('webhook', 'sendgrid', array('token' => $values['webhook_token']), false, '', true) ?>"/><br/> <input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->href('webhook', 'sendgrid', array('token' => $values['webhook_token']), false, '', true) ?>"/><br/>
<p class="form-help"><a href="http://kanboard.net/documentation/sendgrid" target="_blank"><?= t('Help on Sendgrid integration') ?></a></p> <p class="form-help"><?= $this->url->doc(t('Help on Sendgrid integration'), 'sendgrid') ?></p>
</div> </div>
<h3><img src="<?= $this->url->dir() ?>assets/img/postmark-icon.png"/>&nbsp;<?= t('Postmark (incoming emails)') ?></h3> <h3><img src="<?= $this->url->dir() ?>assets/img/postmark-icon.png"/>&nbsp;<?= t('Postmark (incoming emails)') ?></h3>
<div class="listing"> <div class="listing">
<input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->href('webhook', 'postmark', array('token' => $values['webhook_token']), false, '', true) ?>"/><br/> <input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->href('webhook', 'postmark', array('token' => $values['webhook_token']), false, '', true) ?>"/><br/>
<p class="form-help"><a href="http://kanboard.net/documentation/postmark" target="_blank"><?= t('Help on Postmark integration') ?></a></p> <p class="form-help"><?= $this->url->doc(t('Help on Postmark integration'), 'postmark') ?></p>
</div> </div>
<h3><img src="<?= $this->url->dir() ?>assets/img/gravatar-icon.png"/>&nbsp;<?= t('Gravatar') ?></h3> <h3><img src="<?= $this->url->dir() ?>assets/img/gravatar-icon.png"/>&nbsp;<?= t('Gravatar') ?></h3>
@ -64,7 +70,7 @@
<?= $this->form->label(t('Multi-user chat room'), 'integration_jabber_room') ?> <?= $this->form->label(t('Multi-user chat room'), 'integration_jabber_room') ?>
<?= $this->form->text('integration_jabber_room', $values, $errors, array('placeholder="myroom@conference.example.com"')) ?> <?= $this->form->text('integration_jabber_room', $values, $errors, array('placeholder="myroom@conference.example.com"')) ?>
<p class="form-help"><a href="http://kanboard.net/documentation/jabber" target="_blank"><?= t('Help on Jabber integration') ?></a></p> <p class="form-help"><?= $this->url->doc(t('Help on Jabber integration'), 'jabber') ?></p>
</div> </div>
<h3><img src="<?= $this->url->dir() ?>assets/img/hipchat-icon.png"/> <?= t('Hipchat') ?></h3> <h3><img src="<?= $this->url->dir() ?>assets/img/hipchat-icon.png"/> <?= t('Hipchat') ?></h3>
@ -80,7 +86,7 @@
<?= $this->form->label(t('Room notification token'), 'integration_hipchat_room_token') ?> <?= $this->form->label(t('Room notification token'), 'integration_hipchat_room_token') ?>
<?= $this->form->text('integration_hipchat_room_token', $values, $errors) ?> <?= $this->form->text('integration_hipchat_room_token', $values, $errors) ?>
<p class="form-help"><a href="http://kanboard.net/documentation/hipchat" target="_blank"><?= t('Help on Hipchat integration') ?></a></p> <p class="form-help"><?= $this->url->doc(t('Help on Hipchat integration'), 'hipchat') ?></p>
</div> </div>
<h3><i class="fa fa-slack fa-fw"></i>&nbsp;<?= t('Slack') ?></h3> <h3><i class="fa fa-slack fa-fw"></i>&nbsp;<?= t('Slack') ?></h3>
@ -92,7 +98,7 @@
<?= $this->form->label(t('Channel/Group/User (Optional)'), 'integration_slack_webhook_channel') ?> <?= $this->form->label(t('Channel/Group/User (Optional)'), 'integration_slack_webhook_channel') ?>
<?= $this->form->text('integration_slack_webhook_channel', $values, $errors) ?> <?= $this->form->text('integration_slack_webhook_channel', $values, $errors) ?>
<p class="form-help"><a href="http://kanboard.net/documentation/slack" target="_blank"><?= t('Help on Slack integration') ?></a></p> <p class="form-help"><?= $this->url->doc(t('Help on Slack integration'), 'slack') ?></p>
</div> </div>
<div class="form-actions"> <div class="form-actions">

View file

@ -1,36 +1,39 @@
<div class="sidebar"> <div class="sidebar">
<h2><?= t('Actions') ?></h2> <h2><?= t('Actions') ?></h2>
<ul> <ul>
<li> <li <?= $this->app->getRouterAction() === 'index' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('About'), 'config', 'index') ?> <?= $this->url->link(t('About'), 'config', 'index') ?>
</li> </li>
<li> <li <?= $this->app->getRouterAction() === 'application' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Application settings'), 'config', 'application') ?> <?= $this->url->link(t('Application settings'), 'config', 'application') ?>
</li> </li>
<li> <li <?= $this->app->getRouterAction() === 'project' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Project settings'), 'config', 'project') ?> <?= $this->url->link(t('Project settings'), 'config', 'project') ?>
</li> </li>
<li> <li <?= $this->app->getRouterAction() === 'board' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Board settings'), 'config', 'board') ?> <?= $this->url->link(t('Board settings'), 'config', 'board') ?>
</li> </li>
<li> <li <?= $this->app->getRouterAction() === 'calendar' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Calendar settings'), 'config', 'calendar') ?> <?= $this->url->link(t('Calendar settings'), 'config', 'calendar') ?>
</li> </li>
<li> <li <?= $this->app->getRouterController() === 'link' && $this->app->getRouterAction() === 'index' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Link settings'), 'link', 'index') ?> <?= $this->url->link(t('Link settings'), 'link', 'index') ?>
</li> </li>
<li> <li <?= $this->app->getRouterController() === 'currency' && $this->app->getRouterAction() === 'index' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Currency rates'), 'currency', 'index') ?> <?= $this->url->link(t('Currency rates'), 'currency', 'index') ?>
</li> </li>
<li> <li <?= $this->app->getRouterAction() === 'integrations' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Integrations'), 'config', 'integrations') ?> <?= $this->url->link(t('Integrations'), 'config', 'integrations') ?>
</li> </li>
<li> <li <?= $this->app->getRouterAction() === 'webhook' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Webhooks'), 'config', 'webhook') ?> <?= $this->url->link(t('Webhooks'), 'config', 'webhook') ?>
</li> </li>
<li> <li <?= $this->app->getRouterAction() === 'api' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('API'), 'config', 'api') ?> <?= $this->url->link(t('API'), 'config', 'api') ?>
</li> </li>
<li>
<?= $this->url->link(t('Documentation'), 'doc', 'show') ?>
</li>
</ul> </ul>
<div class="sidebar-collapse"><a href="#" title="<?= t('Hide sidebar') ?>"><i class="fa fa-chevron-left"></i></a></div> <div class="sidebar-collapse"><a href="#" title="<?= t('Hide sidebar') ?>"><i class="fa fa-chevron-left"></i></a></div>
<div class="sidebar-expand" style="display: none"><a href="#" title="<?= t('Expand sidebar') ?>"><i class="fa fa-chevron-right"></i></a></div> <div class="sidebar-expand" style="display: none"><a href="#" title="<?= t('Expand sidebar') ?>"><i class="fa fa-chevron-right"></i></a></div>

View file

@ -21,7 +21,7 @@
</span> </span>
</p> </p>
<span class="task-show-file-actions task-show-image-actions"> <span class="task-show-file-actions task-show-image-actions">
<i class="fa fa-eye"></i> <?= $this->url->link(t('open'), 'file', 'open', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id']), false, 'popover') ?> <i class="fa fa-eye"></i> <?= $this->url->link(t('open file'), 'file', 'open', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id']), false, 'popover') ?>
<i class="fa fa-trash"></i> <?= $this->url->link(t('remove'), 'file', 'confirm', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id'])) ?> <i class="fa fa-trash"></i> <?= $this->url->link(t('remove'), 'file', 'confirm', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id'])) ?>
<i class="fa fa-download"></i> <?= $this->url->link(t('download'), 'file', 'download', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id'])) ?> <i class="fa fa-download"></i> <?= $this->url->link(t('download'), 'file', 'download', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id'])) ?>
</span> </span>

View file

@ -6,13 +6,14 @@
<meta name="mobile-web-app-capable" content="yes"> <meta name="mobile-web-app-capable" content="yes">
<meta name="robots" content="noindex,nofollow"> <meta name="robots" content="noindex,nofollow">
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="referrer" content="no-referrer">
<?php if (isset($board_public_refresh_interval)): ?> <?php if (isset($board_public_refresh_interval)): ?>
<meta http-equiv="refresh" content="<?= $board_public_refresh_interval ?>"> <meta http-equiv="refresh" content="<?= $board_public_refresh_interval ?>">
<?php endif ?> <?php endif ?>
<?php if (! isset($not_editable)): ?> <?php if (! isset($not_editable)): ?>
<?= $this->asset->js('assets/js/app.js', true) ?> <?= $this->asset->js('assets/js/app.js') ?>
<?php endif ?> <?php endif ?>
<?= $this->asset->colorCss() ?> <?= $this->asset->colorCss() ?>
@ -48,7 +49,13 @@
<ul> <ul>
<?php if (isset($board_selector) && ! empty($board_selector)): ?> <?php if (isset($board_selector) && ! empty($board_selector)): ?>
<li> <li>
<select id="board-selector" tabindex="-1" data-notfound="<?= t('No results match:') ?>" data-placeholder="<?= t('Display another project') ?>" data-board-url="<?= $this->url->href('board', 'show', array('project_id' => 'PROJECT_ID')) ?>"> <select id="board-selector"
class="chosen-select select-auto-redirect"
tabindex="-1"
data-notfound="<?= t('No results match:') ?>"
data-placeholder="<?= t('Display another project') ?>"
data-redirect-regex="PROJECT_ID"
data-redirect-url="<?= $this->url->href('board', 'show', array('project_id' => 'PROJECT_ID')) ?>">
<option value=""></option> <option value=""></option>
<?php foreach($board_selector as $board_id => $board_name): ?> <?php foreach($board_selector as $board_id => $board_name): ?>
<option value="<?= $board_id ?>"><?= $this->e($board_name) ?></option> <option value="<?= $board_id ?>"><?= $this->e($board_name) ?></option>

View file

@ -13,7 +13,13 @@
<?= $this->form->text('identifier', $values, $errors, array('maxlength="50"')) ?> <?= $this->form->text('identifier', $values, $errors, array('maxlength="50"')) ?>
<p class="form-help"><?= t('The project identifier is an optional alphanumeric code used to identify your project.') ?></p> <p class="form-help"><?= t('The project identifier is an optional alphanumeric code used to identify your project.') ?></p>
<?php if ($this->user->isAdmin()): ?> <?= $this->form->label(t('Start date'), 'start_date') ?>
<?= $this->form->text('start_date', $values, $errors, array('maxlength="10"'), 'form-date') ?>
<?= $this->form->label(t('End date'), 'end_date') ?>
<?= $this->form->text('end_date', $values, $errors, array('maxlength="10"'), 'form-date') ?>
<?php if ($this->user->isAdmin() || $this->user->isProjectAdministrationAllowed($project['id'])): ?>
<?= $this->form->checkbox('is_private', t('Private project'), 1, $project['is_private'] == 1) ?> <?= $this->form->checkbox('is_private', t('Private project'), 1, $project['is_private'] == 1) ?>
<?php endif ?> <?php endif ?>
@ -36,7 +42,7 @@
</li> </li>
</ul> </ul>
</div> </div>
<div class="form-help"><a href="http://kanboard.net/documentation/syntax-guide" target="_blank" rel="noreferrer"><?= t('Write your text in Markdown') ?></a></div> <div class="form-help"><?= $this->url->doc(t('Write your text in Markdown'), 'syntax-guide') ?></div>
<div class="form-actions"> <div class="form-actions">
<input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/> <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/>

View file

@ -1,22 +1,31 @@
<section id="main"> <section id="main">
<div class="page-header"> <div class="page-header">
<ul> <ul>
<?php if ($this->user->isAdmin()): ?> <?php if ($this->user->isProjectAdmin() || $this->user->isAdmin()): ?>
<li><i class="fa fa-plus fa-fw"></i><?= $this->url->link(t('New project'), 'project', 'create') ?></li> <li><i class="fa fa-plus fa-fw"></i><?= $this->url->link(t('New project'), 'project', 'create') ?></li>
<?php endif ?> <?php endif ?>
<li><i class="fa fa-lock fa-fw"></i><?= $this->url->link(t('New private project'), 'project', 'create', array('private' => 1)) ?></li> <li><i class="fa fa-lock fa-fw"></i><?= $this->url->link(t('New private project'), 'project', 'create', array('private' => 1)) ?></li>
<?php if ($this->user->isProjectAdmin() || $this->user->isAdmin()): ?>
<li><i class="fa fa-user fa-fw"></i><?= $this->url->link(t('Users overview'), 'projectuser', 'managers') ?></li>
<li><i class="fa fa-sliders fa-fw"></i><?= $this->url->link(t('Projects Gantt chart'), 'gantt', 'projects') ?></li>
<?php endif ?>
</ul> </ul>
</div> </div>
<section> <section>
<?php if ($paginator->isEmpty()): ?> <?php if ($paginator->isEmpty()): ?>
<p class="alert"><?= t('No project') ?></p> <p class="alert"><?= t('No project') ?></p>
<?php else: ?> <?php else: ?>
<table class="table-fixed"> <table class="table-stripped table-small">
<tr> <tr>
<th class="column-8"><?= $paginator->order(t('Id'), 'id') ?></th> <th class="column-3"><?= $paginator->order(t('Id'), 'id') ?></th>
<th class="column-8"><?= $paginator->order(t('Status'), 'is_active') ?></th> <th class="column-5"><?= $paginator->order(t('Status'), 'is_active') ?></th>
<th class="column-8"><?= $paginator->order(t('Identifier'), 'identifier') ?></th> <th class="column-15"><?= $paginator->order(t('Project'), 'name') ?></th>
<th class="column-20"><?= $paginator->order(t('Project'), 'name') ?></th> <th class="column-8"><?= $paginator->order(t('Start date'), 'start_date') ?></th>
<th class="column-8"><?= $paginator->order(t('End date'), 'end_date') ?></th>
<?php if ($this->user->isAdmin() || $this->user->isProjectAdmin()): ?>
<th class="column-12"><?= t('Managers') ?></th>
<th class="column-12"><?= t('Members') ?></th>
<?php endif ?>
<th><?= t('Columns') ?></th> <th><?= t('Columns') ?></th>
</tr> </tr>
<?php foreach ($paginator->getCollection() as $project): ?> <?php foreach ($paginator->getCollection() as $project): ?>
@ -32,25 +41,50 @@
<?php endif ?> <?php endif ?>
</td> </td>
<td> <td>
<?= $this->e($project['identifier']) ?> <?= $this->url->link('<i class="fa fa-th"></i>', 'board', 'show', array('project_id' => $project['id']), false, 'dashboard-table-link', t('Board')) ?>
</td> <?= $this->url->link('<i class="fa fa-sliders fa-fw"></i>', 'gantt', 'project', array('project_id' => $project['id']), false, 'dashboard-table-link', t('Gantt chart')) ?>
<td>
<?= $this->url->link('<i class="fa fa-th"></i>', 'board', 'show', array('project_id' => $project['id']), false, 'dashboard-table-link', t('Board')) ?>&nbsp;
<?php if ($project['is_public']): ?> <?php if ($project['is_public']): ?>
<i class="fa fa-share-alt fa-fw"></i> <i class="fa fa-share-alt fa-fw" title="<?= t('Shared project') ?>"></i>
<?php endif ?> <?php endif ?>
<?php if ($project['is_private']): ?> <?php if ($project['is_private']): ?>
<i class="fa fa-lock fa-fw"></i> <i class="fa fa-lock fa-fw" title="<?= t('Private project') ?>"></i>
<?php endif ?> <?php endif ?>
<?= $this->url->link($this->e($project['name']), 'project', 'show', array('project_id' => $project['id'])) ?>
<?php if (! empty($project['description'])): ?> <?php if (! empty($project['description'])): ?>
<span class="tooltip" title='<?= $this->e($this->text->markdown($project['description'])) ?>'> <span class="tooltip" title='<?= $this->e($this->text->markdown($project['description'])) ?>'>
<i class="fa fa-info-circle"></i> <i class="fa fa-info-circle"></i>
</span> </span>
<?php endif ?> <?php endif ?>
<?= $this->url->link($this->e($project['name']), 'project', 'show', array('project_id' => $project['id'])) ?>
</td> </td>
<td>
<?= $project['start_date'] ?>
</td>
<td>
<?= $project['end_date'] ?>
</td>
<?php if ($this->user->isAdmin() || $this->user->isProjectAdmin()): ?>
<td>
<ul class="no-bullet">
<?php foreach ($project['managers'] as $user_id => $user_name): ?>
<li><?= $this->url->link($this->e($user_name), 'projectuser', 'opens', array('user_id' => $user_id)) ?></li>
<?php endforeach ?>
</ul>
</td>
<td>
<?php if ($project['is_everybody_allowed'] == 1): ?>
<?= t('Everybody') ?>
<?php else: ?>
<ul class="no-bullet">
<?php foreach ($project['members'] as $user_id => $user_name): ?>
<li><?= $this->url->link($this->e($user_name), 'projectuser', 'opens', array('user_id' => $user_id)) ?></li>
<?php endforeach ?>
</ul>
<?php endif ?>
</td>
<?php endif ?>
<td class="dashboard-project-stats"> <td class="dashboard-project-stats">
<?php foreach ($project['columns'] as $column): ?> <?php foreach ($project['columns'] as $column): ?>
<strong title="<?= t('Task count') ?>"><?= $column['nb_tasks'] ?></strong> <strong title="<?= t('Task count') ?>"><?= $column['nb_tasks'] ?></strong>

View file

@ -9,21 +9,21 @@
<h3><i class="fa fa-github fa-fw"></i>&nbsp;<?= t('Github webhooks') ?></h3> <h3><i class="fa fa-github fa-fw"></i>&nbsp;<?= t('Github webhooks') ?></h3>
<div class="listing"> <div class="listing">
<input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->href('webhook', 'github', array('token' => $webhook_token, 'project_id' => $project['id']), false, '', true) ?>"/><br/> <input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->href('webhook', 'github', array('token' => $webhook_token, 'project_id' => $project['id']), false, '', true) ?>"/><br/>
<p class="form-help"><a href="http://kanboard.net/documentation/github-webhooks" target="_blank"><?= t('Help on Github webhooks') ?></a></p> <p class="form-help"><?= $this->url->doc(t('Help on Github webhooks'), 'github-webhooks') ?></p>
</div> </div>
<h3><img src="<?= $this->url->dir() ?>assets/img/gitlab-icon.png"/>&nbsp;<?= t('Gitlab webhooks') ?></h3> <h3><img src="<?= $this->url->dir() ?>assets/img/gitlab-icon.png"/>&nbsp;<?= t('Gitlab webhooks') ?></h3>
<div class="listing"> <div class="listing">
<input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->href('webhook', 'gitlab', array('token' => $webhook_token, 'project_id' => $project['id']), false, '', true) ?>"/><br/> <input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->href('webhook', 'gitlab', array('token' => $webhook_token, 'project_id' => $project['id']), false, '', true) ?>"/><br/>
<p class="form-help"><a href="http://kanboard.net/documentation/gitlab-webhooks" target="_blank"><?= t('Help on Gitlab webhooks') ?></a></p> <p class="form-help"><?= $this->url->doc(t('Help on Gitlab webhooks'), 'gitlab-webhooks') ?></p>
</div> </div>
<h3><i class="fa fa-bitbucket fa-fw"></i>&nbsp;<?= t('Bitbucket webhooks') ?></h3> <h3><i class="fa fa-bitbucket fa-fw"></i>&nbsp;<?= t('Bitbucket webhooks') ?></h3>
<div class="listing"> <div class="listing">
<input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->href('webhook', 'bitbucket', array('token' => $webhook_token, 'project_id' => $project['id']), false, '', true) ?>"/><br/> <input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->href('webhook', 'bitbucket', array('token' => $webhook_token, 'project_id' => $project['id']), false, '', true) ?>"/><br/>
<p class="form-help"><a href="http://kanboard.net/documentation/bitbucket-webhooks" target="_blank"><?= t('Help on Bitbucket webhooks') ?></a></p> <p class="form-help"><?= $this->url->doc(t('Help on Bitbucket webhooks'), 'bitbucket-webhooks') ?></p>
</div> </div>
@ -50,7 +50,7 @@
<?= $this->form->label(t('Multi-user chat room'), 'jabber_room') ?> <?= $this->form->label(t('Multi-user chat room'), 'jabber_room') ?>
<?= $this->form->text('jabber_room', $values, $errors, array('placeholder="myroom@conference.example.com"')) ?> <?= $this->form->text('jabber_room', $values, $errors, array('placeholder="myroom@conference.example.com"')) ?>
<p class="form-help"><a href="http://kanboard.net/documentation/jabber" target="_blank"><?= t('Help on Jabber integration') ?></a></p> <p class="form-help"><?= $this->url->doc(t('Help on Jabber integration'), 'jabber') ?></p>
<div class="form-actions"> <div class="form-actions">
<input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/> <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/>
@ -71,7 +71,7 @@
<?= $this->form->label(t('Room notification token'), 'hipchat_room_token') ?> <?= $this->form->label(t('Room notification token'), 'hipchat_room_token') ?>
<?= $this->form->text('hipchat_room_token', $values, $errors) ?> <?= $this->form->text('hipchat_room_token', $values, $errors) ?>
<p class="form-help"><a href="http://kanboard.net/documentation/hipchat" target="_blank"><?= t('Help on Hipchat integration') ?></a></p> <p class="form-help"><?= $this->url->doc(t('Help on Hipchat integration'), 'hipchat') ?></a></p>
<div class="form-actions"> <div class="form-actions">
<input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/> <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/>
@ -88,7 +88,7 @@
<?= $this->form->label(t('Channel/Group/User (Optional)'), 'slack_webhook_channel') ?> <?= $this->form->label(t('Channel/Group/User (Optional)'), 'slack_webhook_channel') ?>
<?= $this->form->text('slack_webhook_channel', $values, $errors) ?> <?= $this->form->text('slack_webhook_channel', $values, $errors) ?>
<p class="form-help"><a href="http://kanboard.net/documentation/slack" target="_blank"><?= t('Help on Slack integration') ?></a></p> <p class="form-help"><?= $this->url->doc(t('Help on Slack integration'), 'slack') ?></p>
<div class="form-actions"> <div class="form-actions">
<input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/> <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/>

View file

@ -20,14 +20,22 @@
<li><?= dt('Last modified on %B %e, %Y at %k:%M %p', $project['last_modified']) ?></li> <li><?= dt('Last modified on %B %e, %Y at %k:%M %p', $project['last_modified']) ?></li>
<?php endif ?> <?php endif ?>
<?php if ($project['start_date']): ?>
<li><?= t('Start date: %s', $project['start_date']) ?></li>
<?php endif ?>
<?php if ($project['end_date']): ?>
<li><?= t('End date: %s', $project['end_date']) ?></li>
<?php endif ?>
<?php if ($stats['nb_tasks'] > 0): ?> <?php if ($stats['nb_tasks'] > 0): ?>
<?php if ($stats['nb_active_tasks'] > 0): ?> <?php if ($stats['nb_active_tasks'] > 0): ?>
<li><?= $this->url->link(t('%d tasks on the board', $stats['nb_active_tasks']), 'board', 'show', array('project_id' => $project['id'])) ?></li> <li><?= $this->url->link(t('%d tasks on the board', $stats['nb_active_tasks']), 'board', 'show', array('project_id' => $project['id'], 'search' => 'status:open')) ?></li>
<?php endif ?> <?php endif ?>
<?php if ($stats['nb_inactive_tasks'] > 0): ?> <?php if ($stats['nb_inactive_tasks'] > 0): ?>
<li><?= $this->url->link(t('%d closed tasks', $stats['nb_inactive_tasks']), 'project', 'tasks', array('project_id' => $project['id'])) ?></li> <li><?= $this->url->link(t('%d closed tasks', $stats['nb_inactive_tasks']), 'listing', 'show', array('project_id' => $project['id'], 'search' => 'status:closed')) ?></li>
<?php endif ?> <?php endif ?>
<li><?= t('%d tasks in total', $stats['nb_tasks']) ?></li> <li><?= t('%d tasks in total', $stats['nb_tasks']) ?></li>

View file

@ -1,49 +1,49 @@
<div class="sidebar"> <div class="sidebar">
<h2><?= t('Actions') ?></h2> <h2><?= t('Actions') ?></h2>
<ul> <ul>
<li> <li <?= $this->app->getRouterAction() === 'show' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Summary'), 'project', 'show', array('project_id' => $project['id'])) ?> <?= $this->url->link(t('Summary'), 'project', 'show', array('project_id' => $project['id'])) ?>
</li> </li>
<?php if ($this->user->isManager($project['id'])): ?> <?php if ($this->user->isProjectManagementAllowed($project['id'])): ?>
<li> <li <?= $this->app->getRouterController() === 'project' && $this->app->getRouterAction() === 'share' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Public access'), 'project', 'share', array('project_id' => $project['id'])) ?> <?= $this->url->link(t('Public access'), 'project', 'share', array('project_id' => $project['id'])) ?>
</li> </li>
<li> <li <?= $this->app->getRouterController() === 'project' && $this->app->getRouterAction() === 'integration' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Integrations'), 'project', 'integration', array('project_id' => $project['id'])) ?> <?= $this->url->link(t('Integrations'), 'project', 'integration', array('project_id' => $project['id'])) ?>
</li> </li>
<li> <li <?= $this->app->getRouterController() === 'project' && $this->app->getRouterAction() === 'edit' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Edit project'), 'project', 'edit', array('project_id' => $project['id'])) ?> <?= $this->url->link(t('Edit project'), 'project', 'edit', array('project_id' => $project['id'])) ?>
</li> </li>
<li> <li <?= $this->app->getRouterController() === 'column' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Columns'), 'column', 'index', array('project_id' => $project['id'])) ?> <?= $this->url->link(t('Columns'), 'column', 'index', array('project_id' => $project['id'])) ?>
</li> </li>
<li> <li <?= $this->app->getRouterController() === 'swimlane' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Swimlanes'), 'swimlane', 'index', array('project_id' => $project['id'])) ?> <?= $this->url->link(t('Swimlanes'), 'swimlane', 'index', array('project_id' => $project['id'])) ?>
</li> </li>
<li> <li <?= $this->app->getRouterController() === 'category' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Categories'), 'category', 'index', array('project_id' => $project['id'])) ?> <?= $this->url->link(t('Categories'), 'category', 'index', array('project_id' => $project['id'])) ?>
</li> </li>
<?php if ($this->user->isAdmin() || $project['is_private'] == 0): ?> <?php if ($this->user->isAdmin() || $project['is_private'] == 0): ?>
<li> <li <?= $this->app->getRouterController() === 'project' && $this->app->getRouterAction() === 'users' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Users'), 'project', 'users', array('project_id' => $project['id'])) ?> <?= $this->url->link(t('Users'), 'project', 'users', array('project_id' => $project['id'])) ?>
</li> </li>
<?php endif ?> <?php endif ?>
<li> <li <?= $this->app->getRouterController() === 'action' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Automatic actions'), 'action', 'index', array('project_id' => $project['id'])) ?> <?= $this->url->link(t('Automatic actions'), 'action', 'index', array('project_id' => $project['id'])) ?>
</li> </li>
<li> <li <?= $this->app->getRouterController() === 'project' && $this->app->getRouterAction() === 'duplicate' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Duplicate'), 'project', 'duplicate', array('project_id' => $project['id'])) ?> <?= $this->url->link(t('Duplicate'), 'project', 'duplicate', array('project_id' => $project['id'])) ?>
</li> </li>
<li> <li <?= $this->app->getRouterController() === 'project' && ($this->app->getRouterAction() === 'disable' || $this->app->getRouterAction() === 'enable') ? 'class="active"' : '' ?>>
<?php if ($project['is_active']): ?> <?php if ($project['is_active']): ?>
<?= $this->url->link(t('Disable'), 'project', 'disable', array('project_id' => $project['id']), true) ?> <?= $this->url->link(t('Disable'), 'project', 'disable', array('project_id' => $project['id']), true) ?>
<?php else: ?> <?php else: ?>
<?= $this->url->link(t('Enable'), 'project', 'enable', array('project_id' => $project['id']), true) ?> <?= $this->url->link(t('Enable'), 'project', 'enable', array('project_id' => $project['id']), true) ?>
<?php endif ?> <?php endif ?>
</li> </li>
<?php if ($this->user->isAdmin()): ?> <?php if ($this->user->isProjectAdministrationAllowed($project['id'])): ?>
<li> <li <?= $this->app->getRouterController() === 'project' && $this->app->getRouterAction() === 'remove' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Remove'), 'project', 'remove', array('project_id' => $project['id'])) ?> <?= $this->url->link(t('Remove'), 'project', 'remove', array('project_id' => $project['id'])) ?>
</li> </li>
<?php endif ?> <?php endif ?>

View file

@ -77,5 +77,6 @@
<ul> <ul>
<li><?= t('A project manager can change the settings of the project and have more privileges than a standard user.') ?></li> <li><?= t('A project manager can change the settings of the project and have more privileges than a standard user.') ?></li>
<li><?= t('Don\'t forget that administrators have access to everything.') ?></li> <li><?= t('Don\'t forget that administrators have access to everything.') ?></li>
<li><?= $this->url->doc(t('Help with project permissions'), 'project-permissions') ?></li>
</ul> </ul>
</div> </div>

View file

@ -14,5 +14,7 @@
<div class="form-actions"> <div class="form-actions">
<input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/> <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/>
<?= t('or') ?>
<?= $this->url->link(t('cancel'), 'swimlane', 'index', array('project_id' => $project['id'])) ?>
</div> </div>
</form> </form>

View file

@ -9,7 +9,7 @@
<i class="fa fa-calendar fa-fw"></i> <i class="fa fa-calendar fa-fw"></i>
<?= $this->url->link(t('Back to the calendar'), 'calendar', 'show', array('project_id' => $task['project_id'])) ?> <?= $this->url->link(t('Back to the calendar'), 'calendar', 'show', array('project_id' => $task['project_id'])) ?>
</li> </li>
<?php if ($this->user->isManager($task['project_id'])): ?> <?php if ($this->user->isProjectManagementAllowed($task['project_id'])): ?>
<li> <li>
<i class="fa fa-cog fa-fw"></i> <i class="fa fa-cog fa-fw"></i>
<?= $this->url->link(t('Project settings'), 'project', 'show', array('project_id' => $task['project_id'])) ?> <?= $this->url->link(t('Project settings'), 'project', 'show', array('project_id' => $task['project_id'])) ?>

View file

@ -1,60 +1,60 @@
<div class="sidebar"> <div class="sidebar">
<h2><?= t('Information') ?></h2> <h2><?= t('Information') ?></h2>
<ul> <ul>
<li> <li <?= $this->app->getRouterController() === 'task' && $this->app->getRouterAction() === 'show' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Summary'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> <?= $this->url->link(t('Summary'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li> </li>
<li> <li <?= $this->app->getRouterController() === 'activity' && $this->app->getRouterAction() === 'task' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Activity stream'), 'activity', 'task', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> <?= $this->url->link(t('Activity stream'), 'activity', 'task', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li> </li>
<li> <li <?= $this->app->getRouterController() === 'task' && $this->app->getRouterAction() === 'transitions' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Transitions'), 'task', 'transitions', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> <?= $this->url->link(t('Transitions'), 'task', 'transitions', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li> </li>
<li> <li <?= $this->app->getRouterController() === 'task' && $this->app->getRouterAction() === 'analytics' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Analytics'), 'task', 'analytics', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> <?= $this->url->link(t('Analytics'), 'task', 'analytics', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li> </li>
<?php if ($task['time_estimated'] > 0 || $task['time_spent'] > 0): ?> <?php if ($task['time_estimated'] > 0 || $task['time_spent'] > 0): ?>
<li> <li <?= $this->app->getRouterController() === 'task' && $this->app->getRouterAction() === 'timetracking' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Time tracking'), 'task', 'timetracking', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> <?= $this->url->link(t('Time tracking'), 'task', 'timetracking', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li> </li>
<?php endif ?> <?php endif ?>
</ul> </ul>
<h2><?= t('Actions') ?></h2> <h2><?= t('Actions') ?></h2>
<ul> <ul>
<li> <li <?= $this->app->getRouterController() === 'taskmodification' && $this->app->getRouterAction() === 'edit' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Edit the task'), 'taskmodification', 'edit', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> <?= $this->url->link(t('Edit the task'), 'taskmodification', 'edit', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li> </li>
<li> <li <?= $this->app->getRouterController() === 'taskmodification' && $this->app->getRouterAction() === 'description' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Edit the description'), 'taskmodification', 'description', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> <?= $this->url->link(t('Edit the description'), 'taskmodification', 'description', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li> </li>
<li> <li <?= $this->app->getRouterController() === 'taskmodification' && $this->app->getRouterAction() === 'recurrence' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Edit recurrence'), 'taskmodification', 'recurrence', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> <?= $this->url->link(t('Edit recurrence'), 'taskmodification', 'recurrence', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li> </li>
<li> <li <?= $this->app->getRouterController() === 'subtask' && $this->app->getRouterAction() === 'create' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Add a sub-task'), 'subtask', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> <?= $this->url->link(t('Add a sub-task'), 'subtask', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li> </li>
<li> <li <?= $this->app->getRouterController() === 'tasklink' && $this->app->getRouterAction() === 'create' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Add a link'), 'tasklink', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> <?= $this->url->link(t('Add a link'), 'tasklink', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li> </li>
<li> <li <?= $this->app->getRouterController() === 'comment' && $this->app->getRouterAction() === 'create' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Add a comment'), 'comment', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> <?= $this->url->link(t('Add a comment'), 'comment', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li> </li>
<li> <li <?= $this->app->getRouterController() === 'file' && $this->app->getRouterAction() === 'create' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Attach a document'), 'file', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> <?= $this->url->link(t('Attach a document'), 'file', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li> </li>
<li> <li <?= $this->app->getRouterController() === 'file' && $this->app->getRouterAction() === 'screenshot' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Add a screenshot'), 'file', 'screenshot', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> <?= $this->url->link(t('Add a screenshot'), 'file', 'screenshot', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li> </li>
<li> <li <?= $this->app->getRouterController() === 'taskduplication' && $this->app->getRouterAction() === 'duplicate' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Duplicate'), 'taskduplication', 'duplicate', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> <?= $this->url->link(t('Duplicate'), 'taskduplication', 'duplicate', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li> </li>
<li> <li <?= $this->app->getRouterController() === 'taskduplication' && $this->app->getRouterAction() === 'copy' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Duplicate to another project'), 'taskduplication', 'copy', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> <?= $this->url->link(t('Duplicate to another project'), 'taskduplication', 'copy', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li> </li>
<li> <li <?= $this->app->getRouterController() === 'taskduplication' && $this->app->getRouterAction() === 'move' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Move to another project'), 'taskduplication', 'move', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> <?= $this->url->link(t('Move to another project'), 'taskduplication', 'move', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li> </li>
<li> <li <?= $this->app->getRouterController() === 'taskstatus' ? 'class="active"' : '' ?>>
<?php if ($task['is_active'] == 1): ?> <?php if ($task['is_active'] == 1): ?>
<?= $this->url->link(t('Close this task'), 'taskstatus', 'close', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> <?= $this->url->link(t('Close this task'), 'taskstatus', 'close', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
<?php else: ?> <?php else: ?>
@ -62,7 +62,7 @@
<?php endif ?> <?php endif ?>
</li> </li>
<?php if ($this->task->canRemove($task)): ?> <?php if ($this->task->canRemove($task)): ?>
<li> <li <?= $this->app->getRouterController() === 'task' && $this->app->getRouterAction() === 'remove' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Remove'), 'task', 'remove', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> <?= $this->url->link(t('Remove'), 'task', 'remove', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li> </li>
<?php endif ?> <?php endif ?>

View file

@ -23,7 +23,8 @@
<?= $this->form->select('language', $languages, $values, $errors) ?><br/> <?= $this->form->select('language', $languages, $values, $errors) ?><br/>
<?php if ($this->user->isAdmin()): ?> <?php if ($this->user->isAdmin()): ?>
<?= $this->form->checkbox('is_admin', t('Administrator'), 1, isset($values['is_admin']) && $values['is_admin'] == 1) ?><br/> <?= $this->form->checkbox('is_admin', t('Administrator'), 1, isset($values['is_admin']) && $values['is_admin'] == 1) ?>
<?= $this->form->checkbox('is_project_admin', t('Project Administrator'), 1, isset($values['is_project_admin']) && $values['is_project_admin'] == 1) ?>
<?php endif ?> <?php endif ?>
<div class="form-actions"> <div class="form-actions">

View file

@ -34,6 +34,22 @@
</p> </p>
<?php endif ?> <?php endif ?>
<?php if (! GOOGLE_AUTH && ! GITHUB_AUTH): ?> <?php if (GITHUB_AUTH): ?>
<h3><img src="<?= $this->url->dir() ?>assets/img/gitlab-icon.png"/>&nbsp;<?= t('Gitlab Account') ?></h3>
<p class="listing">
<?php if ($this->user->isCurrentUser($user['id'])): ?>
<?php if (empty($user['gitlab_id'])): ?>
<?= $this->url->link(t('Link my Gitlab Account'), 'oauth', 'gitlab', array(), true) ?>
<?php else: ?>
<?= $this->url->link(t('Unlink my Gitlab Account'), 'oauth', 'unlink', array('backend' => 'gitlab'), true) ?>
<?php endif ?>
<?php else: ?>
<?= empty($user['gitlab_id']) ? t('No account linked.') : t('Account linked.') ?>
<?php endif ?>
</p>
<?php endif ?>
<?php if (! GOOGLE_AUTH && ! GITHUB_AUTH && ! GITLAB_AUTH): ?>
<p class="alert"><?= t('No external authentication enabled.') ?></p> <p class="alert"><?= t('No external authentication enabled.') ?></p>
<?php endif ?> <?php endif ?>

View file

@ -18,9 +18,9 @@
<th><?= $paginator->order(t('Name'), 'name') ?></th> <th><?= $paginator->order(t('Name'), 'name') ?></th>
<th><?= $paginator->order(t('Email'), 'email') ?></th> <th><?= $paginator->order(t('Email'), 'email') ?></th>
<th><?= $paginator->order(t('Administrator'), 'is_admin') ?></th> <th><?= $paginator->order(t('Administrator'), 'is_admin') ?></th>
<th><?= $paginator->order(t('Project Administrator'), 'is_project_admin') ?></th>
<th><?= $paginator->order(t('Two factor authentication'), 'twofactor_activated') ?></th> <th><?= $paginator->order(t('Two factor authentication'), 'twofactor_activated') ?></th>
<th><?= $paginator->order(t('Notifications'), 'notifications_enabled') ?></th> <th><?= $paginator->order(t('Notifications'), 'notifications_enabled') ?></th>
<th><?= t('External accounts') ?></th>
<th><?= $paginator->order(t('Account type'), 'is_ldap_user') ?></th> <th><?= $paginator->order(t('Account type'), 'is_ldap_user') ?></th>
</tr> </tr>
<?php foreach ($paginator->getCollection() as $user): ?> <?php foreach ($paginator->getCollection() as $user): ?>
@ -40,6 +40,9 @@
<td> <td>
<?= $user['is_admin'] ? t('Yes') : t('No') ?> <?= $user['is_admin'] ? t('Yes') : t('No') ?>
</td> </td>
<td>
<?= $user['is_project_admin'] ? t('Yes') : t('No') ?>
</td>
<td> <td>
<?= $user['twofactor_activated'] ? t('Yes') : t('No') ?> <?= $user['twofactor_activated'] ? t('Yes') : t('No') ?>
</td> </td>
@ -50,16 +53,6 @@
<?= t('Disabled') ?> <?= t('Disabled') ?>
<?php endif ?> <?php endif ?>
</td> </td>
<td>
<ul class="no-bullet">
<?php if ($user['google_id']): ?>
<li><i class="fa fa-google fa-fw"></i><?= t('Google account linked') ?></li>
<?php endif ?>
<?php if ($user['github_id']): ?>
<li><i class="fa fa-github fa-fw"></i><?= t('Github account linked') ?></li>
<?php endif ?>
</ul>
</td>
<td> <td>
<?= $user['is_ldap_user'] ? t('Remote') : t('Local') ?> <?= $user['is_ldap_user'] ? t('Remote') : t('Local') ?>
</td> </td>

View file

@ -11,7 +11,7 @@
<h2><?= t('Security') ?></h2> <h2><?= t('Security') ?></h2>
</div> </div>
<ul class="listing"> <ul class="listing">
<li><?= t('Group:') ?> <strong><?= $user['is_admin'] ? t('Administrator') : t('Regular user') ?></strong></li> <li><?= t('Group:') ?> <strong><?= $user['is_admin'] ? t('Administrator') : ($user['is_project_admin'] ? t('Project Administrator') : t('Regular user')) ?></strong></li>
<li><?= t('Account type:') ?> <strong><?= $user['is_ldap_user'] ? t('Remote') : t('Local') ?></strong></li> <li><?= t('Account type:') ?> <strong><?= $user['is_ldap_user'] ? t('Remote') : t('Local') ?></strong></li>
<li><?= $user['twofactor_activated'] == 1 ? t('Two factor authentication enabled') : t('Two factor authentication disabled') ?></li> <li><?= $user['twofactor_activated'] == 1 ? t('Two factor authentication enabled') : t('Two factor authentication disabled') ?></li>
</ul> </ul>

View file

@ -1,7 +1,7 @@
<div class="sidebar"> <div class="sidebar">
<h2><?= t('Information') ?></h2> <h2><?= t('Information') ?></h2>
<ul> <ul>
<li> <li <?= $this->app->getRouterController() === 'user' && $this->app->getRouterAction() === 'show' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Summary'), 'user', 'show', array('user_id' => $user['id'])) ?> <?= $this->url->link(t('Summary'), 'user', 'show', array('user_id' => $user['id'])) ?>
</li> </li>
<?php if ($this->user->isAdmin()): ?> <?php if ($this->user->isAdmin()): ?>
@ -10,13 +10,13 @@
</li> </li>
<?php endif ?> <?php endif ?>
<?php if ($this->user->isAdmin() || $this->user->isCurrentUser($user['id'])): ?> <?php if ($this->user->isAdmin() || $this->user->isCurrentUser($user['id'])): ?>
<li> <li <?= $this->app->getRouterController() === 'user' && $this->app->getRouterAction() === 'timesheet' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Time tracking'), 'user', 'timesheet', array('user_id' => $user['id'])) ?> <?= $this->url->link(t('Time tracking'), 'user', 'timesheet', array('user_id' => $user['id'])) ?>
</li> </li>
<li> <li <?= $this->app->getRouterController() === 'user' && $this->app->getRouterAction() === 'last' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Last logins'), 'user', 'last', array('user_id' => $user['id'])) ?> <?= $this->url->link(t('Last logins'), 'user', 'last', array('user_id' => $user['id'])) ?>
</li> </li>
<li> <li <?= $this->app->getRouterController() === 'user' && $this->app->getRouterAction() === 'sessions' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Persistent connections'), 'user', 'sessions', array('user_id' => $user['id'])) ?> <?= $this->url->link(t('Persistent connections'), 'user', 'sessions', array('user_id' => $user['id'])) ?>
</li> </li>
<?php endif ?> <?php endif ?>
@ -25,51 +25,51 @@
<h2><?= t('Actions') ?></h2> <h2><?= t('Actions') ?></h2>
<ul> <ul>
<?php if ($this->user->isAdmin() || $this->user->isCurrentUser($user['id'])): ?> <?php if ($this->user->isAdmin() || $this->user->isCurrentUser($user['id'])): ?>
<li> <li <?= $this->app->getRouterController() === 'user' && $this->app->getRouterAction() === 'edit' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Edit profile'), 'user', 'edit', array('user_id' => $user['id'])) ?> <?= $this->url->link(t('Edit profile'), 'user', 'edit', array('user_id' => $user['id'])) ?>
</li> </li>
<?php if ($user['is_ldap_user'] == 0): ?> <?php if ($user['is_ldap_user'] == 0): ?>
<li> <li <?= $this->app->getRouterController() === 'user' && $this->app->getRouterAction() === 'password' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Change password'), 'user', 'password', array('user_id' => $user['id'])) ?> <?= $this->url->link(t('Change password'), 'user', 'password', array('user_id' => $user['id'])) ?>
</li> </li>
<?php endif ?> <?php endif ?>
<?php if ($this->user->isCurrentUser($user['id'])): ?> <?php if ($this->user->isCurrentUser($user['id'])): ?>
<li> <li <?= $this->app->getRouterController() === 'twofactor' && $this->app->getRouterAction() === 'index' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Two factor authentication'), 'twofactor', 'index', array('user_id' => $user['id'])) ?> <?= $this->url->link(t('Two factor authentication'), 'twofactor', 'index', array('user_id' => $user['id'])) ?>
</li> </li>
<?php elseif ($this->user->isAdmin() && $user['twofactor_activated'] == 1): ?> <?php elseif ($this->user->isAdmin() && $user['twofactor_activated'] == 1): ?>
<li> <li <?= $this->app->getRouterController() === 'twofactor' && $this->app->getRouterAction() === 'disable' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Two factor authentication'), 'twofactor', 'disable', array('user_id' => $user['id'])) ?> <?= $this->url->link(t('Two factor authentication'), 'twofactor', 'disable', array('user_id' => $user['id'])) ?>
</li> </li>
<?php endif ?> <?php endif ?>
<li> <li <?= $this->app->getRouterController() === 'user' && $this->app->getRouterAction() === 'share' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Public access'), 'user', 'share', array('user_id' => $user['id'])) ?> <?= $this->url->link(t('Public access'), 'user', 'share', array('user_id' => $user['id'])) ?>
</li> </li>
<li> <li <?= $this->app->getRouterController() === 'user' && $this->app->getRouterAction() === 'notifications' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Email notifications'), 'user', 'notifications', array('user_id' => $user['id'])) ?> <?= $this->url->link(t('Email notifications'), 'user', 'notifications', array('user_id' => $user['id'])) ?>
</li> </li>
<li> <li <?= $this->app->getRouterController() === 'user' && $this->app->getRouterAction() === 'external' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('External accounts'), 'user', 'external', array('user_id' => $user['id'])) ?> <?= $this->url->link(t('External accounts'), 'user', 'external', array('user_id' => $user['id'])) ?>
</li> </li>
<?php endif ?> <?php endif ?>
<?php if ($this->user->isAdmin()): ?> <?php if ($this->user->isAdmin()): ?>
<li> <li <?= $this->app->getRouterController() === 'user' && $this->app->getRouterAction() === 'authentication' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Edit Authentication'), 'user', 'authentication', array('user_id' => $user['id'])) ?> <?= $this->url->link(t('Edit Authentication'), 'user', 'authentication', array('user_id' => $user['id'])) ?>
</li> </li>
<li> <li <?= $this->app->getRouterController() === 'hourlyrate' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Hourly rates'), 'hourlyrate', 'index', array('user_id' => $user['id'])) ?> <?= $this->url->link(t('Hourly rates'), 'hourlyrate', 'index', array('user_id' => $user['id'])) ?>
</li> </li>
<li> <li <?= $this->app->getRouterController() === 'timetable' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Manage timetable'), 'timetable', 'index', array('user_id' => $user['id'])) ?> <?= $this->url->link(t('Manage timetable'), 'timetable', 'index', array('user_id' => $user['id'])) ?>
</li> </li>
<?php endif ?> <?php endif ?>
<?php if ($this->user->isAdmin() && ! $this->user->isCurrentUser($user['id'])): ?> <?php if ($this->user->isAdmin() && ! $this->user->isCurrentUser($user['id'])): ?>
<li> <li <?= $this->app->getRouterController() === 'user' && $this->app->getRouterAction() === 'remove' ? 'class="active"' : '' ?>>
<?= $this->url->link(t('Remove'), 'user', 'remove', array('user_id' => $user['id'])) ?> <?= $this->url->link(t('Remove'), 'user', 'remove', array('user_id' => $user['id'])) ?>
</li> </li>
<?php endif ?> <?php endif ?>

View file

@ -113,18 +113,19 @@ if (ENABLE_URL_REWRITE) {
// Board routes // Board routes
$container['router']->addRoute('board/:project_id', 'board', 'show', array('project_id')); $container['router']->addRoute('board/:project_id', 'board', 'show', array('project_id'));
$container['router']->addRoute('b/:project_id', 'board', 'show', array('project_id')); $container['router']->addRoute('b/:project_id', 'board', 'show', array('project_id'));
$container['router']->addRoute('board/:project_id/filter/:search', 'board', 'show', array('project_id', 'search'));
$container['router']->addRoute('public/board/:token', 'board', 'readonly', array('token')); $container['router']->addRoute('public/board/:token', 'board', 'readonly', array('token'));
// Calendar routes // Calendar routes
$container['router']->addRoute('calendar/:project_id', 'calendar', 'show', array('project_id')); $container['router']->addRoute('calendar/:project_id', 'calendar', 'show', array('project_id'));
$container['router']->addRoute('c/:project_id', 'calendar', 'show', array('project_id')); $container['router']->addRoute('c/:project_id', 'calendar', 'show', array('project_id'));
$container['router']->addRoute('calendar/:project_id/:search', 'calendar', 'show', array('project_id', 'search'));
// Listing routes // Listing routes
$container['router']->addRoute('list/:project_id', 'listing', 'show', array('project_id')); $container['router']->addRoute('list/:project_id', 'listing', 'show', array('project_id'));
$container['router']->addRoute('l/:project_id', 'listing', 'show', array('project_id')); $container['router']->addRoute('l/:project_id', 'listing', 'show', array('project_id'));
$container['router']->addRoute('list/:project_id/:search', 'listing', 'show', array('project_id', 'search'));
// Gantt routes
$container['router']->addRoute('gantt/:project_id', 'gantt', 'project', array('project_id'));
$container['router']->addRoute('gantt/:project_id/sort/:sorting', 'gantt', 'project', array('project_id', 'sorting'));
// Subtask routes // Subtask routes
$container['router']->addRoute('project/:project_id/task/:task_id/subtask/create', 'subtask', 'create', array('project_id', 'task_id')); $container['router']->addRoute('project/:project_id/task/:task_id/subtask/create', 'subtask', 'create', array('project_id', 'task_id'));
@ -142,6 +143,7 @@ if (ENABLE_URL_REWRITE) {
// Auth routes // Auth routes
$container['router']->addRoute('oauth/google', 'oauth', 'google'); $container['router']->addRoute('oauth/google', 'oauth', 'google');
$container['router']->addRoute('oauth/github', 'oauth', 'github'); $container['router']->addRoute('oauth/github', 'oauth', 'github');
$container['router']->addRoute('oauth/gitlab', 'oauth', 'gitlab');
$container['router']->addRoute('login', 'auth', 'login'); $container['router']->addRoute('login', 'auth', 'login');
$container['router']->addRoute('logout', 'auth', 'logout'); $container['router']->addRoute('logout', 'auth', 'logout');
} }

View file

@ -5,7 +5,7 @@ defined('DEBUG') or define('DEBUG', false);
defined('DEBUG_FILE') or define('DEBUG_FILE', __DIR__.'/../data/debug.log'); defined('DEBUG_FILE') or define('DEBUG_FILE', __DIR__.'/../data/debug.log');
// Application version // Application version
defined('APP_VERSION') or define('APP_VERSION', '1.0.17'); defined('APP_VERSION') or define('APP_VERSION', '1.0.18');
// Database driver: sqlite, mysql or postgres // Database driver: sqlite, mysql or postgres
defined('DB_DRIVER') or define('DB_DRIVER', 'sqlite'); defined('DB_DRIVER') or define('DB_DRIVER', 'sqlite');
@ -46,6 +46,17 @@ defined('GOOGLE_CLIENT_SECRET') or define('GOOGLE_CLIENT_SECRET', '');
defined('GITHUB_AUTH') or define('GITHUB_AUTH', false); defined('GITHUB_AUTH') or define('GITHUB_AUTH', false);
defined('GITHUB_CLIENT_ID') or define('GITHUB_CLIENT_ID', ''); defined('GITHUB_CLIENT_ID') or define('GITHUB_CLIENT_ID', '');
defined('GITHUB_CLIENT_SECRET') or define('GITHUB_CLIENT_SECRET', ''); defined('GITHUB_CLIENT_SECRET') or define('GITHUB_CLIENT_SECRET', '');
defined('GITHUB_OAUTH_AUTHORIZE_URL') or define('GITHUB_OAUTH_AUTHORIZE_URL', 'https://github.com/login/oauth/authorize');
defined('GITHUB_OAUTH_TOKEN_URL') or define('GITHUB_OAUTH_TOKEN_URL', 'https://github.com/login/oauth/access_token');
defined('GITHUB_API_URL') or define('GITHUB_API_URL', 'https://api.github.com/');
// Gitlab authentication
defined('GITLAB_AUTH') or define('GITLAB_AUTH', false);
defined('GITLAB_CLIENT_ID') or define('GITLAB_CLIENT_ID', '');
defined('GITLAB_CLIENT_SECRET') or define('GITLAB_CLIENT_SECRET', '');
defined('GITLAB_OAUTH_AUTHORIZE_URL') or define('GITLAB_OAUTH_AUTHORIZE_URL', 'https://gitlab.com/oauth/authorize');
defined('GITLAB_OAUTH_TOKEN_URL') or define('GITLAB_OAUTH_TOKEN_URL', 'https://gitlab.com/oauth/token');
defined('GITLAB_API_URL') or define('GITLAB_API_URL', 'https://gitlab.com/api/v3/');
// Proxy authentication // Proxy authentication
defined('REVERSE_PROXY_AUTH') or define('REVERSE_PROXY_AUTH', false); defined('REVERSE_PROXY_AUTH') or define('REVERSE_PROXY_AUTH', false);
@ -53,6 +64,9 @@ defined('REVERSE_PROXY_USER_HEADER') or define('REVERSE_PROXY_USER_HEADER', 'REM
defined('REVERSE_PROXY_DEFAULT_ADMIN') or define('REVERSE_PROXY_DEFAULT_ADMIN', ''); defined('REVERSE_PROXY_DEFAULT_ADMIN') or define('REVERSE_PROXY_DEFAULT_ADMIN', '');
defined('REVERSE_PROXY_DEFAULT_DOMAIN') or define('REVERSE_PROXY_DEFAULT_DOMAIN', ''); defined('REVERSE_PROXY_DEFAULT_DOMAIN') or define('REVERSE_PROXY_DEFAULT_DOMAIN', '');
// Remember me authentication
defined('REMEMBER_ME_AUTH') or define('REMEMBER_ME_AUTH', true);
// Mail configuration // Mail configuration
defined('MAIL_FROM') or define('MAIL_FROM', 'notifications@kanboard.local'); defined('MAIL_FROM') or define('MAIL_FROM', 'notifications@kanboard.local');
defined('MAIL_TRANSPORT') or define('MAIL_TRANSPORT', 'mail'); defined('MAIL_TRANSPORT') or define('MAIL_TRANSPORT', 'mail');
@ -88,3 +102,12 @@ defined('ENABLE_URL_REWRITE') or define('ENABLE_URL_REWRITE', isset($_SERVER['HT
// Hide login form // Hide login form
defined('HIDE_LOGIN_FORM') or define('HIDE_LOGIN_FORM', false); defined('HIDE_LOGIN_FORM') or define('HIDE_LOGIN_FORM', false);
// Bruteforce protection
defined('BRUTEFORCE_CAPTCHA') or define('BRUTEFORCE_CAPTCHA', 3);
defined('BRUTEFORCE_LOCKDOWN') or define('BRUTEFORCE_LOCKDOWN', 6);
defined('BRUTEFORCE_LOCKDOWN_DURATION') or define('BRUTEFORCE_LOCKDOWN_DURATION', 15);
// Session duration in second (0 = until the browser is closed)
// See http://php.net/manual/en/session.configuration.php#ini.session.cookie-lifetime
defined('SESSION_DURATION') or define('SESSION_DURATION', 0);

File diff suppressed because one or more lines are too long

BIN
sources/assets/css/images/ui-bg_flat_0_aaaaaa_40x100.png Executable file → Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 212 B

After

Width:  |  Height:  |  Size: 212 B

BIN
sources/assets/css/images/ui-bg_flat_75_ffffff_40x100.png Executable file → Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 208 B

After

Width:  |  Height:  |  Size: 208 B

BIN
sources/assets/css/images/ui-bg_glass_55_fbf9ee_1x400.png Executable file → Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 335 B

After

Width:  |  Height:  |  Size: 335 B

BIN
sources/assets/css/images/ui-bg_glass_65_ffffff_1x400.png Executable file → Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 207 B

After

Width:  |  Height:  |  Size: 207 B

BIN
sources/assets/css/images/ui-bg_glass_75_dadada_1x400.png Executable file → Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 262 B

After

Width:  |  Height:  |  Size: 262 B

BIN
sources/assets/css/images/ui-bg_glass_75_e6e6e6_1x400.png Executable file → Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 262 B

After

Width:  |  Height:  |  Size: 262 B

BIN
sources/assets/css/images/ui-bg_glass_95_fef1ec_1x400.png Executable file → Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 332 B

After

Width:  |  Height:  |  Size: 332 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 280 B

After

Width:  |  Height:  |  Size: 280 B

BIN
sources/assets/css/images/ui-icons_222222_256x240.png Executable file → Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

BIN
sources/assets/css/images/ui-icons_2e83ff_256x240.png Executable file → Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

BIN
sources/assets/css/images/ui-icons_454545_256x240.png Executable file → Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

BIN
sources/assets/css/images/ui-icons_888888_256x240.png Executable file → Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

BIN
sources/assets/css/images/ui-icons_cd0a0a_256x240.png Executable file → Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

View file

@ -43,7 +43,6 @@ hr {
border-bottom: 1px solid rgba(255, 255, 255, 0.3); border-bottom: 1px solid rgba(255, 255, 255, 0.3);
} }
#board-selector,
.chosen-select { .chosen-select {
min-height: 27px; /* Reserve some space to avoid re-layout due to chosen */ min-height: 27px; /* Reserve some space to avoid re-layout due to chosen */
} }

View file

@ -11,10 +11,22 @@
/* board table */ /* board table */
#board-container { #board-container {
padding-bottom: 220px; /* Space to avoid dropdown menu truncated */
overflow-x: scroll; overflow-x: scroll;
} }
#board {
table-layout: fixed;
}
#board th.board-column-header {
width: 240px;
}
#board td {
vertical-align: top;
}
/* compact mode/horizontal scrolling */
.board-container-compact { .board-container-compact {
overflow-x: initial; overflow-x: initial;
} }
@ -25,34 +37,43 @@
} }
} }
#board { #board th.board-column-header.board-column-compact {
table-layout: fixed;
}
#board th {
width: 120px; /* Width of swimlane column */
}
#board th.board-column {
width: 240px; /* Width of other columns, in default [horizontal scrolling] view mode */
}
#board th.board-column.board-column-compact {
width: initial; /* Do not force the width of the columns in compact view mode */ width: initial; /* Do not force the width of the columns in compact view mode */
} }
#board th a { /* show/hide column */
text-decoration: none; .board-column-collapsed {
color: #3366CC; display: none;
font-size: 150%;
} }
#board td { td.board-column-task-collapsed {
vertical-align: top; font-weight: bold;
background-color: #fbfbfb;
} }
#board td.task-limit-warning { #board th.board-column-header-collapsed {
background-color: #DF5353; 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%;
} }
/* column header */ /* column header */
@ -62,14 +83,54 @@
} }
.board-add-icon a { .board-add-icon a {
text-decoration: none;
color: #3366CC;
font-size: 150%;
line-height: 70%; line-height: 70%;
} }
.task-count { .board-add-icon a:focus,
.board-add-icon a:hover {
text-decoration: none;
color: red;
}
.board-column-header-task-count {
color: #999; color: #999;
font-weight: normal; font-weight: normal;
} }
th.board-column-header-collapsed .board-column-header-task-count {
font-size: 0.85em;
}
/* swimlanes */
th.board-swimlane-header {
width: 120px;
}
a.board-swimlane-toggle {
font-size: 0.95em;
}
.board-swimlane-toggle-title {
font-size: 0.85em;
display: none;
}
.board-swimlane-title {
vertical-align: top;
}
/* board task list */
.board-task-list {
overflow: auto;
}
.board-task-list-limit {
background-color: #DF5353;
}
/* drag and drop */ /* drag and drop */
.draggable-item { .draggable-item {
cursor: pointer; cursor: pointer;
@ -83,16 +144,11 @@
margin-bottom: 10px; margin-bottom: 10px;
} }
/* swimlanes */ div.draggable-item-selected {
#board th a.board-swimlane-toggle { border: 1px solid #000;
font-size: 0.95em;
} }
.board-swimlane-toggle-title { .task-board-sort-handle {
font-size: 0.85em; float: left;
display: none; padding-right: 5px;
}
.board-swimlane-title {
vertical-align: top;
} }

Some files were not shown because too many files have changed in this diff Show more