From 0b1dcecc9c3cd188b8f56f4fe6172ee2f34266ad Mon Sep 17 00:00:00 2001 From: ngosang Date: Sun, 19 Jun 2016 19:29:15 +0200 Subject: Update es_ES translation --- app/Locale/es_ES/translations.php | 388 +++++++++++++++++++------------------- 1 file changed, 194 insertions(+), 194 deletions(-) (limited to 'app') diff --git a/app/Locale/es_ES/translations.php b/app/Locale/es_ES/translations.php index a646e4ef..39757f74 100644 --- a/app/Locale/es_ES/translations.php +++ b/app/Locale/es_ES/translations.php @@ -20,16 +20,16 @@ return array( 'Orange' => 'Naranja', 'Grey' => 'Gris', 'Brown' => 'Marrón', - 'Deep Orange' => 'Naranja Oscuro', - 'Dark Grey' => 'Gris Oscuro', + 'Deep Orange' => 'Naranja oscuro', + 'Dark Grey' => 'Gris oscuro', 'Pink' => 'Rosa', - 'Teal' => 'Verde Azulado', - 'Cyan' => 'Cián', + 'Teal' => 'Verde azulado', + 'Cyan' => 'Cian', 'Lime' => 'Lima', - 'Light Green' => 'Verde Claro', + 'Light Green' => 'Verde claro', 'Amber' => 'Ámbar', 'Save' => 'Guardar', - 'Login' => 'Iniciar sesión (Ingresar)', + 'Login' => 'Iniciar sesión (ingresar)', 'Official website:' => 'Página web oficial:', 'Unassigned' => 'No asignado', 'View this task' => 'Ver esta tarea', @@ -80,7 +80,7 @@ return array( 'Settings' => 'Preferencias', 'Application settings' => 'Preferencias de la aplicación', 'Language' => 'Idioma', - 'Webhook token:' => 'Token de los disparadores Web (webhooks):', + 'Webhook token:' => 'Token de los disparadores web (webhooks):', 'API token:' => 'Token de la API:', 'Database size:' => 'Tamaño de la base de datos:', 'Download the database' => 'Descargar la base de datos', @@ -175,7 +175,7 @@ return array( '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.', 'Remove an action' => 'Eliminar una acción', - 'Unable to remove this action.' => 'No se puede eliminar esta accción.', + 'Unable to remove this action.' => 'No se puede eliminar esta acción.', 'Action removed successfully.' => 'La acción ha sido eliminada correctamente.', 'Automatic actions for the project "%s"' => 'Acciones automatizadas para el proyecto «%s»', 'Add an action' => 'Añadir una acción', @@ -315,9 +315,9 @@ return array( 'Project cloned successfully.' => 'Proyecto clonado correctamente.', 'Unable to clone this project.' => 'No se puede clonar este proyecto.', 'Enable email notifications' => 'Habilitar notificaciones por correo electrónico', - 'Task position:' => 'Posición de la tarea', - 'The task #%d have been opened.' => 'La tarea #%d ha sido abierta', - 'The task #%d have been closed.' => 'La tarea #%d ha sido cerrada', + 'Task position:' => 'Posición de la tarea:', + 'The task #%d have been opened.' => 'La tarea #%d ha sido abierta.', + 'The task #%d have been closed.' => 'La tarea #%d ha sido cerrada.', 'Sub-task updated' => 'Subtarea actualizada', 'Title:' => 'Título:', 'Status:' => 'Estado:', @@ -362,7 +362,7 @@ return array( 'Account type:' => 'Tipo de cuenta:', 'Edit profile' => 'Modificar perfil', 'Change password' => 'Cambiar contraseña', - 'Password modification' => 'Modificacion de contraseña', + 'Password modification' => 'Modificación de contraseña', 'External authentications' => 'Autenticación externa', 'Never connected.' => 'Nunca se ha conectado.', 'No external authentication enabled.' => 'Sin autenticación externa activa.', @@ -411,13 +411,13 @@ return array( 'About' => 'Acerca de', 'Database driver:' => 'Controlador de la base de datos (driver):', 'Board settings' => 'Preferencias del tablero', - 'Webhook settings' => 'Preferencias del disparador web (Webhook)', + 'Webhook settings' => 'Preferencias del disparador web (webhook)', 'Reset token' => 'Limpiar token', 'API endpoint:' => 'Endpoint del API:', 'Refresh interval for private board' => 'Intervalo de refresco del tablero privado', 'Refresh interval for public board' => 'Intervalo de refresco del tablero público', '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 fue 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 (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', @@ -435,7 +435,7 @@ return array( 'Dashboard' => 'Tablero', 'Confirmation' => 'Confirmación', 'Allow everybody to access to this project' => 'Permitir a cualquiera acceder a este proyecto', - 'Everybody have access to this project.' => 'Cualquiera tiene acceso a este proyecto', + 'Everybody have access to this project.' => 'Cualquiera tiene acceso a este proyecto.', 'Webhooks' => 'Disparadores web (webhooks)', 'API' => 'API', 'Create a comment from an external provider' => 'Crear un comentario a partir de un proveedor externo', @@ -504,8 +504,8 @@ return array( 'Task Title' => 'Título de la tarea', 'Untitled' => 'Sin título', 'Application default' => 'Predefinido por la aplicación', - 'Language:' => 'Idioma', - 'Timezone:' => 'Zona horaria', + 'Language:' => 'Idioma:', + 'Timezone:' => 'Zona horaria:', 'All columns' => 'Todas las columnas', 'Calendar' => 'Calendario', 'Next' => 'Siguiente', @@ -564,7 +564,7 @@ return array( '%dh' => '%dh', 'Expand tasks' => 'Expandir tareas', 'Collapse tasks' => 'Colapsar tareas', - 'Expand/collapse tasks' => 'Expande/colapasa tareas', + 'Expand/collapse tasks' => 'Expande/colapsa tareas', 'Close dialog box' => 'Cerrar caja de diálogo', 'Submit a form' => 'Enviar formulario', 'Board view' => 'Vista de tablero', @@ -597,14 +597,14 @@ return array( 'Executer' => 'Ejecutor', 'Time spent in the column' => 'Tiempo transcurrido en la columna', 'Task transitions' => 'Transiciones de tarea', - 'Task transitions export' => 'Eportar transiciones de tarea', - 'This report contains all column moves for each task with the date, the user and the time spent for each transition.' => 'Este informe contiene todos los movimientos de columna para cada tarea con la fecha, el usuario y el tiempo transcurrido en cada trasición.', + 'Task transitions export' => 'Exportar transiciones de tarea', + 'This report contains all column moves for each task with the date, the user and the time spent for each transition.' => 'Este informe contiene todos los movimientos de columna para cada tarea con la fecha, el usuario y el tiempo transcurrido en cada transición.', 'Currency rates' => 'Cambio de monedas', 'Rate' => 'Cambio', 'Change reference currency' => 'Cambiar moneda de referencia', 'Add a new currency rate' => 'Añadir nuevo cambio de moneda', 'Reference currency' => 'Moneda de referencia', - 'The currency rate have been added successfully.' => 'Se ha añadido el cambio de moneda correctamente.', + 'The currency rate have been added successfully.' => 'El cambio de moneda se ha añadido correctamente.', 'Unable to add this currency rate.' => 'No se puede añadir este cambio de moneda.', 'Webhook URL' => 'URL del disparador web (webhook)', '%s remove the assignee of the task %s' => '%s quita el responsable de la tarea %s', @@ -623,67 +623,67 @@ return array( '%s via Kanboard' => '%s vía Kanboard', 'Burndown chart for "%s"' => 'Trabajo pendiente para «%s»', 'Burndown chart' => 'Trabajo pendiente', - 'This chart show the task complexity over the time (Work Remaining).' => 'Este diagrama mestra la complejidad de la tarea a lo largo del tiempo (trabajo restante).', + 'This chart show the task complexity over the time (Work Remaining).' => 'Este diagrama muestra la complejidad de la tarea a lo largo del tiempo (trabajo restante).', 'Screenshot taken %s' => 'Pantallazo tomado el %s', 'Add a screenshot' => 'Añadir un pantallazo', '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 correctamente.', 'SEK - Swedish Krona' => 'SEK - Corona sueca', 'Identifier' => 'Identificador', - '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 quiere desactuvar la autenticación de dos factores para este usuario: "%s?"', + 'Disable two factor authentication' => 'Desactivar la autenticación en dos pasos', + 'Do you really want to disable the two factor authentication for this user: "%s"?' => '¿Realmente desea desactivar la autenticación en dos pasos para este usuario: «%s»?', 'Edit link' => 'Modificar enlace', '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 sigo misma', + 'A task cannot be linked to itself' => 'Una tarea no se puede enlazar con sigo misma', 'The exact same link already exists' => 'El mismo enlace ya existe', 'Recurrent task is scheduled to be generated' => 'Tarea recurrente programada para ser generada', 'Score' => 'Puntuación', '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 identificador de tarea no existe', 'This value must be alphanumeric' => 'Este valor debe ser alfanumérico', 'Edit recurrence' => 'Modificar repetición', - 'Generate recurrent task' => 'Generar tarea recurrente', - 'Trigger to generate recurrent task' => 'Disparador para generar tarea recurrente', + 'Generate recurrent task' => 'Generar una tarea recurrente', + 'Trigger to generate recurrent task' => 'Disparador para generar una tarea recurrente', '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 entrega', 'Base date to calculate new due date' => 'Fecha base para calcular la nueva fecha de entrega', 'Action date' => 'Fecha de la acción', - '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:', + '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 creado esta tarea hija: ', 'Day(s)' => 'Día(s)', 'Existing due date' => 'Fecha de entrega existente', - 'Factor to calculate new due date: ' => 'Factor para calcular la nueva fecha de entrega:', + 'Factor to calculate new due date: ' => 'Factor para calcular la nueva fecha de entrega: ', 'Month(s)' => 'Mes(es)', 'Recurrence' => 'Repetición', 'This task has been created by: ' => 'Esta tarea ha sido creada por: ', 'Recurrent task has been generated:' => 'Tarea recurrente generada:', - 'Timeframe to calculate new due date: ' => 'Calendario para calcular la nueva fecha de entrega:', - 'Trigger to generate recurrent task: ' => 'Disparador para generar tarea recurrente', + 'Timeframe to calculate new due date: ' => 'Calendario para calcular la nueva fecha de entrega: ', + 'Trigger to generate recurrent task: ' => 'Disparador para generar una tarea recurrente: ', 'When task is closed' => 'Cuando la tarea es cerrada', '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', 'Year(s)' => 'Año(s)', - 'Calendar settings' => 'Parámetros del Calendario', - 'Project calendar view' => 'Vista de Calendario para el Proyecto', - 'Project settings' => 'Parámetros del Proyecto', - 'Show subtasks based on the time tracking' => 'Mostrar subtareas en base al seguimiento de tiempo', + 'Calendar settings' => 'Preferencias del calendario', + 'Project calendar view' => 'Vista de calendario del proyecto', + 'Project settings' => 'Preferencias del proyecto', + 'Show subtasks based on the time tracking' => 'Mostrar subtareas en base al seguimiento temporal', 'Show tasks based on the creation date' => 'Mostrar tareas en base a la fecha de creación', - 'Show tasks based on the start date' => 'Mostrar tareas en base a la fecha de comienzo', + 'Show tasks based on the start date' => 'Mostrar tareas en base a la fecha de inicio', 'Subtasks time tracking' => 'Seguimiento de tiempo en subtareas', - 'User calendar view' => 'Vista de Calendario para el Usuario', - 'Automatically update the start date' => 'Actualizar automáticamente la fecha de comienzo', + 'User calendar view' => 'Vista de calendario del usuario', + 'Automatically update the start date' => 'Actualizar automáticamente la fecha de inicio', 'iCal feed' => 'Fuente iCal', 'Preferences' => 'Preferencias', 'Security' => 'Seguridad', - 'Two factor authentication disabled' => 'Autenticación de dos factores deshabilitada', - 'Two factor authentication enabled' => 'Autenticación de dos factores habilitada', + 'Two factor authentication disabled' => 'Autenticación en dos pasos deshabilitada', + 'Two factor authentication enabled' => 'Autenticación en dos pasos habilitada', 'Unable to update this user.' => 'No se puede actualizar este usuario.', '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', 'Email subject' => 'Asunto del correo', 'Date' => 'Fecha', '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 cambie la categoría', 'Send a task by email to someone' => 'Enviar una tarea a alguien por correo', 'Reopen a task' => 'Reabrir tarea', 'Column change' => 'Cambio de columna', @@ -698,12 +698,12 @@ return array( 'Gravatar' => 'Gravatar', '%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 movió la tarea %s a la calle «%s»', - '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.' => 'Este informe contiene todas la información de las tareas para el rango proporcionado de fechas.', + 'This report contains all subtasks information for the given date range.' => 'Este informe contiene toda la información de las subtareas para el rango de fechas proporcionado.', + 'This report contains all tasks information for the given date range.' => 'Este informe contiene toda la información de las tareas para el rango de fechas proporcionado.', 'Project activities for %s' => 'Actividades del proyecto para %s', 'view the board on Kanboard' => 'ver el tablero en Kanboard', '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:' => 'Se ha movido la tarea a otra calle', + 'The task have been moved to another swimlane:' => 'Se ha movido la tarea a otra calle:', 'New title: %s' => 'Nuevo título: %s', 'The task is not assigned anymore' => 'La tarea ya no está asignada', 'New assignee: %s' => 'Nuevo responsable: %s', @@ -717,46 +717,46 @@ return array( 'Time spent changed: %sh' => 'Se ha cambiado el tiempo empleado: %sh', 'Time estimated changed: %sh' => 'Se ha cambiado el tiempo estimado: %sh', 'The field "%s" have been updated' => 'Se ha actualizado el campo «%s»', - 'The description has been modified:' => 'Se ha modificado la descripción', + 'The description has been modified:' => 'Se ha modificado la descripción:', 'Do you really want to close the task "%s" as well as all subtasks?' => '¿Realmente desea cerrar la tarea «%s» así como todas las subtareas?', 'I want to receive notifications for:' => 'Deseo recibir notificaciones para:', 'All tasks' => 'Todas las tareas', 'Only for tasks assigned to me' => 'Sólo para las tareas que me han sido asignadas', - 'Only for tasks created by me' => 'Sólo para las taread creadas por mí', - 'Only for tasks created by me and assigned to me' => 'Sólo para las tareas credas por mí y que me han sido asignadas', + 'Only for tasks created by me' => 'Sólo para las tareas creadas por mí', + 'Only for tasks created by me and assigned to me' => 'Sólo para las tareas creadas por mí y que me han sido asignadas', '%%Y-%%m-%%d' => '%%d/%%M/%%Y', 'Total for all columns' => 'Total para todas las columnas', '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', '<30m' => '<30m', 'Stop timer' => 'Parar temporizador', - 'Start timer' => 'Arrancar temporizador', + 'Start timer' => 'Iniciar temporizador', 'Add project member' => 'Añadir miembro al proyecto', 'My activity stream' => 'Mi flujo de actividad', 'My calendar' => 'Mi calendario', 'Search tasks' => 'Buscar tareas', 'Reset filters' => 'Limpiar filtros', 'My tasks due tomorrow' => 'Mis tareas a entregar mañana', - 'Tasks due today' => 'Tareas a antregar hoy', - 'Tasks due tomorrow' => 'Taraes a entregar mañana', + 'Tasks due today' => 'Tareas a entregar hoy', + 'Tasks due tomorrow' => 'Tareas a entregar mañana', 'Tasks due yesterday' => 'Tareas a entregar ayer', 'Closed tasks' => 'Tareas cerradas', 'Open tasks' => 'Tareas abiertas', 'Not assigned' => 'No asignada', - 'View advanced search syntax' => 'Ver sintáxis avanzada de búsqueda', + 'View advanced search syntax' => 'Ver sintaxis de búsqueda avanzada', 'Overview' => 'Resumen', - 'Board/Calendar/List view' => 'Vista de Tablero/Calendario/Lista', + 'Board/Calendar/List view' => 'Vista de tablero/calendario/lista', 'Switch to the board view' => 'Cambiar a vista de tablero', 'Switch to the calendar view' => 'Cambiar a vista de calendario', 'Switch to the list view' => 'Cambiar a vista de lista', 'Go to the search/filter box' => 'Ir a caja de buscar/filtrar', 'There is no activity yet.' => 'Aún no hay actividades.', - 'No tasks found.' => 'No se ha hallado tarea alguna.', + 'No tasks found.' => 'No se ha encontrado ninguna tarea.', 'Keyboard shortcut: "%s"' => 'Atajo de teclado: %s', 'List' => 'Lista', 'Filter' => 'Filtro', 'Advanced search' => 'Búsqueda avanzada', - 'Example of query: ' => 'Ejemplo de query: ', + 'Example of query: ' => 'Ejemplo de consulta: ', 'Search by project: ' => 'Buscar por proyecto: ', 'Search by column: ' => 'Buscar por columna: ', 'Search by assignee: ' => 'Buscar por responsable: ', @@ -764,36 +764,36 @@ return array( 'Search by category: ' => 'Buscar por categoría: ', 'Search by description: ' => 'Buscar por descripción: ', 'Search by due date: ' => 'Buscar por fecha de entrega: ', - 'Lead and Cycle time for "%s"' => 'Plazo de Entrega y Ciclo para «%s»', + 'Lead and Cycle time for "%s"' => 'Plazo de entrega y ciclo para «%s»', 'Average time spent into each column for "%s"' => 'Tiempo medio empleado en cada columna para «%s»', 'Average time spent into each column' => 'Tiempo medio empleado en cada columna', 'Average time spent' => 'Tiempo medio empleado', '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' => 'Plazo Medio de Entrega y de Ciclo', - 'Average lead time: ' => 'Plazo Medio de entrega: ', - 'Average cycle time: ' => 'Tiempo Medio de Ciclo: ', - 'Cycle Time' => 'Tiempo de Ciclo', - 'Lead Time' => 'Plazo de Entrega', - '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 Lead and Cycle time' => 'Plazo medio de entrega y de ciclo', + 'Average lead time: ' => 'Plazo medio de entrega: ', + 'Average cycle time: ' => 'Tiempo medio de ciclo: ', + 'Cycle Time' => 'Tiempo de ciclo', + 'Lead Time' => 'Plazo de entrega', + '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.', 'Average time into each column' => 'Tiempo medio en cada columna', 'Lead and cycle time' => 'Plazo de entrega y de ciclo', 'Lead time: ' => 'Plazo de entrega: ', - 'Cycle time: ' => 'Tiempo de Ciclo: ', + 'Cycle time: ' => 'Tiempo de ciclo: ', 'Time spent into each column' => 'Tiempo empleado en cada columna', - '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.' => '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.' => 'Si la tarea no se cierra, se usa la fecha actual en lugar de la de terminación.', + '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 finalización.', + '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 finalización.', + '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 finalización.', 'Set automatically the start date' => 'Poner la fecha de inicio de forma automática', 'Edit Authentication' => 'Modificar autenticación', 'Remote user' => 'Usuario remoto', - '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.' => 'Si marcas la caja de edición "Desactivar formulario de ingreso", se ignoran las credenciales entradas en el formulario de ingreso.', + '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.' => 'Si marcas la opción "Desactivar formulario de ingreso", se ignoran las credenciales introducidas en el formulario de ingreso.', 'New remote user' => 'Nuevo usuario remoto', 'New local user' => 'Nuevo usuario local', - 'Default task color' => 'Color por defecto de tarea', - 'This feature does not work with all browsers.' => 'Esta característica no funciona con todos los navegadores', - 'There is no destination project available.' => 'No está disponible proyecto destino', - 'Trigger automatically subtask time tracking' => 'Disparar de forma automática seguimiento temporal de subtarea', + 'Default task color' => 'Color de la tarea por defecto', + 'This feature does not work with all browsers.' => 'Esta característica no funciona en todos los navegadores.', + 'There is no destination project available.' => 'No está disponible proyecto de destino.', + 'Trigger automatically subtask time tracking' => 'Disparar de forma automática el seguimiento temporal de subtarea', 'Include closed tasks in the cumulative flow diagram' => 'Incluir tareas cerradas en el diagrama de flujo acumulado', 'Current swimlane: %s' => 'Calle en curso: %s', 'Current column: %s' => 'Columna en curso: %s', @@ -805,20 +805,20 @@ return array( 'contributors' => 'contribuyentes', 'License:' => 'Licencia:', 'License' => 'Licencia', - 'Enter the text below' => 'Digita el texto de abajo', + 'Enter the text below' => 'Introduzca el texto a continuación', 'Gantt chart for %s' => 'Diagrama de Gantt para %s', - 'Sort by position' => 'Clasificado mediante posición', - 'Sort by date' => 'Clasificado mediante fecha', + 'Sort by position' => 'Ordenar por posición', + 'Sort by date' => 'Ordenar por 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.', + 'Moving or resizing a task will change the start and due date of the task.' => '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', + 'Gantt chart' => 'Diagrama de Gantt', + 'People who are project managers' => 'Usuarios que son administradores del proyecto', + 'People who are project members' => 'Usuarios que son miembros del proyecto', + 'NOK - Norwegian Krone' => 'NOK - Corona Noruega', 'Show this column' => 'Mostrar esta columna', 'Hide this column' => 'Ocultar esta columna', 'open file' => 'abrir fichero', @@ -826,80 +826,80 @@ return array( 'Users overview' => 'Resumen de usuarios', 'Members' => 'Miembros', 'Shared project' => 'Proyecto compartido', - 'Project managers' => 'Administradores de proyecto', + 'Project managers' => 'Administradores del proyecto', 'Gantt chart for all projects' => 'Diagrama de Gantt para todos los proyectos', 'Projects list' => 'Lista de proyectos', 'Gantt chart for this project' => 'Diagrama de Gantt para este proyecto', 'Project board' => 'Tablero del proyecto', - 'End date:' => 'Fecha final', + 'End date:' => 'Fecha de fin:', 'There is no start date or end date for this project.' => 'No existe fecha de inicio o de fin para este proyecto.', - 'Projects Gantt chart' => 'Diagramas de Gantt de los proyectos', - 'Change task color when using a specific task link' => 'Cambiar colo de la tarea al usar un enlace específico a tarea', - 'Task link creation or modification' => 'Creación o modificación de enlace a tarea', + 'Projects Gantt chart' => 'Diagrama de Gantt de los proyectos', + 'Change task color when using a specific task link' => 'Cambiar el color de la tarea al usar un enlace específico a tarea', + 'Task link creation or modification' => 'Creación o modificación del enlace a tarea', 'Milestone' => 'Hito', 'Documentation: %s' => 'Documentación: %s', - 'Switch to the Gantt chart view' => 'Conmutar a vista de diagrama de Gantt', - 'Reset the search/filter box' => 'Limpiar la caja del filtro de búsqueda', + 'Switch to the Gantt chart view' => 'Cambiar a vista de diagrama de Gantt', + 'Reset the search/filter box' => 'Limpiar el filtro de búsqueda', 'Documentation' => 'Documentación', 'Table of contents' => 'Tabla de contenido', 'Gantt' => 'Gantt', 'Author' => 'Autor', 'Version' => 'Versión', 'Plugins' => 'Plugins', - 'There is no plugin loaded.' => 'No hay ningún plugin cargado', + 'There is no plugin loaded.' => 'No hay ningún plugin cargado.', 'Set maximum column height' => 'Establecer altura máxima de la columna', 'Remove maximum column height' => 'Eliminar altura máxima de la columna', 'My notifications' => 'Mis notificaciones', 'Custom filters' => 'Filtros personalizados', 'Your custom filter have been created successfully.' => 'Tus filtros personalizados han sido creados correctamente.', 'Unable to create your custom filter.' => 'No se ha podido crear tu filtro personalizado.', - 'Custom filter removed successfully.' => 'Filtro personalizado ha sido eliminado correctamente.', - 'Unable to remove this custom filter.' => 'No se ha podido eliminar tu filtro personalizado', + 'Custom filter removed successfully.' => 'El filtro personalizado ha sido eliminado correctamente.', + 'Unable to remove this custom filter.' => 'No se ha podido eliminar tu filtro personalizado.', 'Edit custom filter' => 'Modificar filtro personalizado', 'Your custom filter have been updated successfully.' => 'Tu filtro personalizado ha sido actualizado correctamente.', - 'Unable to update custom filter.' => 'No se ha podido actualizar tu filtro personalizado', + 'Unable to update custom filter.' => 'No se ha podido actualizar tu filtro personalizado.', 'Web' => 'Web', 'New attachment on task #%d: %s' => 'Nuevo adjunto en la tarea #%d: %s', 'New comment on task #%d' => 'Nuevo comentario en la tarea #%d', 'Comment updated on task #%d' => 'Comentario actualizado en la tarea #%d', 'New subtask on task #%d' => 'Nueva subtarea en la tarea #%d', - 'Subtask updated on task #%d' => 'La subtarea en la tarea #%d ha sido actualizada', + 'Subtask updated on task #%d' => 'Subtarea actualizada en la tarea #%d', 'New task #%d: %s' => 'Nueva tarea #%d: %s', 'Task updated #%d' => 'Tarea actualizada #%d', - 'Task #%d closed' => 'Tarea #%d ha sido cerrada', - 'Task #%d opened' => 'Tarea #%d ha sido abierta', - 'Column changed for task #%d' => 'Columna para tarea #%d ha sido cambiada', + 'Task #%d closed' => 'Tarea #%d cerrada', + 'Task #%d opened' => 'Tarea #%d abierta', + 'Column changed for task #%d' => 'Columna cambiada para la tarea #%d', 'New position for task #%d' => 'Nueva posición para tarea #%d', - 'Swimlane changed for task #%d' => 'Se cambió el swimlane de la tarea #%d', - 'Assignee changed on task #%d' => 'Se cambió el asignado de la tarea #%d', + 'Swimlane changed for task #%d' => 'Se cambió la calle de la tarea #%d', + 'Assignee changed on task #%d' => 'Se cambió el responsable de la tarea #%d', '%d overdue tasks' => '%d tareas atrasadas', 'Task #%d is overdue' => 'La tarea #%d está atrasada', - 'No new notifications.' => 'No hay nuevas notificaciones', + 'No new notifications.' => 'No hay nuevas notificaciones.', 'Mark all as read' => 'Marcar todo como leído', 'Mark as read' => 'Marcar como leído', - 'Total number of tasks in this column across all swimlanes' => 'Número total de tareas en esta columna por todas las swimlanes', - 'Collapse swimlane' => 'Contraer swimlane', - 'Expand swimlane' => 'Ampliar swimlane', + 'Total number of tasks in this column across all swimlanes' => 'Número total de tareas en esta columna a través de todas las calles', + 'Collapse swimlane' => 'Contraer calle', + 'Expand swimlane' => 'Ampliar calle', 'Add a new filter' => 'Añadir nuevo filtro', 'Share with all project members' => 'Compartir con todos los miembros del proyecto', 'Shared' => 'Compartido', - 'Owner' => 'Dueño', + 'Owner' => 'Propietario', 'Unread notifications' => 'Notificaciones sin leer', - 'Notification methods:' => 'Métodos de notificación', + 'Notification methods:' => 'Métodos de notificación:', 'Import tasks from CSV file' => 'Importar tareas desde archivo CSV', 'Unable to read your file' => 'No es posible leer el archivo', - '%d task(s) have been imported successfully.' => '%d tarea(s) han sido importadas correctamente', - 'Nothing have been imported!' => 'No se ha importado nada!', + '%d task(s) have been imported successfully.' => '%d tarea(s) han sido importadas correctamente.', + 'Nothing have been imported!' => '¡No se ha importado nada!', 'Import users from CSV file' => 'Importar usuarios desde archivo CSV', - '%d user(s) have been imported successfully.' => '%d usuario(s) se han importado correctamente', + '%d user(s) have been imported successfully.' => '%d usuario(s) se han importado correctamente.', 'Comma' => 'Coma', 'Semi-colon' => 'Punto y coma', 'Tab' => 'Tabulación', - 'Vertical bar' => 'Pleca', + 'Vertical bar' => 'Barra vertical', 'Double Quote' => 'Comilla doble', - 'Single Quote' => 'Comilla sencilla', - '%s attached a file to the task #%d' => '%s adjuntó un archivo a la tarea #%d', - 'There is no column or swimlane activated in your project!' => 'No hay ninguna columna o swimlane activada en su proyecto!', + 'Single Quote' => 'Comilla simple', + '%s attached a file to the task #%d' => '%s adjuntó un archivo en la tarea #%d', + 'There is no column or swimlane activated in your project!' => '¡No hay ninguna columna o calle activada en su proyecto!', 'Append filter (instead of replacement)' => 'Añadir filtro (en vez de reemplazar)', 'Append/Replace' => 'Añadir/Reemplazar', 'Append' => 'Añadir', @@ -912,63 +912,63 @@ return array( 'CSV File' => 'Archivo CSV', 'Instructions' => 'Indicaciones', 'Your file must use the predefined CSV format' => 'Su archivo debe utilizar el formato CSV predeterminado', - 'Your file must be encoded in UTF-8' => 'Su archivo debe ser codificado en UTF-8', + 'Your file must be encoded in UTF-8' => 'Su archivo debe estar codificado en UTF-8', 'The first row must be the header' => 'La primera fila debe ser el encabezado', 'Duplicates are not verified for you' => 'Los duplicados no serán verificados', 'The due date must use the ISO format: YYYY-MM-DD' => 'La fecha de entrega debe utilizar el formato ISO: AAAA-MM-DD', 'Download CSV template' => 'Descargar plantilla CSV', - 'No external integration registered.' => 'No se ha registrado integración externa', + 'No external integration registered.' => 'No se ha registrado integración externa.', 'Duplicates are not imported' => 'Los duplicados no son importados', - 'Usernames must be lowercase and unique' => 'Los nombres de usuario deben ser únicos y contener sólo minúsculas', + 'Usernames must be lowercase and unique' => 'Los nombres de usuario deben ser únicos y en minúsculas', 'Passwords will be encrypted if present' => 'Las contraseñas serán cifradas si es que existen', - '%s attached a new file to the task %s' => '%s adjuntó un nuevo archivo a la tarea %s', + '%s attached a new file to the task %s' => '%s adjuntó un nuevo archivo en la tarea %s', 'Link type' => 'Tipo de enlace', 'Assign automatically a category based on a link' => 'Asignar una categoría automáticamente basado en un enlace', - 'BAM - Konvertible Mark' => 'BAM - marco convertible', + 'BAM - Konvertible Mark' => 'BAM - Marco convertible', 'Assignee Username' => 'Nombre de usuario del responsable', 'Assignee Name' => 'Nombre del responsable', 'Groups' => 'Grupos', 'Members of %s' => 'Miembros de %s', 'New group' => 'Nuevo grupo', - 'Group created successfully.' => 'Grupo creado correctamente', - 'Unable to create your group.' => 'No es posible crear el grupo', + 'Group created successfully.' => 'Grupo creado correctamente.', + 'Unable to create your group.' => 'No es posible crear el grupo.', 'Edit group' => 'Modificar grupo', - 'Group updated successfully.' => 'Grupo actualizado correctamente', - 'Unable to update your group.' => 'No es posible actualizar el grupo', + 'Group updated successfully.' => 'Grupo actualizado correctamente.', + 'Unable to update your group.' => 'No es posible actualizar el grupo.', 'Add group member to "%s"' => 'Añadir un miembro del grupo a «%s»', - 'Group member added successfully.' => 'Miembro del grupo añadido correctamente', - 'Unable to add group member.' => 'No es posible añadir miembro del grupo', + 'Group member added successfully.' => 'Miembro del grupo añadido correctamente.', + 'Unable to add group member.' => 'No es posible añadir el miembro del grupo.', 'Remove user from group "%s"' => 'Eliminar usuario del grupo «%s»', - 'User removed successfully from this group.' => 'Usuario eliminado correctamente del grupo', - 'Unable to remove this user from the group.' => 'No es posible eliminar este usuario del grupo', + 'User removed successfully from this group.' => 'Usuario eliminado correctamente del grupo.', + 'Unable to remove this user from the group.' => 'No es posible eliminar este usuario del grupo.', 'Remove group' => 'Eliminar grupo', - 'Group removed successfully.' => 'Grupo eliminado correctamente', - 'Unable to remove this group.' => 'No es posible eliminar este grupo', + 'Group removed successfully.' => 'Grupo eliminado correctamente.', + 'Unable to remove this group.' => 'No es posible eliminar este grupo.', 'Project Permissions' => 'Permisos del proyecto', 'Manager' => 'Administrador', - 'Project Manager' => 'Administrador de proyecto', + 'Project Manager' => 'Administrador del proyecto', 'Project Member' => 'Miembro del proyecto', - 'Project Viewer' => 'Visor de proyectos', - 'Your account is locked for %d minutes' => 'Tu cuenta ha sido bloqueada por %d minuto(s)', + 'Project Viewer' => 'Observador del proyecto', + 'Your account is locked for %d minutes' => 'Tu cuenta ha sido bloqueada durante %d minutos', 'Invalid captcha' => 'CAPTCHA inválido', 'The name must be unique' => 'El nombre debe ser único', 'View all groups' => 'Ver todos los grupos', 'View group members' => 'Ver miembros del grupo', - 'There is no user available.' => 'No hay usuario disponible', - 'Do you really want to remove the user "%s" from the group "%s"?' => '¿Realmente desea eliminar el usuario "%s" del grupo «%s»?', - 'There is no group.' => 'No hay grupo', - 'External Id' => 'ID externo', - 'Add group member' => 'Añadir un miembro de grupo', + 'There is no user available.' => 'No hay usuario disponible.', + 'Do you really want to remove the user "%s" from the group "%s"?' => '¿Realmente desea eliminar el usuario «%s» del grupo «%s»?', + 'There is no group.' => 'No hay grupo.', + 'External Id' => 'Identificador externo', + 'Add group member' => 'Añadir un miembro al grupo', 'Do you really want to remove this group: "%s"?' => '¿Realmente desea eliminar este grupo: «%s»?', - 'There is no user in this group.' => 'No hay usuario en este grupo', + 'There is no user in this group.' => 'No hay usuario en este grupo.', 'Remove this user' => 'Eliminar este usuario', 'Permissions' => 'Permisos', 'Allowed Users' => 'Usuarios permitidos', - 'No user have been allowed specifically.' => 'Ningun usuario ha sido explícitamente permitido', + 'No user have been allowed specifically.' => 'Ningún usuario ha sido explícitamente permitido.', 'Role' => 'Rol', 'Enter user name...' => 'Ingresa nombre de usuario...', 'Allowed Groups' => 'Grupos permitidos', - 'No group have been allowed specifically.' => 'Ningun grupo ha sido explícitamente permitido', + 'No group have been allowed specifically.' => 'Ningún grupo ha sido explícitamente permitido.', 'Group' => 'Grupo', 'Group Name' => 'Nombre del grupo', 'Enter group name...' => 'Ingresa el nombre del grupo...', @@ -977,27 +977,27 @@ return array( 'Compare hours for "%s"' => 'Compara horas con «%s»', '%s mentioned you in the task #%d' => '%s te mencionó en la tarea #%d', '%s mentioned you in a comment on the task #%d' => '%s te mencionó en un comentario en la tarea #%d', - 'You were mentioned in the task #%d' => 'Te mencionaron en la tarea #%d', - 'You were mentioned in a comment on the task #%d' => 'Te mencionaron en un comentario en la tarea #%d', + 'You were mentioned in the task #%d' => 'Fuiste mencionado en la tarea #%d', + 'You were mentioned in a comment on the task #%d' => 'Fuiste mencionado en un comentario de la tarea #%d', 'Mentioned' => 'Mencionado', - 'Compare Estimated Time vs Actual Time' => 'Comparar Tiempo Estimado vs Tiempo Actual', + 'Compare Estimated Time vs Actual Time' => 'Comparar tiempo estimado vs tiempo actual', 'Estimated hours: ' => 'Horas estimadas: ', 'Actual hours: ' => 'Horas actuales: ', 'Hours Spent' => 'Horas gastadas', - 'Hours Estimated' => 'Hora Estimada', - 'Estimated Time' => 'Tiempo Estimado', - 'Actual Time' => 'Tiempo Actual', + 'Hours Estimated' => 'Horas estimadas', + 'Estimated Time' => 'Tiempo estimado', + 'Actual Time' => 'Tiempo actual', 'Estimated vs actual time' => 'Tiempo estimado vs real', - 'RUB - Russian Ruble' => 'RUB - rublo ruso', - 'Assign the task to the person who does the action when the column is changed' => 'Asignar la tarea a la persona que haga la acción al cambiar de columna', + 'RUB - Russian Ruble' => 'RUB - Rublo ruso', + 'Assign the task to the person who does the action when the column is changed' => 'Asignar la tarea a la persona que hace la acción al cambiar de columna', 'Close a task in a specific column' => 'Cerrar tarea en una columna especifica', 'Time-based One-time Password Algorithm' => 'Algoritmo basado en tiempo de un solo uso', - 'Two-Factor Provider: ' => 'Proveedor de autenticación de dos factores', - 'Disable two-factor authentication' => 'Deshabilitar autenticación de dos factores', - 'Enable two-factor authentication' => 'Habilitar autenticación de dos factorse', - 'There is no integration registered at the moment.' => 'No hay ninguna integración registrada por el momento', + 'Two-Factor Provider: ' => 'Proveedor de autenticación en dos pasos: ', + 'Disable two-factor authentication' => 'Deshabilitar autenticación en dos pasos', + 'Enable two-factor authentication' => 'Habilitar autenticación en dos pasos', + 'There is no integration registered at the moment.' => 'No hay ninguna integración registrada por el momento.', 'Password Reset for Kanboard' => 'Restablecimiento de contraseña para Kanboard', - 'Forgot password?' => '¿Olvidó contraseña?', + 'Forgot password?' => '¿Olvidó la contraseña?', 'Enable "Forget Password"' => 'Habilitar "olvidar contraseña"', 'Password Reset' => 'Restablecer contraseña', 'New password' => 'Nueva contraseña', @@ -1008,19 +1008,19 @@ return array( 'Creation' => 'Creación', 'Expiration' => 'Vencimiento', 'Password reset history' => 'Historial de restablecimiento de contraseña', - 'All tasks of the column "%s" and the swimlane "%s" have been closed successfully.' => 'Todas las tareas de la columna "%s" y el swimlane «%s» se han cerrado correctamente', + 'All tasks of the column "%s" and the swimlane "%s" have been closed successfully.' => 'Todas las tareas de la columna "%s" y la calle «%s» se han cerrado correctamente.', 'Do you really want to close all tasks of this column?' => '¿Realmente desea cerrar todas las tareas de esta columna?', - '%d task(s) in the column "%s" and the swimlane "%s" will be closed.' => '%d tarea(s) en la columna "%s" y el swimlane «%s» será(n) cerrada(s)', + '%d task(s) in the column "%s" and the swimlane "%s" will be closed.' => '%d tarea(s) en la columna "%s" y en la calle «%s» será(n) cerrada(s).', 'Close all tasks of this column' => 'Cerrar todas las tareas de esta columna', - 'No plugin has registered a project notification method. You can still configure individual notifications in your user profile.' => 'Ningún plugin ha registrado un método de notificación para el proyecto. Aún puedes configurar notificaciones individuales en tu perfil de usuario', + 'No plugin has registered a project notification method. You can still configure individual notifications in your user profile.' => 'Ningún plugin ha registrado un método de notificación para el proyecto. Aún puedes configurar notificaciones individuales en tu perfil de usuario.', 'My dashboard' => 'Mi tablero', 'My profile' => 'Mi perfil', - 'Project owner: ' => 'Dueño del proyecto', - 'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => 'El identificador de proyecto es opcional y debe ser alfanumérico. Ejemplo: MIPROYECTO', - 'Project owner' => 'Dueño del proyecto', - 'Those dates are useful for the project Gantt chart.' => 'Esas fechas son útiles para el diagrama de Gantt', - 'Private projects do not have users and groups management.' => 'Proyectos privados no cuentan con gestión de usuarios y grupos', - 'There is no project member.' => 'No existe miembro del proyecto', + 'Project owner: ' => 'Propietario del proyecto: ', + 'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => 'El identificador del proyecto es opcional y debe ser alfanumérico. Ejemplo: MIPROYECTO', + 'Project owner' => 'Propietario del proyecto', + 'Those dates are useful for the project Gantt chart.' => 'Esas fechas son útiles para el diagrama de Gantt.', + 'Private projects do not have users and groups management.' => 'Los proyectos privados no cuentan con gestión de usuarios y grupos.', + 'There is no project member.' => 'No existe miembro del proyecto.', 'Priority' => 'Prioridad', 'Task priority' => 'Prioridad de la tarea', 'General' => 'General', @@ -1028,16 +1028,16 @@ return array( 'Default priority' => 'Prioridad predeterminada', 'Lowest priority' => 'Prioridad más baja', 'Highest priority' => 'Prioridad más alta', - 'If you put zero to the low and high priority, this feature will be disabled.' => 'Si estableces la prioridad más baja y alta como cero esta función será deshabilitada', + 'If you put zero to the low and high priority, this feature will be disabled.' => 'Si estableces la prioridad más baja y más alta a cero esta función será deshabilitada.', 'Close a task when there is no activity' => 'Cerrar tarea cuando no haya actividad', 'Duration in days' => 'Duración en días', 'Send email when there is no activity on a task' => 'Enviar correo cuando no haya actividad en una tarea', - 'Unable to fetch link information.' => 'No es posible obtener información sobre el enlace', - 'Daily background job for tasks' => 'Tarea de fondo diaria para las tareas', + 'Unable to fetch link information.' => 'No es posible obtener información del enlace.', + 'Daily background job for tasks' => 'Trabajo en segundo plano diario para las tareas', 'Auto' => 'Automático', 'Related' => 'Relacionado', 'Attachment' => 'Adjunto', - 'Title not found' => 'Título no ha sido encontrado', + 'Title not found' => 'No se ha encontrado el título', 'Web Link' => 'Enlace web', 'External links' => 'Enlaces externos', 'Add external link' => 'Añadir enlace externo', @@ -1050,50 +1050,50 @@ return array( 'Copy and paste your link here...' => 'Copia y pega tu enlace aquí...', 'URL' => 'URL', 'Internal links' => 'Enlaces internos', - 'Assign to me' => 'Asignar a mí', + 'Assign to me' => 'Asignarme a mí', 'Me' => 'Yo', 'Do not duplicate anything' => 'No duplicar nada', 'Projects management' => 'Administración de proyectos', 'Users management' => 'Administración de usuarios', 'Groups management' => 'Administración de grupos', - 'Create from another project' => 'Crear de otro proyecto', + 'Create from another project' => 'Crear a partir de otro proyecto', 'open' => 'abierto', 'closed' => 'cerrado', - 'Priority:' => 'Prioridad', - 'Reference:' => 'Referencia', + 'Priority:' => 'Prioridad:', + 'Reference:' => 'Referencia:', 'Complexity:' => 'Complejidad:', - 'Swimlane:' => 'Swimlane:', + 'Swimlane:' => 'Calle:', 'Column:' => 'Columna:', 'Position:' => 'Posición:', 'Creator:' => 'Creador:', 'Time estimated:' => 'Tiempo estimado:', '%s hours' => '%s horas', 'Time spent:' => 'Tiempo gastado:', - 'Created:' => 'Creado', - 'Modified:' => 'Modificado', - 'Completed:' => 'Terminado', - 'Started:' => 'Iniciado', - 'Moved:' => 'Movido', + 'Created:' => 'Creado:', + 'Modified:' => 'Modificado:', + 'Completed:' => 'Finalizado:', + 'Started:' => 'Iniciado:', + 'Moved:' => 'Movido:', 'Task #%d' => 'Tarea #%d', - 'Date and time format' => 'Formato de hora y fecha', + 'Date and time format' => 'Formato de fecha y hora', 'Time format' => 'Formato de hora', - 'Start date: ' => 'Fecha de inicio', - 'End date: ' => 'Fecha de terminación', - 'New due date: ' => 'Nueva fecha de entrega', - 'Start date changed: ' => 'Fecha de inicio cambiada', + 'Start date: ' => 'Fecha de inicio: ', + 'End date: ' => 'Fecha de finalización: ', + 'New due date: ' => 'Nueva fecha de entrega: ', + 'Start date changed: ' => 'Fecha de inicio cambiada: ', 'Disable private projects' => 'Deshabilitar proyectos privados', 'Do you really want to remove this custom filter: "%s"?' => '¿Realmente desea eliminar este filtro personalizado: «%s»?', - 'Remove a custom filter' => 'Eliminar filtro personalizado', - 'User activated successfully.' => 'Usuario activado correctamente', - 'Unable to enable this user.' => 'No es posible habilitar este usuario', - 'User disabled successfully.' => 'Usuario deshabilitado correctamente', - 'Unable to disable this user.' => 'No es posible deshabilitar este usuario', - 'All files have been uploaded successfully.' => 'Todos los archivos han sido subidos correctamente', - 'View uploaded files' => 'Ver archivos subidos', - 'The maximum allowed file size is %sB.' => 'El límite de tamaño de archivo permitido para subir es %sB.', - 'Choose files again' => 'Eligir archivos de nuevo', + 'Remove a custom filter' => 'Eliminar el filtro personalizado', + 'User activated successfully.' => 'Usuario activado correctamente.', + 'Unable to enable this user.' => 'No es posible habilitar este usuario.', + 'User disabled successfully.' => 'Usuario deshabilitado correctamente.', + 'Unable to disable this user.' => 'No es posible deshabilitar este usuario.', + 'All files have been uploaded successfully.' => 'Todos los archivos han sido cargados correctamente.', + 'View uploaded files' => 'Ver archivos cargados', + 'The maximum allowed file size is %sB.' => 'El tamaño máximo de archivo es %sB.', + 'Choose files again' => 'Elegir archivos de nuevo', 'Drag and drop your files here' => 'Arrastra y suelta tus archivos aquí', - 'choose files' => 'Elegir archivos', + 'choose files' => 'elegir archivos', 'View profile' => 'Ver perfil', 'Two Factor' => 'Dos factores', 'Disable user' => 'Deshabilitar usuario', @@ -1113,16 +1113,16 @@ return array( 'Change column position' => 'Cambiar posición de la columna', 'Switch to the project overview' => 'Cambiar a vista general del proyecto', 'User filters' => 'Usar filtros', - 'Category filters' => 'Categoría y filtros', - 'Upload a file' => 'Subir archivo', + 'Category filters' => 'Filtros de categoría', + 'Upload a file' => 'Cargar archivo', 'View file' => 'Ver archivo', 'Last activity' => 'Última actividad', 'Change subtask position' => 'Cambiar posición de la subtarea', 'This value must be greater than %d' => 'Este valor debe ser mayor que %d', - 'Another swimlane with the same name exists in the project' => 'Ya existe otro swimlane con el mismo nombre en el proyecto', - 'Example: http://example.kanboard.net/ (used to generate absolute URLs)' => 'Ejemplo: http://ejemplo.kanboard.net/ (Usado para generar URLs absolutas)', - 'Actions duplicated successfully.' => 'Acción duplicada con exito.', - 'Unable to duplicate actions.' => 'No se ha podido duplicar la acción.', + 'Another swimlane with the same name exists in the project' => 'Ya existe otra calle con el mismo nombre en el proyecto', + 'Example: http://example.kanboard.net/ (used to generate absolute URLs)' => 'Ejemplo: http://ejemplo.kanboard.net/ (usado para generar URLs absolutas)', + 'Actions duplicated successfully.' => 'Acciones duplicadas con éxito.', + 'Unable to duplicate actions.' => 'No se han podido duplicar las acciones.', 'Add a new action' => 'Añadir una nueva acción', 'Import from another project' => 'Importar de otro proyecto', 'There is no action at the moment.' => 'No hay ninguna acción en este momento.', -- cgit v1.2.3 From 75019b3a8e838f51bfac51bdbf9e6647faaaec1d Mon Sep 17 00:00:00 2001 From: Frederic Guillot Date: Thu, 23 Jun 2016 12:27:34 -0400 Subject: Make embedded documentation available in multiple languages --- ChangeLog | 7 ++ app/Controller/DocumentationController.php | 70 +++++++++-- doc/es_ES/kanban-vs-todo-and-scrum.markdown | 22 ++-- doc/fr/2fa.markdown | 33 ----- doc/fr/analytics-tasks.markdown | 24 ---- doc/fr/analytics.markdown | 70 ----------- doc/fr/application-configuration.markdown | 41 ------- doc/fr/application-configuration.markup | 41 ------- doc/fr/automatic-actions.markdown | 133 --------------------- doc/fr/board-collapsed-expanded.markdown | 18 --- doc/fr/board-configuration.markdown | 24 ---- ...-horizontal-scrolling-and-compact-view.markdown | 11 -- doc/fr/board-show-hide-columns.markdown | 12 -- doc/fr/calendar-configuration.markdown | 43 ------- doc/fr/calendar.markdown | 20 ---- doc/fr/closing-tasks.markdown | 16 --- doc/fr/create-tasks-by-email.markdown | 45 ------- doc/fr/creating-projects.markdown | 39 ------ doc/fr/creating-tasks.markdown | 27 ----- doc/fr/currency-rate.markdown | 11 -- doc/fr/duplicate-move-tasks.markdown | 58 --------- doc/fr/editing-projects.markdown | 15 --- doc/fr/gantt-chart-projects.markdown | 17 --- doc/fr/gantt-chart-tasks.markdown | 20 ---- doc/fr/index.markdown | 63 ---------- doc/fr/kanban-vs-todo-and-scrum.markdown | 36 ------ doc/fr/keyboard-shortcuts.markdown | 37 ------ doc/fr/link-labels.markdown | 13 -- doc/fr/notifications.markdown | 45 ------- doc/fr/project-configuration.markdown | 42 ------- doc/fr/project-permissions.markdown | 22 ---- doc/fr/project-types.markdown | 14 --- doc/fr/project-views.markdown | 61 ---------- doc/fr/recurring-tasks.markdown | 24 ---- doc/fr/roles.markdown | 24 ---- doc/fr/screenshots.markdown | 26 ---- doc/fr/screenshots/automatic-action-creation.png | Bin 19900 -> 0 bytes doc/fr/screenshots/board-collapsed-mode.png | Bin 7074 -> 0 bytes doc/fr/screenshots/board-compact-mode.png | Bin 12765 -> 0 bytes doc/fr/screenshots/board-expanded-mode.png | Bin 11783 -> 0 bytes doc/fr/screenshots/board-task-limit.png | Bin 16848 -> 0 bytes doc/fr/screenshots/board-view.png | Bin 24371 -> 0 bytes doc/fr/screenshots/calendar-view.png | Bin 21691 -> 0 bytes doc/fr/screenshots/gantt-view.png | Bin 29367 -> 0 bytes doc/fr/screenshots/hide-column.png | Bin 9642 -> 0 bytes doc/fr/screenshots/list-view.png | Bin 23457 -> 0 bytes doc/fr/screenshots/new-project.png | Bin 20818 -> 0 bytes doc/fr/screenshots/new-user.png | Bin 26286 -> 0 bytes doc/fr/screenshots/project-disable-sharing.png | Bin 17706 -> 0 bytes doc/fr/screenshots/project-edition.png | Bin 40230 -> 0 bytes doc/fr/screenshots/project-enable-sharing.png | Bin 14297 -> 0 bytes doc/fr/screenshots/project-permissions.png | Bin 32926 -> 0 bytes doc/fr/screenshots/project-view.png | Bin 40868 -> 0 bytes doc/fr/screenshots/show-column.png | Bin 17940 -> 0 bytes doc/fr/screenshots/swimlane-configuration.png | Bin 14226 -> 0 bytes doc/fr/screenshots/swimlanes.png | Bin 25290 -> 0 bytes doc/fr/sharing-projects.markdown | 35 ------ doc/fr/subtasks.markdown | 43 ------- doc/fr/swimlanes.markdown | 29 ----- doc/fr/task-links.markdown | 22 ---- doc/fr/time-tracking.markdown | 44 ------- doc/fr/transitions.markdown | 20 ---- doc/fr/usage-examples.markdown | 69 ----------- doc/fr/user-management.markdown | 35 ------ doc/fr/what-is-kanban.markdown | 34 ------ doc/fr_FR/2fa.markdown | 33 +++++ doc/fr_FR/analytics-tasks.markdown | 24 ++++ doc/fr_FR/analytics.markdown | 70 +++++++++++ doc/fr_FR/application-configuration.markdown | 41 +++++++ doc/fr_FR/application-configuration.markup | 41 +++++++ doc/fr_FR/automatic-actions.markdown | 133 +++++++++++++++++++++ doc/fr_FR/board-collapsed-expanded.markdown | 18 +++ doc/fr_FR/board-configuration.markdown | 24 ++++ ...-horizontal-scrolling-and-compact-view.markdown | 11 ++ doc/fr_FR/board-show-hide-columns.markdown | 12 ++ doc/fr_FR/calendar-configuration.markdown | 43 +++++++ doc/fr_FR/calendar.markdown | 20 ++++ doc/fr_FR/closing-tasks.markdown | 16 +++ doc/fr_FR/create-tasks-by-email.markdown | 45 +++++++ doc/fr_FR/creating-projects.markdown | 39 ++++++ doc/fr_FR/creating-tasks.markdown | 27 +++++ doc/fr_FR/currency-rate.markdown | 11 ++ doc/fr_FR/duplicate-move-tasks.markdown | 58 +++++++++ doc/fr_FR/editing-projects.markdown | 15 +++ doc/fr_FR/gantt-chart-projects.markdown | 17 +++ doc/fr_FR/gantt-chart-tasks.markdown | 20 ++++ doc/fr_FR/index.markdown | 63 ++++++++++ doc/fr_FR/kanban-vs-todo-and-scrum.markdown | 36 ++++++ doc/fr_FR/keyboard-shortcuts.markdown | 37 ++++++ doc/fr_FR/link-labels.markdown | 13 ++ doc/fr_FR/notifications.markdown | 45 +++++++ doc/fr_FR/project-configuration.markdown | 42 +++++++ doc/fr_FR/project-permissions.markdown | 22 ++++ doc/fr_FR/project-types.markdown | 14 +++ doc/fr_FR/project-views.markdown | 61 ++++++++++ doc/fr_FR/recurring-tasks.markdown | 24 ++++ doc/fr_FR/roles.markdown | 24 ++++ doc/fr_FR/screenshots.markdown | 26 ++++ .../screenshots/automatic-action-creation.png | Bin 0 -> 19900 bytes doc/fr_FR/screenshots/board-collapsed-mode.png | Bin 0 -> 7074 bytes doc/fr_FR/screenshots/board-compact-mode.png | Bin 0 -> 12765 bytes doc/fr_FR/screenshots/board-expanded-mode.png | Bin 0 -> 11783 bytes doc/fr_FR/screenshots/board-task-limit.png | Bin 0 -> 16848 bytes doc/fr_FR/screenshots/board-view.png | Bin 0 -> 24371 bytes doc/fr_FR/screenshots/calendar-view.png | Bin 0 -> 21691 bytes doc/fr_FR/screenshots/gantt-view.png | Bin 0 -> 29367 bytes doc/fr_FR/screenshots/hide-column.png | Bin 0 -> 9642 bytes doc/fr_FR/screenshots/list-view.png | Bin 0 -> 23457 bytes doc/fr_FR/screenshots/new-project.png | Bin 0 -> 20818 bytes doc/fr_FR/screenshots/new-user.png | Bin 0 -> 26286 bytes doc/fr_FR/screenshots/project-disable-sharing.png | Bin 0 -> 17706 bytes doc/fr_FR/screenshots/project-edition.png | Bin 0 -> 40230 bytes doc/fr_FR/screenshots/project-enable-sharing.png | Bin 0 -> 14297 bytes doc/fr_FR/screenshots/project-permissions.png | Bin 0 -> 32926 bytes doc/fr_FR/screenshots/project-view.png | Bin 0 -> 40868 bytes doc/fr_FR/screenshots/show-column.png | Bin 0 -> 17940 bytes doc/fr_FR/screenshots/swimlane-configuration.png | Bin 0 -> 14226 bytes doc/fr_FR/screenshots/swimlanes.png | Bin 0 -> 25290 bytes doc/fr_FR/sharing-projects.markdown | 35 ++++++ doc/fr_FR/subtasks.markdown | 43 +++++++ doc/fr_FR/swimlanes.markdown | 29 +++++ doc/fr_FR/task-links.markdown | 22 ++++ doc/fr_FR/time-tracking.markdown | 44 +++++++ doc/fr_FR/transitions.markdown | 20 ++++ doc/fr_FR/usage-examples.markdown | 69 +++++++++++ doc/fr_FR/user-management.markdown | 35 ++++++ doc/fr_FR/what-is-kanban.markdown | 34 ++++++ 127 files changed, 1531 insertions(+), 1480 deletions(-) delete mode 100644 doc/fr/2fa.markdown delete mode 100644 doc/fr/analytics-tasks.markdown delete mode 100644 doc/fr/analytics.markdown delete mode 100644 doc/fr/application-configuration.markdown delete mode 100644 doc/fr/application-configuration.markup delete mode 100644 doc/fr/automatic-actions.markdown delete mode 100644 doc/fr/board-collapsed-expanded.markdown delete mode 100644 doc/fr/board-configuration.markdown delete mode 100644 doc/fr/board-horizontal-scrolling-and-compact-view.markdown delete mode 100644 doc/fr/board-show-hide-columns.markdown delete mode 100644 doc/fr/calendar-configuration.markdown delete mode 100644 doc/fr/calendar.markdown delete mode 100644 doc/fr/closing-tasks.markdown delete mode 100644 doc/fr/create-tasks-by-email.markdown delete mode 100644 doc/fr/creating-projects.markdown delete mode 100644 doc/fr/creating-tasks.markdown delete mode 100644 doc/fr/currency-rate.markdown delete mode 100644 doc/fr/duplicate-move-tasks.markdown delete mode 100644 doc/fr/editing-projects.markdown delete mode 100644 doc/fr/gantt-chart-projects.markdown delete mode 100644 doc/fr/gantt-chart-tasks.markdown delete mode 100644 doc/fr/index.markdown delete mode 100644 doc/fr/kanban-vs-todo-and-scrum.markdown delete mode 100644 doc/fr/keyboard-shortcuts.markdown delete mode 100644 doc/fr/link-labels.markdown delete mode 100644 doc/fr/notifications.markdown delete mode 100644 doc/fr/project-configuration.markdown delete mode 100644 doc/fr/project-permissions.markdown delete mode 100644 doc/fr/project-types.markdown delete mode 100644 doc/fr/project-views.markdown delete mode 100644 doc/fr/recurring-tasks.markdown delete mode 100644 doc/fr/roles.markdown delete mode 100644 doc/fr/screenshots.markdown delete mode 100644 doc/fr/screenshots/automatic-action-creation.png delete mode 100644 doc/fr/screenshots/board-collapsed-mode.png delete mode 100644 doc/fr/screenshots/board-compact-mode.png delete mode 100644 doc/fr/screenshots/board-expanded-mode.png delete mode 100644 doc/fr/screenshots/board-task-limit.png delete mode 100644 doc/fr/screenshots/board-view.png delete mode 100644 doc/fr/screenshots/calendar-view.png delete mode 100644 doc/fr/screenshots/gantt-view.png delete mode 100644 doc/fr/screenshots/hide-column.png delete mode 100644 doc/fr/screenshots/list-view.png delete mode 100644 doc/fr/screenshots/new-project.png delete mode 100644 doc/fr/screenshots/new-user.png delete mode 100644 doc/fr/screenshots/project-disable-sharing.png delete mode 100644 doc/fr/screenshots/project-edition.png delete mode 100644 doc/fr/screenshots/project-enable-sharing.png delete mode 100644 doc/fr/screenshots/project-permissions.png delete mode 100644 doc/fr/screenshots/project-view.png delete mode 100644 doc/fr/screenshots/show-column.png delete mode 100644 doc/fr/screenshots/swimlane-configuration.png delete mode 100644 doc/fr/screenshots/swimlanes.png delete mode 100644 doc/fr/sharing-projects.markdown delete mode 100644 doc/fr/subtasks.markdown delete mode 100644 doc/fr/swimlanes.markdown delete mode 100644 doc/fr/task-links.markdown delete mode 100644 doc/fr/time-tracking.markdown delete mode 100644 doc/fr/transitions.markdown delete mode 100644 doc/fr/usage-examples.markdown delete mode 100644 doc/fr/user-management.markdown delete mode 100644 doc/fr/what-is-kanban.markdown create mode 100644 doc/fr_FR/2fa.markdown create mode 100644 doc/fr_FR/analytics-tasks.markdown create mode 100644 doc/fr_FR/analytics.markdown create mode 100644 doc/fr_FR/application-configuration.markdown create mode 100644 doc/fr_FR/application-configuration.markup create mode 100644 doc/fr_FR/automatic-actions.markdown create mode 100644 doc/fr_FR/board-collapsed-expanded.markdown create mode 100644 doc/fr_FR/board-configuration.markdown create mode 100644 doc/fr_FR/board-horizontal-scrolling-and-compact-view.markdown create mode 100644 doc/fr_FR/board-show-hide-columns.markdown create mode 100644 doc/fr_FR/calendar-configuration.markdown create mode 100644 doc/fr_FR/calendar.markdown create mode 100644 doc/fr_FR/closing-tasks.markdown create mode 100644 doc/fr_FR/create-tasks-by-email.markdown create mode 100644 doc/fr_FR/creating-projects.markdown create mode 100644 doc/fr_FR/creating-tasks.markdown create mode 100644 doc/fr_FR/currency-rate.markdown create mode 100644 doc/fr_FR/duplicate-move-tasks.markdown create mode 100644 doc/fr_FR/editing-projects.markdown create mode 100644 doc/fr_FR/gantt-chart-projects.markdown create mode 100644 doc/fr_FR/gantt-chart-tasks.markdown create mode 100644 doc/fr_FR/index.markdown create mode 100644 doc/fr_FR/kanban-vs-todo-and-scrum.markdown create mode 100644 doc/fr_FR/keyboard-shortcuts.markdown create mode 100644 doc/fr_FR/link-labels.markdown create mode 100644 doc/fr_FR/notifications.markdown create mode 100644 doc/fr_FR/project-configuration.markdown create mode 100644 doc/fr_FR/project-permissions.markdown create mode 100644 doc/fr_FR/project-types.markdown create mode 100644 doc/fr_FR/project-views.markdown create mode 100644 doc/fr_FR/recurring-tasks.markdown create mode 100644 doc/fr_FR/roles.markdown create mode 100644 doc/fr_FR/screenshots.markdown create mode 100644 doc/fr_FR/screenshots/automatic-action-creation.png create mode 100644 doc/fr_FR/screenshots/board-collapsed-mode.png create mode 100644 doc/fr_FR/screenshots/board-compact-mode.png create mode 100644 doc/fr_FR/screenshots/board-expanded-mode.png create mode 100644 doc/fr_FR/screenshots/board-task-limit.png create mode 100644 doc/fr_FR/screenshots/board-view.png create mode 100644 doc/fr_FR/screenshots/calendar-view.png create mode 100644 doc/fr_FR/screenshots/gantt-view.png create mode 100644 doc/fr_FR/screenshots/hide-column.png create mode 100644 doc/fr_FR/screenshots/list-view.png create mode 100644 doc/fr_FR/screenshots/new-project.png create mode 100644 doc/fr_FR/screenshots/new-user.png create mode 100644 doc/fr_FR/screenshots/project-disable-sharing.png create mode 100644 doc/fr_FR/screenshots/project-edition.png create mode 100644 doc/fr_FR/screenshots/project-enable-sharing.png create mode 100644 doc/fr_FR/screenshots/project-permissions.png create mode 100644 doc/fr_FR/screenshots/project-view.png create mode 100644 doc/fr_FR/screenshots/show-column.png create mode 100644 doc/fr_FR/screenshots/swimlane-configuration.png create mode 100644 doc/fr_FR/screenshots/swimlanes.png create mode 100644 doc/fr_FR/sharing-projects.markdown create mode 100644 doc/fr_FR/subtasks.markdown create mode 100644 doc/fr_FR/swimlanes.markdown create mode 100644 doc/fr_FR/task-links.markdown create mode 100644 doc/fr_FR/time-tracking.markdown create mode 100644 doc/fr_FR/transitions.markdown create mode 100644 doc/fr_FR/usage-examples.markdown create mode 100644 doc/fr_FR/user-management.markdown create mode 100644 doc/fr_FR/what-is-kanban.markdown (limited to 'app') diff --git a/ChangeLog b/ChangeLog index ebd6e38e..20ffbca1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +Version 1.0.31 (unreleased) +-------------- + +Improvements: + +* Make embedded documentation available in multiple languages + Version 1.0.30 -------------- diff --git a/app/Controller/DocumentationController.php b/app/Controller/DocumentationController.php index d86fb3c8..0d02ebda 100644 --- a/app/Controller/DocumentationController.php +++ b/app/Controller/DocumentationController.php @@ -20,16 +20,7 @@ class DocumentationController extends BaseController $page = 'index'; } - if ($this->languageModel->getCurrentLanguage() === 'fr_FR') { - $filename = __DIR__.'/../../doc/fr/' . $page . '.markdown'; - } else { - $filename = __DIR__ . '/../../doc/' . $page . '.markdown'; - } - - if (!file_exists($filename)) { - $filename = __DIR__.'/../../doc/index.markdown'; - } - + $filename = $this->getPageFilename($page); $this->response->html($this->helper->layout->app('doc/show', $this->render($filename))); } @@ -83,10 +74,63 @@ class DocumentationController extends BaseController */ public function replaceImageUrl(array $matches) { - if ($this->languageModel->getCurrentLanguage() === 'fr_FR') { - return '('.$this->helper->url->base().'doc/fr/'.$matches[1].')'; + return '('.$this->getFileBaseUrl($matches[1]).')'; + } + + /** + * Get Markdown file according to the current language + * + * @access private + * @param string $page + * @return string + */ + private function getPageFilename($page) + { + return $this->getFileLocation($page . '.markdown') ?: + implode(DIRECTORY_SEPARATOR, array(ROOT_DIR, 'doc', 'index.markdown')); + } + + /** + * Get base URL for Markdown links + * + * @access private + * @param string $filename + * @return string + */ + private function getFileBaseUrl($filename) + { + $language = $this->languageModel->getCurrentLanguage(); + $path = $this->getFileLocation($filename); + + if (strpos($path, $language) !== false) { + $url = implode('/', array('doc', $language, $filename)); + } else { + $url = implode('/', array('doc', $filename)); + } + + return $this->helper->url->base().$url; + } + + /** + * Get file location according to the current language + * + * @access private + * @param string $filename + * @return string + */ + private function getFileLocation($filename) + { + $files = array( + implode(DIRECTORY_SEPARATOR, array(ROOT_DIR, 'doc', $this->languageModel->getCurrentLanguage(), $filename)), + implode(DIRECTORY_SEPARATOR, array(ROOT_DIR, 'doc', $filename)), + ); + + foreach ($files as $filename) { + if (file_exists($filename)) { + return $filename; + } } - return '('.$this->helper->url->base().'doc/'.$matches[1].')'; + return ''; } } diff --git a/doc/es_ES/kanban-vs-todo-and-scrum.markdown b/doc/es_ES/kanban-vs-todo-and-scrum.markdown index ad9dd1a9..6e8d9e6c 100644 --- a/doc/es_ES/kanban-vs-todo-and-scrum.markdown +++ b/doc/es_ES/kanban-vs-todo-and-scrum.markdown @@ -6,13 +6,13 @@ Kanban vs Todo lists ### Todo lists (lista de tareas) : -Fase unica (es solo una lista de tareas) -Multitarea posible (no eficiente) +- Fase unica (es solo una lista de tareas) +- Multitarea posible (no eficiente) ### Kanban: -Multi fases, -Concentración absoluta para evitar multitareas por que se puede establecer un limite por columna para mejorar el progreso +- Multi fases, +- Concentración absoluta para evitar multitareas por que se puede establecer un limite por columna para mejorar el progreso Kanban vs Scrum @@ -20,13 +20,13 @@ Kanban vs Scrum ### Scrum: -Los sprints son time-boxed, usualmente 2 o 4 semanas -No permitir cambios durante la iteración -La estimación es requerida -Utiliza la velocidad como métrica predeterminada -El tablero de Scrum se borra entre cada sprint -Scrum tiene funciones predefinidas como scrum master , los dueños del producto y el equipo -Una gran cantidad de reuniones: planeaciones, backlogs grooming, daily stand-up, retrospectiva +- Los sprints son time-boxed, usualmente 2 o 4 semanas +- No permitir cambios durante la iteración +- La estimación es requerida +- Utiliza la velocidad como métrica predeterminada +- El tablero de Scrum se borra entre cada sprint +- Scrum tiene funciones predefinidas como scrum master , los dueños del producto y el equipo +- Una gran cantidad de reuniones: planeaciones, backlogs grooming, daily stand-up, retrospectiva ### Kanban: diff --git a/doc/fr/2fa.markdown b/doc/fr/2fa.markdown deleted file mode 100644 index 2ecaa10b..00000000 --- a/doc/fr/2fa.markdown +++ /dev/null @@ -1,33 +0,0 @@ -Authentification à deux facteurs -========================= - -Chaque utilisateur peut activer [l'authentification à deux facteurs](http://en.wikipedia.org/wiki/Two_factor_authentication). -Après s’être connecté, un code à usage unique (6 caractères) est demandé à l'utilisateur pour lui autoriser l’accès à Kanboard. - -Ce code doit être fourni par un logiciel compatible, généralement installé sur votre smartphone. - -Kanboard utilise le [Time-based One-time Password Algorithm](http://en.wikipedia.org/wiki/Time-based_One-time_Password_Algorithm) défini dans la [RFC 6238](http://tools.ietf.org/html/rfc6238). - -Il existe de nombreux logiciels compatibles avec le standard TOTP system. -Par exemple, vous pouvez utilisez ces applications libres et open source : - -- [Google Authenticator](https://github.com/google/google-authenticator/) (Android, iOS, Blackberry) -- [FreeOTP](https://fedorahosted.org/freeotp/) (Android, iOS) -- [OATH Toolkit](http://www.nongnu.org/oath-toolkit/) (utilitaire en ligne de commande sur Unix/Linux) - -Ce système peut fonctionner hors ligne et vous n'avez pas l'obligation d'avoir un téléphone portable. - -Paramétrage ------ - -1. Allez dans le profil utilisateur. -2. Sur la gauche, cliquez sur **Authentification à deux facteurs** et cochez la case. -3. Une clef secrète est générée pour vous. - -![2FA](https://kanboard.net/screenshots/documentation/2fa.png) - -- Vous devez sauvegarder votre clef dans votre logiciel TOTP. Si vous utilisez un smartphone, la solution la plus simple est de scanner le QR code avec FreeOTP ou Google Authenticator -- À chaque ouverture de session, un nouveau code sera demandé -- N'oubliez pas de tester votre appareil avant de quitter votre session - -Une nouvelle clef est générée à chaque fois que vous activez/désactivez cette fonction diff --git a/doc/fr/analytics-tasks.markdown b/doc/fr/analytics-tasks.markdown deleted file mode 100644 index 0eb89e34..00000000 --- a/doc/fr/analytics-tasks.markdown +++ /dev/null @@ -1,24 +0,0 @@ -Analytique des tâches -=================== - -Chaque tâche possède une section analytique accessible à partir du menu à gauche dans la page des tâches - -Lead et cycle time -------------------- - -![Lead and cycle time](https://kanboard.net/screenshots/documentation/task-lead-cycle-time.png) - -- Le lead time est la durée entre la création de la tâche et son achèvement (tâche fermée). -- Le cycle time est la durée entre la date de début et l'achèvement. -- Si la tâche n’est pas fermée, l’heure courante est utilisée à la place de la date d'achèvement. -- Si la date de départ n'est pas spécifiée, le cycle time n'est pas calculé. - -Remarque : vous pouvez configurer une action pour définir automatiquement que la date de départ sera le moment où vous déplacez une tâche vers une colonne de votre choix - -Temps passé dans chaque colonne ---------------------------- - -![Temps passé dans chaque colonne](https://kanboard.net/screenshots/documentation/time-into-each-column.png) - -- Ce graphique montre le temps total passé dans chaque colonne pour la tâche -- Le temps passé est calculé jusqu’à ce que la tâche soit fermée diff --git a/doc/fr/analytics.markdown b/doc/fr/analytics.markdown deleted file mode 100644 index 0b94f272..00000000 --- a/doc/fr/analytics.markdown +++ /dev/null @@ -1,70 +0,0 @@ -Analytique -========= - -Chaque projet dispose d'une section analytique. En fonction de la façon dont vous utilisez Kanboard, vous pourrez voir les rapports suivants : - -Répartition des utilisateurs ----------------- - -![Répartition des utilisateurs](https://kanboard.net/screenshots/documentation/user-repartition.png) - -Ce graphique circulaire affiche le nombre de tâches assignées par utilisateur. - -Distribution des tâches ------------------ - -![Distribution des tâches](https://kanboard.net/screenshots/documentation/task-distribution.png) - -Ce graphique circulaire donne une vue d'ensemble du nombre de tâches ouvertes par colonne. - -Diagramme de flux cumulé ------------------------ - -![Diagramme de flux cumulé](https://kanboard.net/screenshots/documentation/cfd.png) - -- Ce graphique affiche le nombre de tâches de façon cumulée pour chaque colonne en fonction du temps passé. -- Chaque jour, le nombre total de tâches est enregistré pour chaque colonne. -- Si vous souhaitez exclure les tâches terminées, modifiez les [paramètres du projet global](project-configuration.markdown). - -Remarque : il faut au moins deux jours de données pour que le graphique apparaisse. - -Graphique d'avancement --------------- - -![Graphique d'avancement](https://kanboard.net/screenshots/documentation/burndown-chart.png) - -Un [graphique d'avancement](http://en.wikipedia.org/wiki/Burn_down_chart) est disponible pour chaque projet. - -- Il s'agit de la représentation graphique du travail qui reste à faire en fonction du temps restant. -- Kanboard utilise la complexité des estimations d'achèvement pour créer le graphique. -- Chaque jour, la somme des estimations pour chaque colonne est calculée. - -Temps moyen passé pour chaque colonne ------------------------------------ - -![Temps moyen passé pour chaque colonne](https://kanboard.net/screenshots/documentation/average-time-spent-into-each-column.png) - -Ce graphique affiche le temps moyen passé pour chaque colonne pour les 1000 dernière tâches. - -- Kanboard utilise les transitions entre tâches pour calculer les données. -- Le temps passé est calculé jusqu'à la fin de la tâche. - -Temps moyen de Lead et Cycle ---------------------------- - -![Temps moyen passé pour chaque colonne](https://kanboard.net/screenshots/documentation/average-lead-cycle-time.png) - -Ce graphique affiche le temps moyen de lead et cycle pour les 1000 dernières tâches au cours du temps. - -- Le *lead time* est le temps passé entre la création de la tâche et sa date d'achèvement. -- Le *cycle time* est le temps passé entre la date de début spécifiée et la date d'achèvement de la tâche. -- Si la tâche n'est pas close, la date courante est utilisée à la place de la date d'achèvement. - -Ces métriques sont calculées et enregistrées chaque jour pour l'ensemble du projet. - -N'oubliez pas de lancer chaque jour le calcul statistique -------------------------------------------------------- - -Pour générer des données analytique précises, vous devriez lancer chaque jour le cronjob **statistiques quotidiennes du projet**. - -[Consultez la documentation sur la ligne de commande avec Kanboard](cli.markdown) diff --git a/doc/fr/application-configuration.markdown b/doc/fr/application-configuration.markdown deleted file mode 100644 index 12768f03..00000000 --- a/doc/fr/application-configuration.markdown +++ /dev/null @@ -1,41 +0,0 @@ -Paramètres de l'application -==================== - -Certains paramètres de l'application peuvent être modifiés sur la page des paramètres. -Seuls les administrateurs peuvent modifier ces paramètres. - -Allez au menu **Paramètres**, puis choisissez **Paramètres de l'application** sur la gauche. - -![Paramètres de l'application](https://kanboard.net/screenshots/documentation/application-settings.png) - -### URL de l'application - -Ce paramètre est utilisé pour les notifications par mail. -Le pied de page du mail contiendra un lien vers la tâche du Kanboard. - -### Langue - -La langue de l'application peut être modifiée à tout moment. -Elle sera définie pour tous les utilisateurs. - -### Fuseau horaire - -Par défaut, Kanboard utilise le TUC comme fuseau horaire, mais vous pouvez définir votre propre fuseau horaire. -La liste contient tous les fuseaux horaires pris en charge par votre serveur web. - -### Format de date - -Format d'entrée utilisé pour les champs de saisie de date, par exemple la date d'échéance pour les tâches. - -Kanboard propose 4 différents formats: - -- JJ/MM/AAAA -- MM/JJ/AAAA (par défaut) -- AAAA/MM/JJ -- MM.JJ.AAAA - -Le format [ISO 8601](http://en.wikipedia.org/wiki/ISO_8601) est toujours accepté (AAAA-MM-JJ ou AAAA_MM_JJ). - -### Feuille de style personnalisée - -Écrivez votre propre CSS pour remplacer ou améliorer le style par défaut de Kanboard. diff --git a/doc/fr/application-configuration.markup b/doc/fr/application-configuration.markup deleted file mode 100644 index 12768f03..00000000 --- a/doc/fr/application-configuration.markup +++ /dev/null @@ -1,41 +0,0 @@ -Paramètres de l'application -==================== - -Certains paramètres de l'application peuvent être modifiés sur la page des paramètres. -Seuls les administrateurs peuvent modifier ces paramètres. - -Allez au menu **Paramètres**, puis choisissez **Paramètres de l'application** sur la gauche. - -![Paramètres de l'application](https://kanboard.net/screenshots/documentation/application-settings.png) - -### URL de l'application - -Ce paramètre est utilisé pour les notifications par mail. -Le pied de page du mail contiendra un lien vers la tâche du Kanboard. - -### Langue - -La langue de l'application peut être modifiée à tout moment. -Elle sera définie pour tous les utilisateurs. - -### Fuseau horaire - -Par défaut, Kanboard utilise le TUC comme fuseau horaire, mais vous pouvez définir votre propre fuseau horaire. -La liste contient tous les fuseaux horaires pris en charge par votre serveur web. - -### Format de date - -Format d'entrée utilisé pour les champs de saisie de date, par exemple la date d'échéance pour les tâches. - -Kanboard propose 4 différents formats: - -- JJ/MM/AAAA -- MM/JJ/AAAA (par défaut) -- AAAA/MM/JJ -- MM.JJ.AAAA - -Le format [ISO 8601](http://en.wikipedia.org/wiki/ISO_8601) est toujours accepté (AAAA-MM-JJ ou AAAA_MM_JJ). - -### Feuille de style personnalisée - -Écrivez votre propre CSS pour remplacer ou améliorer le style par défaut de Kanboard. diff --git a/doc/fr/automatic-actions.markdown b/doc/fr/automatic-actions.markdown deleted file mode 100644 index f136b98c..00000000 --- a/doc/fr/automatic-actions.markdown +++ /dev/null @@ -1,133 +0,0 @@ -Actions automatiques -==================== - -Pour réduire au minimum l'interaction avec les utilisateurs, Kanboard dispose d'actions automatiques. - -Chaque action automatique est définie ainsi : - -- Un événement à suivre -- Une action associée à cet évènement -- Éventuellement quelques paramètres à définir - -Chaque projet a une série d'actions automatisées qui lui sont propres, le panneau de configuration est situé sur la page qui liste les projets, il vous suffit de cliquer sur le lien **Actions automatiques**. - -Ajouter une nouvelle action ---------------------------- - -Cliquez sur le lien **Ajouter une nouvelle action**. - -![Action automatique](screenshots/automatic-action-creation.png) - -- Commencez par choisir une action -- Ensuite, sélectionnez un évènement -- Et pour finir, les paramètres de l'action - -Liste des évènements disponibles --------------------------------- - -- Déplacement d'une tâche vers une autre colonne -- Déplacement d'une tâche à un autre emplacement de la même colonne -- Modification d'une tâche -- Création d'une tâche -- Réouverture d'une tâche -- Fermeture d'une tâche -- Création ou modification d'une tâche -- Changement d'assigné à une tâche -- Création ou mise à jour du lien vers une tâche -- Réception d'un *commit* de Github -- Ouverture d'une *issue* de Github -- Fermeture d'une *issue* de Github -- Réouverture d'une *issue* de Github -- Modification de l'assigné à une *issue* de Github -- Modification de l'étiquette d'une *issue* de Github -- Création d'un commentaire d'une *issue* de Github -- Ouverture d'une *issue* de Gitlab -- Fermeture d'une *issue* de Gitlab -- Réception d'un *commit* de Gitlab -- Réception d'un *commit* de Bitbucket -- Ouverture d'une *issue* de Bitbucket -- Fermeture d'une *issue* de Bitbucket -- Réouverture d'une *issue* de Bitbucket -- Modification de l'assigné à une *issue* de Bitbucket issue assignee change -- Création d'un commentaire d'une *issue* de Bitbucket - -Liste des actions disponibles ------------------------------ - -- Fermer une tâche -- Ouvrir une tâche -- Assigner la tâche à un utilisateur particulier -- Assigner la tâche à la personne qui fait l'action -- Cloner la tâche depuis un autre projet -- Déplacer la tâche vers un autre projet -- Déplacer la tâche vers une autre colonne quand elle est assignée à un utilisateur -- Déplacer la tâche vers une autre colonne quand quand l'assigné est supprimé -- Assigner une couleur quand la tâche est déplacée vers une colonne particulière -- Assigner une couleur à un utilisateur particulier -- Assigner automatiquement une couleur selon la catégorie -- Assigner automatiquement une catégorie en fonction d'une couleur -- Créer un commentaire depuis un fournisseur externe -- Créer une tâche depuis un fournisseur externe -- Ajouter un journal de commentaires quand on change une tâche de colonne -- Modifier l'assigné en fonction d'un nom d'utilisateur externe -- Modifier la catégorie en fonction d'une étiquette externe -- Mettre à jour automatiquement la date de début -- Déplacer la tâche vers une autre colonne quand la catégorie a changé -- Envoyer une tâche par mail à quelqu'un -- Modifier la couleur de la tâche quand on utilise un lien particulier pour cette tâche - -Exemples --------- -Voici quelques exemples d'utilisation dans la vraie vie : - -### Quand je déplace une tâche vers la colonne "Terminer", fermer automatiquement cette tâche - -- Choisir l'action : **Fermer la tâche** -- Choisir l'évènement : **Déplacement d'une tâche vers une autre colonne** -- Définir le paramètre de l'action : **Colonne = Terminé** (c'est la colonne de destination) - -### Quand je déplace une tâche vers la colonne "À valider", assigner cette tâche à un utilisateur particulier - -- Choisir l'action : **Assigner la tâche à un utilisateur particulier** -- Choisir l'évènement : **Déplacer une tâche vers une nouvelle colonne** -- Définir les paramètres de l'action :**Colonne = À valider** et **Utilisateur = Adrien** (Adrien est par exemple un testeur) - -### Quand je déplace une tâche vers la colonne "Travail en cours", assigner cette tâche à l'utilisateur courant - -- Choisir l'action : **Assigner la tâche à la personne qui fait cette action** -- Choisir l'évènement : **Déplacer une tâche vers une autre colonne** -- Définir le paramètre de l'action : **Colonne = Travail en cours** - -### Quand une tâche est terminée, dupliquer cette tâche vers un autre projet - -Supposons que nous ayons deux projets : "Commande du client" et "Production". Une fois validée la commande, la basculer vers le projet "Production". - -- Choisir l'action : **Dupliquer la tâche vers un autre projet** -- Choisir l'évènement : **Fermer une tâche** -- Définir les paramètres de l'action : **Colonne = Validé** et **Projet = Production** - -### Quand une tâche est déplacée vers la toute dernière colonne, déplacer la même tâche exactement vers un autre projet - -Supposons que nous ayons deux projets : "Idées" et "Développement". Une fois validée l'idée, la basculer vers le projet "Développement". - -- Choisir l'action : **Déplacer la tâche vers un autre projet** -- Choisir l'évènement : **Déplacer une tâche vers une autre colonne** -- Définir les paramètres de l'action : **Colonne = Validé** et **Projet = Développement** - -### Je veux assigner automatiquement une couleur à l'utilisateur Adrien - -- Choisir l'action : **Assigner une couleur à un utilisateur particulier** -- Choisir l'évènement : **Modification de l'assigné à une tâche** -- Définir les paramètres de l'action :**Couleur = Vert** et **Assigné = Adrien** - -### Je veux assigner automatiquement une couleur à la catégorie "Demande de fonctionnalité" - -- Choisir l'action : **Assigner automatiquement une couleur à une catégorie particulière** -- Choisir l'évènement : **Création ou modification d'une tâche** -- Définir les paramètres de l'action : **Couleur = Bleu** et **Catégorie = Demande de fonctionnalité** - -### Je veux régler automatiquement la date de début quand la tâche est déplacée dans la colonne "Travail en cours" - -- Choisir l'action : **Mettre à jour automatiquement la date de début** -- Choisir l'évènement : **Déplacer une tâche vers une autre colonne** -- Définir les paramètres de l'action : **Colonne= Travail en cours** diff --git a/doc/fr/board-collapsed-expanded.markdown b/doc/fr/board-collapsed-expanded.markdown deleted file mode 100644 index 29396772..00000000 --- a/doc/fr/board-collapsed-expanded.markdown +++ /dev/null @@ -1,18 +0,0 @@ -Mode replié et déplié -===================== - -Les tâches peuvent être affichées sur le tableau en mode replié ou déplié. -Basculer d'un mode à l'autre peut être fait à l'aide du raccourci clavier **« s »** ou en utilisant le menu déroulant sur la gauche. - -Mode replié ------------ - -![Tâches repliées](screenshots/board-collapsed-mode.png) - -- Si la tâche est affectée à quelqu'un, les initiales de la personne sont affichées à côté du numéro de la tâche. -- Si le titre de la tâche est trop long, mettez le curseur de la souris au-dessus de la tâche pour voir une boite flottante avec le titre entier. - -Mode déplié ------------ - -![Tâches dépliées](screenshots/board-expanded-mode.png) diff --git a/doc/fr/board-configuration.markdown b/doc/fr/board-configuration.markdown deleted file mode 100644 index f7f8be33..00000000 --- a/doc/fr/board-configuration.markdown +++ /dev/null @@ -1,24 +0,0 @@ -Paramètres du tableau -============== - -Allez dans le menu **Paramètres** puis choisissez *Paramètres du tableau** sur la gauche - -![Paramètres du tableau](https://kanboard.net/screenshots/documentation/board-settings.png) - -### Mise en avant d'une tâche - -Cette fonctionnalité affiche une ombre autour de la tâche lorsqu'une tâche à été déplacée récemment. - -Initialisez la fonctionnalité à 0 pour la désactiver, par défaut 2 jours (172800 secondes). - -Toutes les tâches qui ont été déplacées depuis 2 jours seront entourées d'une ombre. - -### Intervalle pour rafraîchir un tableau public - - Lorsque vous partagez un tableau, la page sera, par défaut, automatiquement rafraîchie toutes les 60 secondes. - -### Intervalle pour rafraîchir un tableau privé - - Lorsque votre navigateur web est ouvert sur un tableau, Kanboard vérifie toutes les 10 secondes si quelque chose à été modifié par un autre utilisateur. - - Techniquement, ce processus est fait par Ajax polling. diff --git a/doc/fr/board-horizontal-scrolling-and-compact-view.markdown b/doc/fr/board-horizontal-scrolling-and-compact-view.markdown deleted file mode 100644 index 7ad9c23c..00000000 --- a/doc/fr/board-horizontal-scrolling-and-compact-view.markdown +++ /dev/null @@ -1,11 +0,0 @@ -Défilement horizontal et mode compact -===================================== - -Lorsque le tableau ne loge pas dans votre écran, une barre de défilement horizontal appaîtra en bas de l'écran. - -Cependant, il est possible de basculer vers la vue compacte pour afficher toutes les colonnes dans votre écran. - -![Tableau en mode compact](screenshots/board-compact-mode.png) - -Basculer entre le défilement horizontal et la vue compacte s'effectue avec le raccourci clavier **« c »** ou en utilisant le menu déroulant sur la gauche. - diff --git a/doc/fr/board-show-hide-columns.markdown b/doc/fr/board-show-hide-columns.markdown deleted file mode 100644 index 8eac0b2c..00000000 --- a/doc/fr/board-show-hide-columns.markdown +++ /dev/null @@ -1,12 +0,0 @@ -Afficher ou cacher des colonnes dans le tableau -=============================================== - -Vous pouvez très facilement cacher ou afficher des colonnes dans le tableau : - -![Cacher une colonne](screenshots/hide-column.png) - -Pour cacher une colonne, ouvrez le menu déroulant de la colonne. - -![Afficher une colonne](screenshots/show-column.png) - -Pour afficher de nouveau la colonne, cliquez sur l'icône avec le « plus ». diff --git a/doc/fr/calendar-configuration.markdown b/doc/fr/calendar-configuration.markdown deleted file mode 100644 index 6494568a..00000000 --- a/doc/fr/calendar-configuration.markdown +++ /dev/null @@ -1,43 +0,0 @@ -Paramètres du calendrier -================= - -Allez au menu **Paramètres**, puis choisissez **Paramètres du calendrier** sur la gauche. - -![Paramètres du calendrier](https://kanboard.net/screenshots/documentation/calendar-settings.png) - -il existe deux calendriers distincts dans Kanboard : - -- le calendrier du projet -- le calendrier de l'utilisateur, disponible dans le tableau de bord - -Le calendrier du projet ----------------- - -Ce calendrier affiche les tâches avec les dates d'échéance et les tâches selon leur date de création ou de début. - -### Afficher les tâches selon leur date de création - -- La date de début d'un évènement du calendrier est la date de création de la tâche. -- la date de fin de l'évènement est la date d'achèvement de la tâche. - -### Afficher les tâches selon leur date de début - -- La date de début d'un évènement du calendrier est la date du démarrage effectif de la tâche. -- Cette date ne peut pas être définie manuellement. -- La date de fin de l'évènement est la date de l'achèvement de la tâche. -- S'il n'existe pas de date de début la tâche ne figurera pas sur le calendrier . - -Calendrier de l'utilisateur -------------- - -Ce calendrier n'affiche que les tâches assignées à l'utilisateur et de façon facultative des informations sur les sous-tâches. - -### Afficher les sous-tâches selon le suivi du temps passé - -- Affiche les sous-tâches dans le calendrier d'après les informations recueillies dans l afeuille de suivi du temps. -- Le croisement des données avec l'emploi du temps de l'utilisateur est également calculé. - -### Afficher les estimations des sous-tâches (anticipation sur le travail à venir) - -- Affiche l'estimation du travail à venir pour les sous-tâches qui ont le statut « à faire » et avec une valeur définie à « estimé ». - diff --git a/doc/fr/calendar.markdown b/doc/fr/calendar.markdown deleted file mode 100644 index 2ceeeaa4..00000000 --- a/doc/fr/calendar.markdown +++ /dev/null @@ -1,20 +0,0 @@ -Calendriers -======== - -il existe deux visualisations différentes des calendriers : - -- La vue du projet avec des filtres (disponibles depuis le tableau) -- La vue utilisateur (disponible depuis le tableau de bord de l'utilisateur) - -Pour l'instant le calendrier permet d'afficher les informations suivantes : - -- Les tâches avec une date d'échéance, affichée en haut. **La date d'échéance peut être modifiée en déplaçant la tâche vers un autre jour**. -- les tâches basées sur la date de création ou la date de début. **Ces évènements ne peuvent pas être modifiés avec le calendrier**. -- Le suivi dans le temps de sous-tâches, tous les segments temporels sont affichés dans le calendrier. -- Les estimations pour les sous-tâches, les prévisions et le travail restant - -![Calendrier](https://kanboard.net/screenshots/documentation/calendar.png) - -La configuration du calendrier peut être modifiée dans la page des paramètres. - -Remarque : la date d'échéance n'inclut pas d'information temporelle. diff --git a/doc/fr/closing-tasks.markdown b/doc/fr/closing-tasks.markdown deleted file mode 100644 index 022a1dfd..00000000 --- a/doc/fr/closing-tasks.markdown +++ /dev/null @@ -1,16 +0,0 @@ -Fermer des tâches -============= - -Quand une tâche est fermée, elle n'est plus visible sur le tableau. - -Toutefois, vous pouvez toujours accéder à la liste des tâches closes en utilisant la requête **status:closed** dans un formulaire de recherche, ou bien choisissez simplement **Tâches fermées** dans le menu déroulant des filtres. - -Il existe deux façons différentes de fermer une tâche, depuis le menu déroulant des tâches sur le tableau : - -![Fermer une tâche par le menu déroulant](https://kanboard.net/screenshots/documentation/menu-close-task.png) - -…ou bien depuis la barre latérale dans la vue détaillée des tâches - -![Fermer une tâche](https://kanboard.net/screenshots/documentation/closing-tasks.png) - -Remarque : quand vous fermez une tâche, toutes les sous-tâches qui ne sont pas achevées verront leur statut passer à "Terminé". diff --git a/doc/fr/create-tasks-by-email.markdown b/doc/fr/create-tasks-by-email.markdown deleted file mode 100644 index dd06a1c4..00000000 --- a/doc/fr/create-tasks-by-email.markdown +++ /dev/null @@ -1,45 +0,0 @@ -Créer des tâches par email -===================== - -Vous pouvez créer des tâches directement en envoyant un message. - -Pour le moment, Kanboard fonctionne avec 3 services externes : - -- [Mailgun](https://kanboard.net/documentation/mailgun) -- [Sendgrid](https://kanboard.net/documentation/sendgrid) -- [Postmark](https://kanboard.net/documentation/postmark) - -Ces services gèrent le courrier entrant sans qu'on ait à configurer un serveur SMTP. - -À la réception d'un email par l'un de ces services, le message qu'il contenait est transmis et traité automatiquement par Kanboard. -Toutes les opérations complexes sont prises en charge par ces services. - -Processus de réception du courrier entrant ------------------------- - -1. Vous envoyez un mail à une adresse spécifique, par exemple **quelquechose+monprojet@inbound.mondomaine.tld** -2. Votre mail est envoyé sur les serveurs tiers SMTP -3. Le fournisseur de SMTP appelle Kanboard via un webhook avec le mail en JSON ou aux formats multipart/form-data -4. Kanboard analyse le mail reçu et crée la tâche dans le bon projet - -Remarque : les nouvelles tâches sont automatiquement créées dans la première colonne. - -Format du mail ------------- - -- La partie locale de l'adresse mail doit utiliser le signe + comme séparateur, par exemple **kanboard+projet123** -- La chaîne de caractères définie après le signe + doit correspondre à l'identifiant d'un projet, par exemple **projet123** est l'identifiant du projet **Projet 123** -- le sujet de l'email devient le titre de la tâche -- Le corps du message devient la description de la tâche (au format Markdown) - -Les courriers entrants peuvent être écrits aux formats .txt ou .HTML. -**Kanboard peut convertir en Markdown les messages écrits en simple HTML**. - -Sécurité et prérequis -------------------------- - -- Le webhook de Kanboard est protégé par un jeton aléatoire -- L'adresse de l'expéditeur doit correspondre à celle d'un utilisateur de Kanboard -- L'utilisateur de Kanboard doit être un membre du projet -- Le projet Kanboard doit avoir un identifiant unique, par exemple **MONPROJET** - diff --git a/doc/fr/creating-projects.markdown b/doc/fr/creating-projects.markdown deleted file mode 100644 index e5da7cc6..00000000 --- a/doc/fr/creating-projects.markdown +++ /dev/null @@ -1,39 +0,0 @@ -Créer des projets -================= - -Kanboard peut gérer de multiples projets. Voici deux sortes de projets : - -- Les projets multi-utilisateurs (pour le travail collaboratif, en équipe) -- Les projets privés, réservés à un seul utilisateur - -Créer des projets multi-utilisateurs ------------------------------------- - -- Seuls les administrateurs et les gestionnaires de projets peuvent créer ce type de projets -- La gestion des utilisateurs est disponible - -Depuis le tableau de bord, cliquez sur le lien **Nouveau projet** : - -![Formulaire de création de projet](screenshots/new-project.png) - -C'est vraiment très simple, il vous suffit de trouver un nom pour votre projet ! - -Créer un projet privé ---------------------- - -- Tout le monde peut créer un projet privé (sauf si désactivé par l'administrateur) -- Il n'y a **pas** de gestion des utilisateurs -- Seuls le propriétaire et les administrateurs peuvent accéder au projet - -Depuis le tableau principal, cliquez sur le lien **Nouveau projet privé**. - -Créer un projet depuis un autre projet --------------------------------------- - -Lorsque vous créez un nouveau projet, vous pouvez choisir de dupliquer les propriétés d'un projet existant : - -- Permissions -- Catégories -- Actions -- Swimlanes -- Tâches diff --git a/doc/fr/creating-tasks.markdown b/doc/fr/creating-tasks.markdown deleted file mode 100644 index 9b7fa274..00000000 --- a/doc/fr/creating-tasks.markdown +++ /dev/null @@ -1,27 +0,0 @@ -Créer des tâches -============== - -Depuis le tableau, cliquez sur le signe plus + à côté du nom de la colonne : - -![Création de tâche à partir du tableau](https://kanboard.net/screenshots/documentation/task-creation-board.png) - -Le formulaire de création de tâche apparaît : - -![Formulaire de création de tâche](https://kanboard.net/screenshots/documentation/task-creation-form.png) - -Le seul champ obligatoire est le titre. - -Description des champs : - -- **Titre** : le titre de votre tâche, tel qu'il sera affiché sur le tableau. -- **Description** : vous permet d'ajouter davantage d'informations sur la tâche. Le contenu peut être écrit en [Markdown](https://kanboard.net/documentation/syntax-guide). -- **Créer une autre tâche** : cochez cette case si vous souhaitez créer une tâche similaire (les champs seront pré-remplis). -- **Assigné** : la personne qui va travailler sur la tâche. -- **Catégorie** : une seule catégorie peut être assignée à une tâche. -- **Colonne** : la colonne dans laquelle la tâche sera créée. La tâche sera positionnée en bas de cette colonne. -- **Couleur** : Choisissez la couleur de la carte. -- **Complexité** : utilisée dans la gestion de projet agile (Scrum), la complexité des points d'étape est un nombre qui montre à l'équipe le degré de difficulté de l'avancement du projet. Les utilisateurs se servent souvent des suites de Fibonacci. -- **Estimation originale** : estimation du nombre d'heures nécessaire pour terminer les tâches. -- **Date d'échéance** : les tâches dont la date d'échéance est dépassée auront une date d'échéance en rouge et les dates suivantes seront en noir dans le tableau. Plusieurs formats de date sont acceptés, outre le sélecteur de date. - -Avec le lien d'aperçu (« Prévisualiser »), vous pouvez voir la description de la tâche convertie depuis la syntaxe Markdown. diff --git a/doc/fr/currency-rate.markdown b/doc/fr/currency-rate.markdown deleted file mode 100644 index e84acd31..00000000 --- a/doc/fr/currency-rate.markdown +++ /dev/null @@ -1,11 +0,0 @@ -Taux de change des devises -============== - -Chaque utilisateur peut avoir un taux horaire prédéfini dans différentes devises. -Si vous avez à manipuler plusieurs devises, vous pouvez définir ici le taux en fonction de la devise de référence. - -Cette fonctionnalité est utilisée pour calculer le budget du projet. - -![Currency Rate](https://kanboard.net/screenshots/documentation/currency-rate.png) - -Les paramètres pour le taux de change des devises sont situés dans **Paramètres > Taux de change** diff --git a/doc/fr/duplicate-move-tasks.markdown b/doc/fr/duplicate-move-tasks.markdown deleted file mode 100644 index 07c863d0..00000000 --- a/doc/fr/duplicate-move-tasks.markdown +++ /dev/null @@ -1,58 +0,0 @@ -Dupliquer et déplacer des tâches -======================== - -Dupliquer une tâche dans le même projet --------------------------------------- - -Allez à la vue par tâche et choisissez **Dupliquer** sur la gauche. - -![Duplication de tâche](https://kanboard.net/screenshots/documentation/task-duplication.png) - -Une nouvelle tâche sera créée avec les mêmes propriétés que celles de la tâche originale. - -Dupliquer une tâche vers un autre projet ------------------------------------ - -Allez à la vue par tâches et choisissez **Dupliquer dans un autre projet**. - -![Duplication d'une tâche dans un autre projet](https://kanboard.net/screenshots/documentation/task-duplication-another-project.png) - -Seuls les projets dont vous êtes membre apparaîtront dans le menu déroulant. - -Avant de copier les tâches, Kanboard vous demandera les propriétés de la destination qui ne sont pas communes entre les projets source et destination. - -Vous devez essentiellement définir : - -- La swimlane de destination -- La colonne -- La catégorie -- L'assigné - -Déplacer une tâche vers un autre projet ------------------------------- - -Allez à la vue par tâches et choisissez **Déplacer vers un autre projet**. - -Déplacer vers un autre projet est semblable à l'opération de duplication, vous devez choisir les nouvelles propriétés de la tâche. - -Liste des champs dupliqués -------------------------- -Voici la liste des champs dupliqués : - -- title -- description -- date_due -- color_id -- project_id -- column_id -- owner_id -- score -- category_id -- time_estimated -- swimlane_id -- recurrence_status -- recurrence_trigger -- recurrence_factor -- recurrence_timeframe -- recurrence_basedate - diff --git a/doc/fr/editing-projects.markdown b/doc/fr/editing-projects.markdown deleted file mode 100644 index 2186a1b9..00000000 --- a/doc/fr/editing-projects.markdown +++ /dev/null @@ -1,15 +0,0 @@ -Modifier des projets -==================== - -Les projets peuvent être renommés et désactivés à tout moment. - -Pour renommer un projet, il suffit de cliquer sur le lien « Modifier un projet » sur la gauche. - -![Modification de projet](screenshots/project-edition.png) - -- Les dates de début et de fin sont utilisées pour créer le diagramme de Gantt du projet -- La description est visible en infobulle sur le tableau et sur la page qui liste les projets -- Les administrateurs et administrateurs de projets peuvent convertir un projet privé en projet multi-utilisateur en décochant la case « Projet privé ». -- Vous pouvez également convertir un projet multi-utilisateur en projet privé. - -Remarque : quand vous rendez un projet privé, tous les utilisateurs existants auront accès au projet. Ajustez la liste des utilisateurs selon vos besoins. diff --git a/doc/fr/gantt-chart-projects.markdown b/doc/fr/gantt-chart-projects.markdown deleted file mode 100644 index 3801dc88..00000000 --- a/doc/fr/gantt-chart-projects.markdown +++ /dev/null @@ -1,17 +0,0 @@ -Diagramme de Gantt pour tous les projets -============================ - -Le but de ce diagramme de Gantt est d'afficher une vue d'ensemble de tous les projets basée sur les dates de début et de fin. - -- Ce diagramme de Gantt est disponible dans la section de gestion du projet -- Seuls les administrateurs et administrateurs de projet peuvent accéder à cette section -- Les administrateurs de projet ne verront que les projets dans lesquels il y a des membres -- Les objets privés ne sont pas affichés dans ce graphique - -![Diagramme de Gantt pour tous les projets](https://kanboard.net/screenshots/documentation/gantt-chart-all-projects.png) - -- La **date de début** et la **date de fin** des projets est utilisée pour construire le graphique -- Les barres horizontales peuvent être redimensionnées et déplacées latéralement avec votre souris -- Il n'y a pas de glisser-déposer vertical -- Les barres de projet sont affichées en noir quand il n'y a ni date de début ni date de fin définies -- L'infobulle affiche la liste des gestionnaires de projets et les membres ordinaires diff --git a/doc/fr/gantt-chart-tasks.markdown b/doc/fr/gantt-chart-tasks.markdown deleted file mode 100644 index fbd1b587..00000000 --- a/doc/fr/gantt-chart-tasks.markdown +++ /dev/null @@ -1,20 +0,0 @@ -Diagramme de Gantt pour les tâches -====================== - -Le but de ce diagramme de Gantt est de montrer une vue d'ensemble du temps utilisé en fonction de l'ensemble des tâches d'un projet donné. - -- Le diagramme de Gantt est disponible depuis le « sélecteur de vue » -- Seuls les gestionnaires de projet peuvent accéder à cette section - -![Gantt Chart](https://kanboard.net/screenshots/documentation/gantt-chart-project.png) - -- La **date de début** et la **date de fin** des tâches sont utilisées pour créer le graphique -- Les tâches peuvent être redimensionnées et déplacées horizontalement avec votre souris -- Il n'y a pas de glisser-déposer vertical -- La barre est de la même couleur que la tâche -- Chaque barre affiche un niveau de progression en pourcentage, qui est calculé en utilisant la position de la colonne dans le tableau -- Pour correspondre au modèle du Kanban, les tâches peuvent être ordonnées suivant leur position dans le tableau ou suivant les dates de début -- Les nouvelles tâches crées avec cette vue seront affichées sur le tableau en position 1 de la première colonne -- Les tâches sont affichées en noir quand il n'existe ni date de début ni date d'échéance définies - -![Tâche non définie](https://kanboard.net/screenshots/documentation/gantt-chart-not-defined.png) diff --git a/doc/fr/index.markdown b/doc/fr/index.markdown deleted file mode 100644 index f74c3fce..00000000 --- a/doc/fr/index.markdown +++ /dev/null @@ -1,63 +0,0 @@ -Documentation -============= - -Utiliser Kanboard ------------------ - -### Introduction - -- [Qu'est-ce que Kanban ?](what-is-kanban.markdown) -- [Comparons Kanban aux Todo listes et à Scrum](kanban-vs-todo-and-scrum.markdown) -- [Exemples d'utilisation](usage-examples.markdown) - -### Utiliser un tableau - -- [Vues Tableau, Agenda et Liste](project-views.markdown) -- [Mode Replié et Déplié](board-collapsed-expanded.markdown) -- [Défilement horizontal et mode compact](board-horizontal-scrolling-and-compact-view.markdown) -- [Afficher ou cacher des colonnes dans le tableau](board-show-hide-columns.markdown) - -### Travailler avec les projets - -- [Types de projets](project-types.markdown) -- [Créer des projets](creating-projects.markdown) -- [Modifier des projets](editing-projects.markdown) -- [Partager des tableaux et des tâches](sharing-projects.markdown) -- [Actions automatiques](automatic-actions.markdown) -- [Permissions des projets](project-permissions.markdown) -- [Swimlanes](swimlanes.markdown) -- [Calendriers](calendar.markdown) -- [Analytique](analytics.markdown) -- [Diagramme de Gantt pour les tâches](gantt-chart-tasks.markdown) -- [Diagramme de Gantt pour tous les projets](gantt-chart-projects.markdown) - -### Travailler avec les tâches - -- [Créer des tâches](creating-tasks.markdown) -- [Fermer des tâches](closing-tasks.markdown) -- [Dupliquer et déplacer des tâches](duplicate-move-tasks.markdown) -- [Ajouter des captures d'écran](screenshots.markdown) -- [Liens entre les tâches](task-links.markdown) -- [Transitions](transitions.markdown) -- [Suivi du temps](time-tracking.markdown) -- [Tâches récurrentes](recurring-tasks.markdown) -- [Créer des tâches par email](create-tasks-by-email.markdown) -- [Sous-tâches](subtasks.markdown) -- [Analytique des tâches](analytics-tasks.markdown) - -### Travailler avec les utilisateurs - -- [Rôles](roles.markdown) -- [Gestion des utilisateurs](user-management.markdown) -- [Notifications](notifications.markdown) -- [Authentification à deux facteurs](2fa.markdown) - -### Paramètres - -- [Raccourcis clavier](keyboard-shortcuts.markdown) -- [Paramètres de l'application](application-configuration.markdown) -- [Paramètres du projet](project-configuration.markdown) -- [Paramètres du tableau](board-configuration.markdown) -- [Paramètres du calendrier](calendar-configuration.markdown) -- [Paramètres du lien](link-labels.markdown) -- [Taux de change](currency-rate.markdown) diff --git a/doc/fr/kanban-vs-todo-and-scrum.markdown b/doc/fr/kanban-vs-todo-and-scrum.markdown deleted file mode 100644 index b6f5bc1f..00000000 --- a/doc/fr/kanban-vs-todo-and-scrum.markdown +++ /dev/null @@ -1,36 +0,0 @@ -Comparons Kanban aux Todo listes et à Scrum -============================== - -Kanban et les Todo listes --------------------- - -### Todo listes : - -- Une seule phase (une simple liste d'éléments) -- La possibilité de multitâche (moins efficace) - -### Kanban: - -- Multiples phases, chaque colonne représente une étape -- Permet de se concentrer sans se disperser sur de multiples tâches, puisque l'on peut poser une limite au travail en cours par colonne - -Kanban et Scrum ---------------- -### Scrum : - -- Limite les Sprints dans le temps, généralement à 2 ou 4 semaines -- N'accepte pas de modifications pendant l'itération -- Nécessite une estimation -- Utilise la vélocité comme métrique par défaut -- Le tableau Scrum est remis à zéro entre chaque Sprint -- Scrum a des rôles prédéfinis comme Scrum Master, Product Owner et l'équipe -- Beaucoup de réunions : planification, consolidation du backlog, quotidienne, rétrospective - -### Kanban : -- Flux continu -- Des modifications peuvent arriver à n'importe quel moment -- L'estimation est facultative -- Utilise le temps *lead* et *cycle* pour mesurer l'efficacité -- Le tableau Kanban est permanent -- Kanban n'impose aucune contrainte stricte ni de réunion, le processus est plus flexible - diff --git a/doc/fr/keyboard-shortcuts.markdown b/doc/fr/keyboard-shortcuts.markdown deleted file mode 100644 index 28a131d8..00000000 --- a/doc/fr/keyboard-shortcuts.markdown +++ /dev/null @@ -1,37 +0,0 @@ -Raccourcis clavier -================== - -La disponibilité des raccourcis clavier dépend de la page sur laquelle vous êtes couramment. - -Vues par projets (Tableau, Agenda, Liste, Gantt) --------------------------------------------- - -- Passer à la vue tableau = **v b** (appuyer sur **v** puis **b**) -- Passer à la vue agenda = **v c** -- Passer à la vue liste = **v l** -- Passer à la vue Gantt = **v g** - -Vue tableau ----------- - -- Nouvelle tâche = **n** -- Étendre / replier une tâche = **s** -- Vue compacte / vue étendue = **c** - -Vue détaillée d'une tâche -------------------------- - -- Modifier une tâche = **e** -- Nouvelle sous-tâche = **s** -- Nouveau commentaire = **c** -- Nouveau lien interne = **l** - -Application ------------ - -- Afficher la liste des raccourcis clavier = **?** -- Ouvrir le changement de tableau = **b** -- Aller au moteur de recherche = **f** -- Restaurer la boîte de recherche = **r** -- Fermer la fenêtre de dialogue = **ESC** -- Soumettre un formulaire = **CTRL+ENTER** ou **⌘+ENTER** diff --git a/doc/fr/link-labels.markdown b/doc/fr/link-labels.markdown deleted file mode 100644 index 9c266b5a..00000000 --- a/doc/fr/link-labels.markdown +++ /dev/null @@ -1,13 +0,0 @@ -Paramètres des liens -============= - -Les relations entre les tâches peuvent être modifiées depuis les paramètres de l'application (**Paramètres > Paramètres des liens**) - -![Libellé des liens](https://kanboard.net/screenshots/documentation/link-labels.png) - -Chaque nom du libellé peut avoir un nom du libellé opposé. - -Si il n'y a pas d'opposé, le nom du libellé sera considéré comme étant bidirectionnel. - -![Création d'un libellé de lien](https://kanboard.net/screenshots/documentation/link-label-creation.png) - diff --git a/doc/fr/notifications.markdown b/doc/fr/notifications.markdown deleted file mode 100644 index 43f34a8e..00000000 --- a/doc/fr/notifications.markdown +++ /dev/null @@ -1,45 +0,0 @@ -Notifications -============= - -Kanboard est capable d'envoyer des notifications via différents canaux : - -- Email -- Web (Liste de message non lus) - -Vous pouvez ajouter d'autres canaux en ajoutant des extensions comme par exemple Hipchat, Slack ou encore Jabber. - -Configuration --------------- - -Chaque utilisateur doit autoriser les notifications dans son profil : **Profil Utilisateur > Notifications**. Cette option est désactivée par défaut. - -Vous devez, bien sûr, avoir renseigné une adresse email valide dans votre profil et l'application doit être configurée pour envoyer des emails. - -![Notifications](https://kanboard.net/screenshots/documentation/notifications.png) - -Vous pouvez choisir votre méthode favorite de notification : - -- Email -- Web - -Pour chaque projet dont vous êtes membre, vous pouvez choisir de recevoir des notifications pour : - -- Toutes les tâches -- Seulement les tâches qui vous sont assignées -- Seulement les tâches que vous avez créées -- Seulement les tâches que vous avez créées et celles qui vous sont assignées - -Vous pouvez aussi sélectionner certain projets, par défaut tous les projets dont vous êtes membre sont sélectionnés. - -Notifications web ------------------ - -Les notifications web sont accessibles depuis le tableau de bord ou depuis l'icône en haut de la page : - -![Icône des notifications web](https://kanboard.net/screenshots/documentation/web-notifications-icon.png) - -Les notifications sont affichées sous forme de liste. Vous pouvez marquer comme lu chacune d'entre-elle ou toutes en même temps. - -![Notifications web](https://kanboard.net/screenshots/documentation/web-notifications.png) - -Avec cette méthode vous pouvez quand même rester avertis de ce que se passe sans pour autant être inondé d'emails. diff --git a/doc/fr/project-configuration.markdown b/doc/fr/project-configuration.markdown deleted file mode 100644 index 22db5bf1..00000000 --- a/doc/fr/project-configuration.markdown +++ /dev/null @@ -1,42 +0,0 @@ - -Paramètres du projet -================ - -Aller dans le menu **Préférences**; puis choisissez **Paramètres du projet** sur la gauche - -![Paramètres du projet](https://kanboard.net/screenshots/documentation/project-settings.png) - -###Colonnes par défaut pour les nouveaux projets - -Vous pouvez changer le nom des colonnes par défaut. -C'est utile si vous créez toujours des projets comprenant les même colonnes - -Chaque nom de colonne doit être séparé par une virgule. - -Par défaut, Kanboard utilise les noms de colonne suivants : en attente, prêt, en cours, terminé. - -###Catégories par défaut pour les nouveaux projets - -Les catégories ne sont pas globales à l'application mais rattachées à un projet. -Chaque projet peut avoir plusieurs catégories. - -De plus, si vous créez toujours la même catégorie pour tous vos projets, vous pouvez définir ici la liste des catégories à créer automatiquement - -### Autoriser une seule sous-tâche en cours à la fois pour un utilisateur - -Lorsque cette option est sélectionnée, un utilisateur ne peut travailler que sur une seule sous-tâche à la fois - -Si une autre sous-tâche possède le statut « en cours », l'utilisateur verra cette boite de dialogue : - -![Limite des sous-tâches pour l'utilisateur](https://kanboard.net/screenshots/documentation/subtask-user-restriction.png) - -### Déclencher automatiquement le suivi du temps pour les sous-tâches - -- Si activé, lorsque le statut d'une sous-tâche devient « en cours », le chrono va démarrer automatiquement -- Désactivez cette option si vous n'utilisez pas le suivi du temps. - -### Inclure les tâches fermées dans le diagramme de flux cumulé - -- Si l'option est activée, les tâches fermées seront incluses dans le diagramme de flux cumulé -- Si l'option est désactivée, seules les tâches ouvertes seront incluses dans le diagramme de flux cumulé -- Cette option affecte la colonne "total" de la table "project_daily_column_stats" diff --git a/doc/fr/project-permissions.markdown b/doc/fr/project-permissions.markdown deleted file mode 100644 index c4ef4df4..00000000 --- a/doc/fr/project-permissions.markdown +++ /dev/null @@ -1,22 +0,0 @@ -Permissions des projets -======================= - -Chaque projet est isolé des autres. -Les accès au projet doivent être autorisés par le chef de projet. - -Chaque utilisateur et chaque groupe peut avoir un rôle différent. -Il y a 3 types de [rôles pour les projets](roles.markdown) : - -- Chef de projet -- Membre du projet -- Visualiseur - -L'assignation des rôles est disponible depuis **Paramètres du projet > Permissions**: - -![Permissions du projet](screenshots/project-permissions.png) - -Si vous choisissez d'autoriser tout le monde, tous les utilisateurs de Kanboard seront considérés comme **Membre du projet**. -Ce qui signifie qu'il n'y a plus des gestion de rôles. -Les permissions par utilisateur ou par groupe ne peuvent plus être appliquées. - -Les projets privés ne peuvent pas définir de permissions. diff --git a/doc/fr/project-types.markdown b/doc/fr/project-types.markdown deleted file mode 100644 index 70434ec8..00000000 --- a/doc/fr/project-types.markdown +++ /dev/null @@ -1,14 +0,0 @@ -Types de projets -================ - -Il y a deux types de projets : - -| Type | Description | -|-------------------|-------------------------------------------------------------------------------------| -| Projet d'équipe | La gestion des utilisateurs est activée | -| Projet privé | Projet qui appartient à une seule personne, il n'y a pas de gestion d'utilisateurs | - -- Seulement les administrateurs et les gestionnaires peuvent créer des projets d'équipe. -- Les projets privés peuvent être créé par tout le monde. - -[Lire la documentation à propos des rôles dans Kanboard](roles.markdown) diff --git a/doc/fr/project-views.markdown b/doc/fr/project-views.markdown deleted file mode 100644 index 603108f6..00000000 --- a/doc/fr/project-views.markdown +++ /dev/null @@ -1,61 +0,0 @@ -Vues Tableau, Agenda et Liste -============================= - -Pour chaque projet, les tâches peuvent être visualisées dans différentes vues : **Tableau, Agenda, Liste ou Gantt**. -Chaque vue affiche le résultat filtré par le champ de recherche en haut de page. -Le moteur de recherche utilise la [syntaxe avancée](search.markdown). - -Vue Tableau ------------ - -![Vue Tableau](screenshots/board-view.png) - -- Dans cette vue, il est possible de glisser-déposer facilement des tâches d'une colonne à l'autre. -- Il est également possible d'utiliser le raccourci clavier **« v b »** pour afficher la vue Tableau. -- Les tâches avec une ombre ont été modifiées récemment. - -![Tableau Limite de tâches](screenshots/board-task-limit.png) - -Lorsque la limite de tâches est atteinte pour une colonne, l'arrière-plan devient rouge. -Ce qui signifie qu'il y a trop de tâches en cours en même temps. - -[En apprendre plus sur la configuration du Tableau](board-configuration.markdown) - -Vue Agenda ----------- - -![Vue Agenda](screenshots/calendar-view.png) - -- Dans cette vue, il est possible de voir les tâches avec des dates d'échéance. -- Selon les paramètres, il est également possible de voir les tâches en cours. -- Il est également possible d'utiliser le raccourci clavier **« v c »** pour afficher la vue Agenda. -- [En apprendre plus sur la configuration de l'Agenda](calendar-configuration.markdown) - -Vue Liste ---------- - -![Vue liste](screenshots/list-view.png) - -- Dans cette vue, tous les résultats de votre recherche sont affichés dans un tableau. -- Il est également possible d'utiliser le raccourci clavier **« v l »** pour afficher la vue Liste. - -Vue Gantt ---------- - -![Vue Gantt](screenshots/gantt-view.png) - -- La vue Gantt affiche les tâches dans une fresque horizontale -- Le diagramme utilise la date de début et la date d'échéance pour afficher les tâches -- Il est également possible d'utiliser le raccourci clavier **« v g »** pour afficher la vue Gantt. - -Aperçu du projet ----------------- - -![Aperçu du projet](screenshots/project-view.png) - -Ce mode permet d'afficher une vue d'ensemble du projet : - -- Vous pouvez voir la description du projet -- Attacher et visualiser des pièces-jointes au projet -- Visualiser la liste des membres -- Voir les dernières activités du projet diff --git a/doc/fr/recurring-tasks.markdown b/doc/fr/recurring-tasks.markdown deleted file mode 100644 index 95f24c40..00000000 --- a/doc/fr/recurring-tasks.markdown +++ /dev/null @@ -1,24 +0,0 @@ -Tâches récurrentes -=============== - -Pour convenir à ma méthodologie de Kanban, les tâches récurrentes ne sont pas basées sur une date mais sur les évènements du tableau. - -- Les tâches récurrentes sont dupliquées dans la première colonne du tableau quand les évènements sélectionnés se produisent -- La date d'échéance peut être automatiquement recalculée -- Chaque tâche enregistre l'identifiant de tâche de la tâche parente qui l'a créée et la tâche enfant qui a été créée. - -Configuration -------------- - -Allez à la page de vue par tâches ou utilisez le menu déroulant du tableau, puis choisissez **Modifier la récurrence**. - -![Tâche récurrente](https://kanboard.net/screenshots/documentation/recurring-tasks.png) - -il existe trois façons de déclencher la création d'une nouvelle tâche récurrente : - -- Déplacer une tâche depuis la première colonne -- Déplacer une tâche vers la dernière colonne -- Fermer la tâche - -Les dates d'échéance, si elles concernent la tâche courante, peuvent être recalculées en fonction d'un nombre donné de jours, mois ou années. -La date de base pour le calcul de la nouvelle date d'échéance peut être soit la date d'échéance existante, soit la date de l'action. diff --git a/doc/fr/roles.markdown b/doc/fr/roles.markdown deleted file mode 100644 index e55a3969..00000000 --- a/doc/fr/roles.markdown +++ /dev/null @@ -1,24 +0,0 @@ -Rôles des utilisateurs -====================== - -Rôles au niveau de l'application --------------------------------- - -Chaque utilisateur possède un de ces rôles : - -| Rôle | Description | -|----------------|----------------------------------------------------------------------------------------| -| Administrateur | Accès à tout | -| Gestionnaire | Peut créer des projets d'équipe mais ne peut pas changer les réglages de l'application | -| Utilisateur | Peut créer des projets privés | - -Rôles au niveau des projets ---------------------------- - -Chaque membre d'un projet peut avoir un rôle différent : - -| Rôle | Description | -|------------------------|----------------------------------------------------------------------| -| Chef de projet | Peut changer les paramètres du projet, accéder aux rapports | -| Membre du projet | Peut créer des tâches et utiliser le tableau Kanban | -| Visualiseur de projet | Accès en lecture seule au projet | diff --git a/doc/fr/screenshots.markdown b/doc/fr/screenshots.markdown deleted file mode 100644 index e634bd1b..00000000 --- a/doc/fr/screenshots.markdown +++ /dev/null @@ -1,26 +0,0 @@ -Ajouter des captures d'écran -================== - -Vous pouvez copier-coller des images directement dans Kanboard pour gagner du temps. -Ces images sont mises en ligne en tant que pièces jointes à une tâche. - -Ceci est particulièrement utile pour prendre des captures d'écran, quand il faut par exemple décrire un problème. - -Vous pouvez ajouter directement des captures depuis le tableau en cliquant sur le menu déroulant ou sur la page de visualisation des tâches. - -![La capture d'écran dans le menu déroulant](https://kanboard.net/screenshots/documentation/dropdown-screenshot.png) - -Pour ajouter une nouvelle image, prenez votre capture et collez-la avec CTRL+V ou Command+V: - -![Page de capture](https://kanboard.net/screenshots/documentation/task-screenshot.png) - -Avec Mac OS X, vous pouvez utiliser les raccourcis suivants pour prendre des captures d'écran : - -- Command-Control-Maj-3 : prend une capture de l'écran entier et l'enregistre dans le presse-papiers -- Command-Control-Maj-4, puis choix d'une zone : prend une capture d'une zone définie et l'enregistre dans le presse-papiers -- Command-Control-Maj-4, puis touche espace, puis clic sur une fenêtre : prend une capture d'une fenêtre et l'enregistre dans le presse-papiers - -Il existe plusieurs applications tierces qui peuvent être utilisées pour prendre des captures d'écran avec des annotations et un choix de formes. - -**Remarque : cette fonctionnalité n'est pas disponible sur tous les navigateurs.** Elle n'existe pas pour Safari en raison de ce bug : https://bugs.webkit.org/show_bug.cgi?id=49141 - diff --git a/doc/fr/screenshots/automatic-action-creation.png b/doc/fr/screenshots/automatic-action-creation.png deleted file mode 100644 index ad90590d..00000000 Binary files a/doc/fr/screenshots/automatic-action-creation.png and /dev/null differ diff --git a/doc/fr/screenshots/board-collapsed-mode.png b/doc/fr/screenshots/board-collapsed-mode.png deleted file mode 100644 index a496faff..00000000 Binary files a/doc/fr/screenshots/board-collapsed-mode.png and /dev/null differ diff --git a/doc/fr/screenshots/board-compact-mode.png b/doc/fr/screenshots/board-compact-mode.png deleted file mode 100644 index 872ceae5..00000000 Binary files a/doc/fr/screenshots/board-compact-mode.png and /dev/null differ diff --git a/doc/fr/screenshots/board-expanded-mode.png b/doc/fr/screenshots/board-expanded-mode.png deleted file mode 100644 index 19f61451..00000000 Binary files a/doc/fr/screenshots/board-expanded-mode.png and /dev/null differ diff --git a/doc/fr/screenshots/board-task-limit.png b/doc/fr/screenshots/board-task-limit.png deleted file mode 100644 index 8353f33c..00000000 Binary files a/doc/fr/screenshots/board-task-limit.png and /dev/null differ diff --git a/doc/fr/screenshots/board-view.png b/doc/fr/screenshots/board-view.png deleted file mode 100644 index 0d1e18ea..00000000 Binary files a/doc/fr/screenshots/board-view.png and /dev/null differ diff --git a/doc/fr/screenshots/calendar-view.png b/doc/fr/screenshots/calendar-view.png deleted file mode 100644 index 1226162b..00000000 Binary files a/doc/fr/screenshots/calendar-view.png and /dev/null differ diff --git a/doc/fr/screenshots/gantt-view.png b/doc/fr/screenshots/gantt-view.png deleted file mode 100644 index 3caafa98..00000000 Binary files a/doc/fr/screenshots/gantt-view.png and /dev/null differ diff --git a/doc/fr/screenshots/hide-column.png b/doc/fr/screenshots/hide-column.png deleted file mode 100644 index 61015f9a..00000000 Binary files a/doc/fr/screenshots/hide-column.png and /dev/null differ diff --git a/doc/fr/screenshots/list-view.png b/doc/fr/screenshots/list-view.png deleted file mode 100644 index c40e807a..00000000 Binary files a/doc/fr/screenshots/list-view.png and /dev/null differ diff --git a/doc/fr/screenshots/new-project.png b/doc/fr/screenshots/new-project.png deleted file mode 100644 index 42e5f196..00000000 Binary files a/doc/fr/screenshots/new-project.png and /dev/null differ diff --git a/doc/fr/screenshots/new-user.png b/doc/fr/screenshots/new-user.png deleted file mode 100644 index 116e9074..00000000 Binary files a/doc/fr/screenshots/new-user.png and /dev/null differ diff --git a/doc/fr/screenshots/project-disable-sharing.png b/doc/fr/screenshots/project-disable-sharing.png deleted file mode 100644 index 58832045..00000000 Binary files a/doc/fr/screenshots/project-disable-sharing.png and /dev/null differ diff --git a/doc/fr/screenshots/project-edition.png b/doc/fr/screenshots/project-edition.png deleted file mode 100644 index ce8594fe..00000000 Binary files a/doc/fr/screenshots/project-edition.png and /dev/null differ diff --git a/doc/fr/screenshots/project-enable-sharing.png b/doc/fr/screenshots/project-enable-sharing.png deleted file mode 100644 index 147ccc53..00000000 Binary files a/doc/fr/screenshots/project-enable-sharing.png and /dev/null differ diff --git a/doc/fr/screenshots/project-permissions.png b/doc/fr/screenshots/project-permissions.png deleted file mode 100644 index 54f38690..00000000 Binary files a/doc/fr/screenshots/project-permissions.png and /dev/null differ diff --git a/doc/fr/screenshots/project-view.png b/doc/fr/screenshots/project-view.png deleted file mode 100644 index ff9a7f76..00000000 Binary files a/doc/fr/screenshots/project-view.png and /dev/null differ diff --git a/doc/fr/screenshots/show-column.png b/doc/fr/screenshots/show-column.png deleted file mode 100644 index 51f78ac8..00000000 Binary files a/doc/fr/screenshots/show-column.png and /dev/null differ diff --git a/doc/fr/screenshots/swimlane-configuration.png b/doc/fr/screenshots/swimlane-configuration.png deleted file mode 100644 index d0b25e9c..00000000 Binary files a/doc/fr/screenshots/swimlane-configuration.png and /dev/null differ diff --git a/doc/fr/screenshots/swimlanes.png b/doc/fr/screenshots/swimlanes.png deleted file mode 100644 index e24a5b85..00000000 Binary files a/doc/fr/screenshots/swimlanes.png and /dev/null differ diff --git a/doc/fr/sharing-projects.markdown b/doc/fr/sharing-projects.markdown deleted file mode 100644 index f3db3c68..00000000 --- a/doc/fr/sharing-projects.markdown +++ /dev/null @@ -1,35 +0,0 @@ -Partager des tableaux et des tâches -=================================== - -Par défaut, les tableaux sont privés, mais il est possible de rendre un tableau public. - -Un tableau public ne **peut pas être modifié, il est en lecture seule**. -Son accès est protégé par un jeton aléatoire, seules les personnes qui ont la bonne URL peuvent voir le tableau. - -Les tableaux publics sont automatiquement réactualisés toutes les minutes. -Les détails des tâches sont disponibles en lecture seule. - -Exemples d'utilisation : - -- Partager son tableau avec quelqu'un qui ne fait pas partie de votre organisation / entreprise / groupe -- Afficher le tableau sur un grand écran dans votre bureau - -Activer l'accès public ----------------------- - -Choisissez votre projet, puis cliquez sur « Accès public » et enfin sur le bouton « Activer l'accès public ». - -![Activer l'accès public](screenshots/project-enable-sharing.png) - -Lorsque l'accès public est activé, plusieurs liens sont créés : - -- Affichage du tableau public -- Lien de souscription au fil RSS -- Lien d'abonnement à iCalendar - -![Désactiver l'accès public](screenshots/project-disable-sharing.png) - -Vous pouvez désactiver l'accès public à tout moment. - -À chaque fois que vous activez ou désactivez l'accès public, un nouveau jeton aléatoire est créé. -**Les liens précédents ne fonctionneront pas**. diff --git a/doc/fr/subtasks.markdown b/doc/fr/subtasks.markdown deleted file mode 100644 index 02345c2a..00000000 --- a/doc/fr/subtasks.markdown +++ /dev/null @@ -1,43 +0,0 @@ -Sous-tâches -======== - -Les sous-tâches sont utiles pour se partager le travail que représente une tâche. - -Chaque sous-tâche : - -- peut être assignée à un membre du projet -- a trois différents statuts : **À faire**, **En cours**, **Terminé** -- dispose d'informations sur le temps de travail : **temps passé** et **temps estimé** -- est classée en fonction de sa position - -Créer des sous-tâches ------------------ - -Depuis la vue par tâche, cliquez sur **Ajouter une sous-tâche** dans le panneau latéral. - -![Ajouter une sous-tâche](https://kanboard.net/screenshots/documentation/add-subtask.png) - -Vous pouvez aussi ajouter rapidement une sous-tâche en saisissant seulement son titre : - -![Add a subtask from the task view](https://kanboard.net/screenshots/documentation/add-subtask-shortcut.png) - -Modifier le statut d'une sous-tâche ---------------------- - -Quand vous cliquez sur le titre d'une sous-tâche son statut change : - -![Sous-tâche en cours](https://kanboard.net/screenshots/documentation/subtask-status-inprogress.png) - -L'icône devant le titre est mise à jour en fonction du statut. - -![Sous-tâche effectuée](https://kanboard.net/screenshots/documentation/subtask-status-done.png) - -Remarque : quand la tâche est fermée, toutes les sous-tâches voient leur statut passer à **Terminé**. - -Chrono des sous-tâches -------------- - -- À chaque fois qu'une sous-tâche est en cours de réalisation, le chronomètre est également démarré. Il peut être lancé et interrompu à tout moment. -- Le chronomètre enregistre automatiquement le temps passé sur la sous-tâche. Vous pouvez aussi modifier manuellement la valeur du temps passé dans le champ adéquat quand vous modifiez une sous-tâche. -- Le temps passé est arrondi au quart d'heure le plus proche. Cette information est enregistrée dans un tableau distinct. -- Le temps passé à la tâche ainsi que le temps estimé sont automatiquement mis à jour en fonction de la somme de toutes les sous-tâches. diff --git a/doc/fr/swimlanes.markdown b/doc/fr/swimlanes.markdown deleted file mode 100644 index 92b4a9fa..00000000 --- a/doc/fr/swimlanes.markdown +++ /dev/null @@ -1,29 +0,0 @@ -Swimlanes -========= - -Les *swimlanes* sont des séparations horizontales de votre tableau (pensez à des « couloirs » ou « lignes d'eau » dans une piscine). - -Par exemple, cela peut servir à séparer les sorties des différentes versions d'un logiciel, à diviser vos tâches selon différents produits, équipes ou tout autre critère de votre choix. - -Tableau avec des swimlanes --------------------------- - -![Swimlanes](screenshots/swimlanes.png) - -Gestion des swimlanes ------------------- - -- Tous les projets ont une swimlane par défaut. -- S'il existe plus d'une swimlane, le tableau les affichera toutes. -- Vous pouvez glisser-déposer les tâches d'une swimlane à l'autre. - -Pour configurer les swimlanes allez sur la page de **Configuration du projet** et choisissez la section **Swimlanes**. - -![Swimlanes Configuration](screenshots/swimlane-configuration.png) - -À partir de cet endroit, vous pouvez ajouter une nouvelle swimlane ou renommer celle qui existe par défaut. -Vous pouvez aussi désactiver et modifier la position des diverses swimlanes. - -- La swimlane par défaut est toujours en haut de tableau mais vous pouvez la cacher. -- Les swimlanes inactives ne sont pas affichées dans le tableau. -- **Supprimer une swimlane ne supprime pas les tâches qui lui sont assignées**, ces tâches seront transférées à la swimlane par défaut. diff --git a/doc/fr/task-links.markdown b/doc/fr/task-links.markdown deleted file mode 100644 index f2756ac7..00000000 --- a/doc/fr/task-links.markdown +++ /dev/null @@ -1,22 +0,0 @@ -Liens entre les tâches -========== - -Les tâches peuvent être liées ensemble avec des relations prédéfinies. - -![Task Links](https://kanboard.net/screenshots/documentation/task-links.png) - -Les relations établies par défaut sont les suivantes : - -- **fait référence à** -- **bloque** | est bloqué par -- **est bloqué par** | bloque -- **duplique** | est dupliqué par -- **est dupliqué par** | duplique -- **est un enfant de** | est un parent de -- **est un parent de** | est un enfant de -- **vise les étapes importantes** | est une étape importante de -- **est une étape importante de** | vise les étapes importantes -- **correctifs** | est réglé par -- **est réglé par** | correctifs - -Ces étiquettes peuvent être modifiées dans les paramètres de l'application. diff --git a/doc/fr/time-tracking.markdown b/doc/fr/time-tracking.markdown deleted file mode 100644 index 625bc26f..00000000 --- a/doc/fr/time-tracking.markdown +++ /dev/null @@ -1,44 +0,0 @@ -Suivi du temps -============= - -Les informations de la feuille de suivi du temps peuvent être définies au niveau des tâches ou des sous-tâches - -Suivi de temps des tâches ------------------- - -![Suivi de temps des tâches ](https://kanboard.net/screenshots/documentation/task-time-tracking.png) - -Les tâches ont deux champs: - -- Temps estimé -- Temps passé - -Ces valeurs représentent des heures de travail et doivent être entrées manuellement. - - -Suivi de temps des sous-tâches ---------------------- - -![Suivi de temps des sous-tâches](https://kanboard.net/screenshots/documentation/subtask-time-tracking.png) - -Les sous-tâches ont aussi les champs "temps passé" et "temps estimé" - -Lorsque vous changez la valeur de ces champs, **le suivi des tâches est mis à jour automatiquement et devient la somme des sous-tâches**. - -Kanboard enregistre le temps entre chaque changement de statut des sous-tâches dans une table séparée - -- Changer le statut de la sous-tâche de **à faire** à **en cours** marque le temps de début -- Changer le statut de la sous-tâche de **en cours** à **à faire** marque le temps de fin mais aussi met à jour le temps passé sur la sous-tâche et la tâche - -La répartition de tous les enregistrements est visible sur la page de la tâche - -![Feuille de suivi du temps pour les tâches](https://kanboard.net/screenshots/documentation/task-timesheet.png) - -Pour chaque sous-tâche, le chrono peut être à tout moment arrêté/démarré - -![Chrono des sous-tâches](https://kanboard.net/screenshots/documentation/subtask-timer.png) - -- Le chrono ne dépend pas du statut de la sous-tâche -- Chaque fois que vous démarrez le chrono, un nouvel enregistrement est créé dans la table de suivi des temps -- Chaque fois que vous arrêtez l'horloge, la date de fin est enregistrée dans la table de suivi des temps -- Le temps passé est arrondi au quart d’heure le plus proche diff --git a/doc/fr/transitions.markdown b/doc/fr/transitions.markdown deleted file mode 100644 index 94a14bbc..00000000 --- a/doc/fr/transitions.markdown +++ /dev/null @@ -1,20 +0,0 @@ -Transitions entre les tâches -================ - -Les transitions enregistrent tous les mouvements des tâches entre les colonnes - -![Transitions](https://kanboard.net/screenshots/documentation/transitions.png) - -Depuis la page des tâches, vous pouvez accéder à ces informations: - -- Date de l'action -- Colonne d'origine -- Colonne de destination -- Exécutant (Pour l'utilisateur qui a déplacé la tâche) -- Temps passé sur la colonne d’origine - -Les données de transition entre les tâches peuvent aussi être exportées depuis la page des paramètres du projet - -![Transitions Export](https://kanboard.net/screenshots/documentation/transitions-export.png) - -Pour la période spécifiée, vous allez générer un fichier CSV que vous pouvez utiliser avec n’importe quel tableur diff --git a/doc/fr/usage-examples.markdown b/doc/fr/usage-examples.markdown deleted file mode 100644 index b91fa613..00000000 --- a/doc/fr/usage-examples.markdown +++ /dev/null @@ -1,69 +0,0 @@ -Exemples d'utilisation -============== -Il est possible de personnaliser ses tableaux selon l'activité de votre entreprise : - -Développement logiciel --------------------- - -- Prévu -- Prêt -- En cours -- À valider -- Validé -- En production - -Suivi de bogues ------------- - -- Rapporté -- Confirmé -- En cours -- Testé -- Résolu - -Ventes ------ - -- Objectifs -- Réunions -- Propositions -- Achats - -Gestion au plus juste ------------------------- - -- Idées -- Expression de la demande -- Étude de marché -- Analyses -- Fait - - -Procédure de recrutement ------------------- - -- Offres d'emploi -- Candidats -- Appels téléphoniques -- Entretiens -- Embauches - -Boutiques en ligne ------------- - -- Commande -- Empaquetage -- Prêt à envoyer -- Envoyé - -Artisanat ------------ - -- Commande -- Assemblage -- Tests -- Empaquetage -- Prêt à envoyer -- Envoyé - - diff --git a/doc/fr/user-management.markdown b/doc/fr/user-management.markdown deleted file mode 100644 index bb9b0731..00000000 --- a/doc/fr/user-management.markdown +++ /dev/null @@ -1,35 +0,0 @@ -Gestion des utilisateurs -======================== - -Ajouter un nouvel utilisateur ------------------------------ - -Pour ajouter un nouvel utilisateur, vous devez être administrateur. - -1. Depuis le menu déroulant situé en haut à droite, cliquez sur **Gestion des utilisateurs** -2. Dans la partie haute vous avez un lien **Créer un utilisateur local** ou **Créer un utilisateur distant** -3. Informez les champs de saisie et enregistrez - -![Nouvel utilisateur](screenshots/new-user.png) - -Quand vous créez un **utilisateur local**, vous devez préciser au moins deux valeurs : - -- **nom d'utilisateur** : c'est l'identifiant unique de votre utilisateur (login) -- **mot de passe** : le mot de passe de votre utilisateur doit comporter au moins 6 caractères - -Pour les **utilisateurs distants**, seul le nom d'utilisateur est obligatoire. - -Modifier des utilisateurs -------------------------- - -Quand vous allez au menu **utilisateurs**, vous disposez d'une liste d'utilisateurs. Pour modifier un utilisateur cliquez sur le lien **Modifier**. - -- si vous êtes un utilisateur ordinaire, vous ne pouvez modifier que votre propre profil -- vous devez être administrateur pour pouvoir modifier n'importe quel utilisateur - -Supprimer des utilisateurs --------------------------- - -Depuis le menu **utilisateurs**, cliquez sur le lien **supprimer**. Ce lien n'est visible que si vous êtes administrateur. - -Si vous supprimez un utilisateur particulier, **les tâches assignées à cette personne ne lui seront plus assignées** après cette opération. diff --git a/doc/fr/what-is-kanban.markdown b/doc/fr/what-is-kanban.markdown deleted file mode 100644 index f479927c..00000000 --- a/doc/fr/what-is-kanban.markdown +++ /dev/null @@ -1,34 +0,0 @@ -Qu'est-ce que Kanban? -=============== - - -Kanban est une méthodologie développée à l'origine par l'entreprise Toyota pour gagner en efficacité. - -Kanban n'impose que deux contraintes : - -- Visualiser votre flux d'activité -- Limiter votre travail en cours - -Visualiser votre flux d'activité ------------------------ - -- Votre activité est affichée sur un tableau, vous disposez ainsi d'une vue très nette sur l'ensemble de votre projet -- Chaque colonne représente une étape de votre flux d'activité - -Se concentrer sur une seule tâche à la fois sans disperser son activité ----------------------------------- - -- Chaque phase peut avoir sa date d'échéance -- Les limites fixées sont très utiles pour identifier les goulots d'étranglement -- Les limites évitent de travailler à un trop grand nombre de tâches à la fois - -Mesure des performances et des progrès ------------------------------------ - -Kanban utilise lead time et cycle times pour mesurer les performances : - -- **Lead time** : le *lead time* est la durée entre la création de la tâche et son achèvement. -- **Cycle time** : le *cycle time* est la durée entre la date de début et l'achèvement. - -Par exemple, vous pouvez avoir un *lead time* de 100 jours et n'avoir à travailler qu'une heure pour achever la tâche. - diff --git a/doc/fr_FR/2fa.markdown b/doc/fr_FR/2fa.markdown new file mode 100644 index 00000000..2ecaa10b --- /dev/null +++ b/doc/fr_FR/2fa.markdown @@ -0,0 +1,33 @@ +Authentification à deux facteurs +========================= + +Chaque utilisateur peut activer [l'authentification à deux facteurs](http://en.wikipedia.org/wiki/Two_factor_authentication). +Après s’être connecté, un code à usage unique (6 caractères) est demandé à l'utilisateur pour lui autoriser l’accès à Kanboard. + +Ce code doit être fourni par un logiciel compatible, généralement installé sur votre smartphone. + +Kanboard utilise le [Time-based One-time Password Algorithm](http://en.wikipedia.org/wiki/Time-based_One-time_Password_Algorithm) défini dans la [RFC 6238](http://tools.ietf.org/html/rfc6238). + +Il existe de nombreux logiciels compatibles avec le standard TOTP system. +Par exemple, vous pouvez utilisez ces applications libres et open source : + +- [Google Authenticator](https://github.com/google/google-authenticator/) (Android, iOS, Blackberry) +- [FreeOTP](https://fedorahosted.org/freeotp/) (Android, iOS) +- [OATH Toolkit](http://www.nongnu.org/oath-toolkit/) (utilitaire en ligne de commande sur Unix/Linux) + +Ce système peut fonctionner hors ligne et vous n'avez pas l'obligation d'avoir un téléphone portable. + +Paramétrage +----- + +1. Allez dans le profil utilisateur. +2. Sur la gauche, cliquez sur **Authentification à deux facteurs** et cochez la case. +3. Une clef secrète est générée pour vous. + +![2FA](https://kanboard.net/screenshots/documentation/2fa.png) + +- Vous devez sauvegarder votre clef dans votre logiciel TOTP. Si vous utilisez un smartphone, la solution la plus simple est de scanner le QR code avec FreeOTP ou Google Authenticator +- À chaque ouverture de session, un nouveau code sera demandé +- N'oubliez pas de tester votre appareil avant de quitter votre session + +Une nouvelle clef est générée à chaque fois que vous activez/désactivez cette fonction diff --git a/doc/fr_FR/analytics-tasks.markdown b/doc/fr_FR/analytics-tasks.markdown new file mode 100644 index 00000000..0eb89e34 --- /dev/null +++ b/doc/fr_FR/analytics-tasks.markdown @@ -0,0 +1,24 @@ +Analytique des tâches +=================== + +Chaque tâche possède une section analytique accessible à partir du menu à gauche dans la page des tâches + +Lead et cycle time +------------------- + +![Lead and cycle time](https://kanboard.net/screenshots/documentation/task-lead-cycle-time.png) + +- Le lead time est la durée entre la création de la tâche et son achèvement (tâche fermée). +- Le cycle time est la durée entre la date de début et l'achèvement. +- Si la tâche n’est pas fermée, l’heure courante est utilisée à la place de la date d'achèvement. +- Si la date de départ n'est pas spécifiée, le cycle time n'est pas calculé. + +Remarque : vous pouvez configurer une action pour définir automatiquement que la date de départ sera le moment où vous déplacez une tâche vers une colonne de votre choix + +Temps passé dans chaque colonne +--------------------------- + +![Temps passé dans chaque colonne](https://kanboard.net/screenshots/documentation/time-into-each-column.png) + +- Ce graphique montre le temps total passé dans chaque colonne pour la tâche +- Le temps passé est calculé jusqu’à ce que la tâche soit fermée diff --git a/doc/fr_FR/analytics.markdown b/doc/fr_FR/analytics.markdown new file mode 100644 index 00000000..0b94f272 --- /dev/null +++ b/doc/fr_FR/analytics.markdown @@ -0,0 +1,70 @@ +Analytique +========= + +Chaque projet dispose d'une section analytique. En fonction de la façon dont vous utilisez Kanboard, vous pourrez voir les rapports suivants : + +Répartition des utilisateurs +---------------- + +![Répartition des utilisateurs](https://kanboard.net/screenshots/documentation/user-repartition.png) + +Ce graphique circulaire affiche le nombre de tâches assignées par utilisateur. + +Distribution des tâches +----------------- + +![Distribution des tâches](https://kanboard.net/screenshots/documentation/task-distribution.png) + +Ce graphique circulaire donne une vue d'ensemble du nombre de tâches ouvertes par colonne. + +Diagramme de flux cumulé +----------------------- + +![Diagramme de flux cumulé](https://kanboard.net/screenshots/documentation/cfd.png) + +- Ce graphique affiche le nombre de tâches de façon cumulée pour chaque colonne en fonction du temps passé. +- Chaque jour, le nombre total de tâches est enregistré pour chaque colonne. +- Si vous souhaitez exclure les tâches terminées, modifiez les [paramètres du projet global](project-configuration.markdown). + +Remarque : il faut au moins deux jours de données pour que le graphique apparaisse. + +Graphique d'avancement +-------------- + +![Graphique d'avancement](https://kanboard.net/screenshots/documentation/burndown-chart.png) + +Un [graphique d'avancement](http://en.wikipedia.org/wiki/Burn_down_chart) est disponible pour chaque projet. + +- Il s'agit de la représentation graphique du travail qui reste à faire en fonction du temps restant. +- Kanboard utilise la complexité des estimations d'achèvement pour créer le graphique. +- Chaque jour, la somme des estimations pour chaque colonne est calculée. + +Temps moyen passé pour chaque colonne +----------------------------------- + +![Temps moyen passé pour chaque colonne](https://kanboard.net/screenshots/documentation/average-time-spent-into-each-column.png) + +Ce graphique affiche le temps moyen passé pour chaque colonne pour les 1000 dernière tâches. + +- Kanboard utilise les transitions entre tâches pour calculer les données. +- Le temps passé est calculé jusqu'à la fin de la tâche. + +Temps moyen de Lead et Cycle +--------------------------- + +![Temps moyen passé pour chaque colonne](https://kanboard.net/screenshots/documentation/average-lead-cycle-time.png) + +Ce graphique affiche le temps moyen de lead et cycle pour les 1000 dernières tâches au cours du temps. + +- Le *lead time* est le temps passé entre la création de la tâche et sa date d'achèvement. +- Le *cycle time* est le temps passé entre la date de début spécifiée et la date d'achèvement de la tâche. +- Si la tâche n'est pas close, la date courante est utilisée à la place de la date d'achèvement. + +Ces métriques sont calculées et enregistrées chaque jour pour l'ensemble du projet. + +N'oubliez pas de lancer chaque jour le calcul statistique +------------------------------------------------------- + +Pour générer des données analytique précises, vous devriez lancer chaque jour le cronjob **statistiques quotidiennes du projet**. + +[Consultez la documentation sur la ligne de commande avec Kanboard](cli.markdown) diff --git a/doc/fr_FR/application-configuration.markdown b/doc/fr_FR/application-configuration.markdown new file mode 100644 index 00000000..12768f03 --- /dev/null +++ b/doc/fr_FR/application-configuration.markdown @@ -0,0 +1,41 @@ +Paramètres de l'application +==================== + +Certains paramètres de l'application peuvent être modifiés sur la page des paramètres. +Seuls les administrateurs peuvent modifier ces paramètres. + +Allez au menu **Paramètres**, puis choisissez **Paramètres de l'application** sur la gauche. + +![Paramètres de l'application](https://kanboard.net/screenshots/documentation/application-settings.png) + +### URL de l'application + +Ce paramètre est utilisé pour les notifications par mail. +Le pied de page du mail contiendra un lien vers la tâche du Kanboard. + +### Langue + +La langue de l'application peut être modifiée à tout moment. +Elle sera définie pour tous les utilisateurs. + +### Fuseau horaire + +Par défaut, Kanboard utilise le TUC comme fuseau horaire, mais vous pouvez définir votre propre fuseau horaire. +La liste contient tous les fuseaux horaires pris en charge par votre serveur web. + +### Format de date + +Format d'entrée utilisé pour les champs de saisie de date, par exemple la date d'échéance pour les tâches. + +Kanboard propose 4 différents formats: + +- JJ/MM/AAAA +- MM/JJ/AAAA (par défaut) +- AAAA/MM/JJ +- MM.JJ.AAAA + +Le format [ISO 8601](http://en.wikipedia.org/wiki/ISO_8601) est toujours accepté (AAAA-MM-JJ ou AAAA_MM_JJ). + +### Feuille de style personnalisée + +Écrivez votre propre CSS pour remplacer ou améliorer le style par défaut de Kanboard. diff --git a/doc/fr_FR/application-configuration.markup b/doc/fr_FR/application-configuration.markup new file mode 100644 index 00000000..12768f03 --- /dev/null +++ b/doc/fr_FR/application-configuration.markup @@ -0,0 +1,41 @@ +Paramètres de l'application +==================== + +Certains paramètres de l'application peuvent être modifiés sur la page des paramètres. +Seuls les administrateurs peuvent modifier ces paramètres. + +Allez au menu **Paramètres**, puis choisissez **Paramètres de l'application** sur la gauche. + +![Paramètres de l'application](https://kanboard.net/screenshots/documentation/application-settings.png) + +### URL de l'application + +Ce paramètre est utilisé pour les notifications par mail. +Le pied de page du mail contiendra un lien vers la tâche du Kanboard. + +### Langue + +La langue de l'application peut être modifiée à tout moment. +Elle sera définie pour tous les utilisateurs. + +### Fuseau horaire + +Par défaut, Kanboard utilise le TUC comme fuseau horaire, mais vous pouvez définir votre propre fuseau horaire. +La liste contient tous les fuseaux horaires pris en charge par votre serveur web. + +### Format de date + +Format d'entrée utilisé pour les champs de saisie de date, par exemple la date d'échéance pour les tâches. + +Kanboard propose 4 différents formats: + +- JJ/MM/AAAA +- MM/JJ/AAAA (par défaut) +- AAAA/MM/JJ +- MM.JJ.AAAA + +Le format [ISO 8601](http://en.wikipedia.org/wiki/ISO_8601) est toujours accepté (AAAA-MM-JJ ou AAAA_MM_JJ). + +### Feuille de style personnalisée + +Écrivez votre propre CSS pour remplacer ou améliorer le style par défaut de Kanboard. diff --git a/doc/fr_FR/automatic-actions.markdown b/doc/fr_FR/automatic-actions.markdown new file mode 100644 index 00000000..f136b98c --- /dev/null +++ b/doc/fr_FR/automatic-actions.markdown @@ -0,0 +1,133 @@ +Actions automatiques +==================== + +Pour réduire au minimum l'interaction avec les utilisateurs, Kanboard dispose d'actions automatiques. + +Chaque action automatique est définie ainsi : + +- Un événement à suivre +- Une action associée à cet évènement +- Éventuellement quelques paramètres à définir + +Chaque projet a une série d'actions automatisées qui lui sont propres, le panneau de configuration est situé sur la page qui liste les projets, il vous suffit de cliquer sur le lien **Actions automatiques**. + +Ajouter une nouvelle action +--------------------------- + +Cliquez sur le lien **Ajouter une nouvelle action**. + +![Action automatique](screenshots/automatic-action-creation.png) + +- Commencez par choisir une action +- Ensuite, sélectionnez un évènement +- Et pour finir, les paramètres de l'action + +Liste des évènements disponibles +-------------------------------- + +- Déplacement d'une tâche vers une autre colonne +- Déplacement d'une tâche à un autre emplacement de la même colonne +- Modification d'une tâche +- Création d'une tâche +- Réouverture d'une tâche +- Fermeture d'une tâche +- Création ou modification d'une tâche +- Changement d'assigné à une tâche +- Création ou mise à jour du lien vers une tâche +- Réception d'un *commit* de Github +- Ouverture d'une *issue* de Github +- Fermeture d'une *issue* de Github +- Réouverture d'une *issue* de Github +- Modification de l'assigné à une *issue* de Github +- Modification de l'étiquette d'une *issue* de Github +- Création d'un commentaire d'une *issue* de Github +- Ouverture d'une *issue* de Gitlab +- Fermeture d'une *issue* de Gitlab +- Réception d'un *commit* de Gitlab +- Réception d'un *commit* de Bitbucket +- Ouverture d'une *issue* de Bitbucket +- Fermeture d'une *issue* de Bitbucket +- Réouverture d'une *issue* de Bitbucket +- Modification de l'assigné à une *issue* de Bitbucket issue assignee change +- Création d'un commentaire d'une *issue* de Bitbucket + +Liste des actions disponibles +----------------------------- + +- Fermer une tâche +- Ouvrir une tâche +- Assigner la tâche à un utilisateur particulier +- Assigner la tâche à la personne qui fait l'action +- Cloner la tâche depuis un autre projet +- Déplacer la tâche vers un autre projet +- Déplacer la tâche vers une autre colonne quand elle est assignée à un utilisateur +- Déplacer la tâche vers une autre colonne quand quand l'assigné est supprimé +- Assigner une couleur quand la tâche est déplacée vers une colonne particulière +- Assigner une couleur à un utilisateur particulier +- Assigner automatiquement une couleur selon la catégorie +- Assigner automatiquement une catégorie en fonction d'une couleur +- Créer un commentaire depuis un fournisseur externe +- Créer une tâche depuis un fournisseur externe +- Ajouter un journal de commentaires quand on change une tâche de colonne +- Modifier l'assigné en fonction d'un nom d'utilisateur externe +- Modifier la catégorie en fonction d'une étiquette externe +- Mettre à jour automatiquement la date de début +- Déplacer la tâche vers une autre colonne quand la catégorie a changé +- Envoyer une tâche par mail à quelqu'un +- Modifier la couleur de la tâche quand on utilise un lien particulier pour cette tâche + +Exemples +-------- +Voici quelques exemples d'utilisation dans la vraie vie : + +### Quand je déplace une tâche vers la colonne "Terminer", fermer automatiquement cette tâche + +- Choisir l'action : **Fermer la tâche** +- Choisir l'évènement : **Déplacement d'une tâche vers une autre colonne** +- Définir le paramètre de l'action : **Colonne = Terminé** (c'est la colonne de destination) + +### Quand je déplace une tâche vers la colonne "À valider", assigner cette tâche à un utilisateur particulier + +- Choisir l'action : **Assigner la tâche à un utilisateur particulier** +- Choisir l'évènement : **Déplacer une tâche vers une nouvelle colonne** +- Définir les paramètres de l'action :**Colonne = À valider** et **Utilisateur = Adrien** (Adrien est par exemple un testeur) + +### Quand je déplace une tâche vers la colonne "Travail en cours", assigner cette tâche à l'utilisateur courant + +- Choisir l'action : **Assigner la tâche à la personne qui fait cette action** +- Choisir l'évènement : **Déplacer une tâche vers une autre colonne** +- Définir le paramètre de l'action : **Colonne = Travail en cours** + +### Quand une tâche est terminée, dupliquer cette tâche vers un autre projet + +Supposons que nous ayons deux projets : "Commande du client" et "Production". Une fois validée la commande, la basculer vers le projet "Production". + +- Choisir l'action : **Dupliquer la tâche vers un autre projet** +- Choisir l'évènement : **Fermer une tâche** +- Définir les paramètres de l'action : **Colonne = Validé** et **Projet = Production** + +### Quand une tâche est déplacée vers la toute dernière colonne, déplacer la même tâche exactement vers un autre projet + +Supposons que nous ayons deux projets : "Idées" et "Développement". Une fois validée l'idée, la basculer vers le projet "Développement". + +- Choisir l'action : **Déplacer la tâche vers un autre projet** +- Choisir l'évènement : **Déplacer une tâche vers une autre colonne** +- Définir les paramètres de l'action : **Colonne = Validé** et **Projet = Développement** + +### Je veux assigner automatiquement une couleur à l'utilisateur Adrien + +- Choisir l'action : **Assigner une couleur à un utilisateur particulier** +- Choisir l'évènement : **Modification de l'assigné à une tâche** +- Définir les paramètres de l'action :**Couleur = Vert** et **Assigné = Adrien** + +### Je veux assigner automatiquement une couleur à la catégorie "Demande de fonctionnalité" + +- Choisir l'action : **Assigner automatiquement une couleur à une catégorie particulière** +- Choisir l'évènement : **Création ou modification d'une tâche** +- Définir les paramètres de l'action : **Couleur = Bleu** et **Catégorie = Demande de fonctionnalité** + +### Je veux régler automatiquement la date de début quand la tâche est déplacée dans la colonne "Travail en cours" + +- Choisir l'action : **Mettre à jour automatiquement la date de début** +- Choisir l'évènement : **Déplacer une tâche vers une autre colonne** +- Définir les paramètres de l'action : **Colonne= Travail en cours** diff --git a/doc/fr_FR/board-collapsed-expanded.markdown b/doc/fr_FR/board-collapsed-expanded.markdown new file mode 100644 index 00000000..29396772 --- /dev/null +++ b/doc/fr_FR/board-collapsed-expanded.markdown @@ -0,0 +1,18 @@ +Mode replié et déplié +===================== + +Les tâches peuvent être affichées sur le tableau en mode replié ou déplié. +Basculer d'un mode à l'autre peut être fait à l'aide du raccourci clavier **« s »** ou en utilisant le menu déroulant sur la gauche. + +Mode replié +----------- + +![Tâches repliées](screenshots/board-collapsed-mode.png) + +- Si la tâche est affectée à quelqu'un, les initiales de la personne sont affichées à côté du numéro de la tâche. +- Si le titre de la tâche est trop long, mettez le curseur de la souris au-dessus de la tâche pour voir une boite flottante avec le titre entier. + +Mode déplié +----------- + +![Tâches dépliées](screenshots/board-expanded-mode.png) diff --git a/doc/fr_FR/board-configuration.markdown b/doc/fr_FR/board-configuration.markdown new file mode 100644 index 00000000..f7f8be33 --- /dev/null +++ b/doc/fr_FR/board-configuration.markdown @@ -0,0 +1,24 @@ +Paramètres du tableau +============== + +Allez dans le menu **Paramètres** puis choisissez *Paramètres du tableau** sur la gauche + +![Paramètres du tableau](https://kanboard.net/screenshots/documentation/board-settings.png) + +### Mise en avant d'une tâche + +Cette fonctionnalité affiche une ombre autour de la tâche lorsqu'une tâche à été déplacée récemment. + +Initialisez la fonctionnalité à 0 pour la désactiver, par défaut 2 jours (172800 secondes). + +Toutes les tâches qui ont été déplacées depuis 2 jours seront entourées d'une ombre. + +### Intervalle pour rafraîchir un tableau public + + Lorsque vous partagez un tableau, la page sera, par défaut, automatiquement rafraîchie toutes les 60 secondes. + +### Intervalle pour rafraîchir un tableau privé + + Lorsque votre navigateur web est ouvert sur un tableau, Kanboard vérifie toutes les 10 secondes si quelque chose à été modifié par un autre utilisateur. + + Techniquement, ce processus est fait par Ajax polling. diff --git a/doc/fr_FR/board-horizontal-scrolling-and-compact-view.markdown b/doc/fr_FR/board-horizontal-scrolling-and-compact-view.markdown new file mode 100644 index 00000000..7ad9c23c --- /dev/null +++ b/doc/fr_FR/board-horizontal-scrolling-and-compact-view.markdown @@ -0,0 +1,11 @@ +Défilement horizontal et mode compact +===================================== + +Lorsque le tableau ne loge pas dans votre écran, une barre de défilement horizontal appaîtra en bas de l'écran. + +Cependant, il est possible de basculer vers la vue compacte pour afficher toutes les colonnes dans votre écran. + +![Tableau en mode compact](screenshots/board-compact-mode.png) + +Basculer entre le défilement horizontal et la vue compacte s'effectue avec le raccourci clavier **« c »** ou en utilisant le menu déroulant sur la gauche. + diff --git a/doc/fr_FR/board-show-hide-columns.markdown b/doc/fr_FR/board-show-hide-columns.markdown new file mode 100644 index 00000000..8eac0b2c --- /dev/null +++ b/doc/fr_FR/board-show-hide-columns.markdown @@ -0,0 +1,12 @@ +Afficher ou cacher des colonnes dans le tableau +=============================================== + +Vous pouvez très facilement cacher ou afficher des colonnes dans le tableau : + +![Cacher une colonne](screenshots/hide-column.png) + +Pour cacher une colonne, ouvrez le menu déroulant de la colonne. + +![Afficher une colonne](screenshots/show-column.png) + +Pour afficher de nouveau la colonne, cliquez sur l'icône avec le « plus ». diff --git a/doc/fr_FR/calendar-configuration.markdown b/doc/fr_FR/calendar-configuration.markdown new file mode 100644 index 00000000..6494568a --- /dev/null +++ b/doc/fr_FR/calendar-configuration.markdown @@ -0,0 +1,43 @@ +Paramètres du calendrier +================= + +Allez au menu **Paramètres**, puis choisissez **Paramètres du calendrier** sur la gauche. + +![Paramètres du calendrier](https://kanboard.net/screenshots/documentation/calendar-settings.png) + +il existe deux calendriers distincts dans Kanboard : + +- le calendrier du projet +- le calendrier de l'utilisateur, disponible dans le tableau de bord + +Le calendrier du projet +---------------- + +Ce calendrier affiche les tâches avec les dates d'échéance et les tâches selon leur date de création ou de début. + +### Afficher les tâches selon leur date de création + +- La date de début d'un évènement du calendrier est la date de création de la tâche. +- la date de fin de l'évènement est la date d'achèvement de la tâche. + +### Afficher les tâches selon leur date de début + +- La date de début d'un évènement du calendrier est la date du démarrage effectif de la tâche. +- Cette date ne peut pas être définie manuellement. +- La date de fin de l'évènement est la date de l'achèvement de la tâche. +- S'il n'existe pas de date de début la tâche ne figurera pas sur le calendrier . + +Calendrier de l'utilisateur +------------- + +Ce calendrier n'affiche que les tâches assignées à l'utilisateur et de façon facultative des informations sur les sous-tâches. + +### Afficher les sous-tâches selon le suivi du temps passé + +- Affiche les sous-tâches dans le calendrier d'après les informations recueillies dans l afeuille de suivi du temps. +- Le croisement des données avec l'emploi du temps de l'utilisateur est également calculé. + +### Afficher les estimations des sous-tâches (anticipation sur le travail à venir) + +- Affiche l'estimation du travail à venir pour les sous-tâches qui ont le statut « à faire » et avec une valeur définie à « estimé ». + diff --git a/doc/fr_FR/calendar.markdown b/doc/fr_FR/calendar.markdown new file mode 100644 index 00000000..2ceeeaa4 --- /dev/null +++ b/doc/fr_FR/calendar.markdown @@ -0,0 +1,20 @@ +Calendriers +======== + +il existe deux visualisations différentes des calendriers : + +- La vue du projet avec des filtres (disponibles depuis le tableau) +- La vue utilisateur (disponible depuis le tableau de bord de l'utilisateur) + +Pour l'instant le calendrier permet d'afficher les informations suivantes : + +- Les tâches avec une date d'échéance, affichée en haut. **La date d'échéance peut être modifiée en déplaçant la tâche vers un autre jour**. +- les tâches basées sur la date de création ou la date de début. **Ces évènements ne peuvent pas être modifiés avec le calendrier**. +- Le suivi dans le temps de sous-tâches, tous les segments temporels sont affichés dans le calendrier. +- Les estimations pour les sous-tâches, les prévisions et le travail restant + +![Calendrier](https://kanboard.net/screenshots/documentation/calendar.png) + +La configuration du calendrier peut être modifiée dans la page des paramètres. + +Remarque : la date d'échéance n'inclut pas d'information temporelle. diff --git a/doc/fr_FR/closing-tasks.markdown b/doc/fr_FR/closing-tasks.markdown new file mode 100644 index 00000000..022a1dfd --- /dev/null +++ b/doc/fr_FR/closing-tasks.markdown @@ -0,0 +1,16 @@ +Fermer des tâches +============= + +Quand une tâche est fermée, elle n'est plus visible sur le tableau. + +Toutefois, vous pouvez toujours accéder à la liste des tâches closes en utilisant la requête **status:closed** dans un formulaire de recherche, ou bien choisissez simplement **Tâches fermées** dans le menu déroulant des filtres. + +Il existe deux façons différentes de fermer une tâche, depuis le menu déroulant des tâches sur le tableau : + +![Fermer une tâche par le menu déroulant](https://kanboard.net/screenshots/documentation/menu-close-task.png) + +…ou bien depuis la barre latérale dans la vue détaillée des tâches + +![Fermer une tâche](https://kanboard.net/screenshots/documentation/closing-tasks.png) + +Remarque : quand vous fermez une tâche, toutes les sous-tâches qui ne sont pas achevées verront leur statut passer à "Terminé". diff --git a/doc/fr_FR/create-tasks-by-email.markdown b/doc/fr_FR/create-tasks-by-email.markdown new file mode 100644 index 00000000..dd06a1c4 --- /dev/null +++ b/doc/fr_FR/create-tasks-by-email.markdown @@ -0,0 +1,45 @@ +Créer des tâches par email +===================== + +Vous pouvez créer des tâches directement en envoyant un message. + +Pour le moment, Kanboard fonctionne avec 3 services externes : + +- [Mailgun](https://kanboard.net/documentation/mailgun) +- [Sendgrid](https://kanboard.net/documentation/sendgrid) +- [Postmark](https://kanboard.net/documentation/postmark) + +Ces services gèrent le courrier entrant sans qu'on ait à configurer un serveur SMTP. + +À la réception d'un email par l'un de ces services, le message qu'il contenait est transmis et traité automatiquement par Kanboard. +Toutes les opérations complexes sont prises en charge par ces services. + +Processus de réception du courrier entrant +------------------------ + +1. Vous envoyez un mail à une adresse spécifique, par exemple **quelquechose+monprojet@inbound.mondomaine.tld** +2. Votre mail est envoyé sur les serveurs tiers SMTP +3. Le fournisseur de SMTP appelle Kanboard via un webhook avec le mail en JSON ou aux formats multipart/form-data +4. Kanboard analyse le mail reçu et crée la tâche dans le bon projet + +Remarque : les nouvelles tâches sont automatiquement créées dans la première colonne. + +Format du mail +------------ + +- La partie locale de l'adresse mail doit utiliser le signe + comme séparateur, par exemple **kanboard+projet123** +- La chaîne de caractères définie après le signe + doit correspondre à l'identifiant d'un projet, par exemple **projet123** est l'identifiant du projet **Projet 123** +- le sujet de l'email devient le titre de la tâche +- Le corps du message devient la description de la tâche (au format Markdown) + +Les courriers entrants peuvent être écrits aux formats .txt ou .HTML. +**Kanboard peut convertir en Markdown les messages écrits en simple HTML**. + +Sécurité et prérequis +------------------------- + +- Le webhook de Kanboard est protégé par un jeton aléatoire +- L'adresse de l'expéditeur doit correspondre à celle d'un utilisateur de Kanboard +- L'utilisateur de Kanboard doit être un membre du projet +- Le projet Kanboard doit avoir un identifiant unique, par exemple **MONPROJET** + diff --git a/doc/fr_FR/creating-projects.markdown b/doc/fr_FR/creating-projects.markdown new file mode 100644 index 00000000..e5da7cc6 --- /dev/null +++ b/doc/fr_FR/creating-projects.markdown @@ -0,0 +1,39 @@ +Créer des projets +================= + +Kanboard peut gérer de multiples projets. Voici deux sortes de projets : + +- Les projets multi-utilisateurs (pour le travail collaboratif, en équipe) +- Les projets privés, réservés à un seul utilisateur + +Créer des projets multi-utilisateurs +------------------------------------ + +- Seuls les administrateurs et les gestionnaires de projets peuvent créer ce type de projets +- La gestion des utilisateurs est disponible + +Depuis le tableau de bord, cliquez sur le lien **Nouveau projet** : + +![Formulaire de création de projet](screenshots/new-project.png) + +C'est vraiment très simple, il vous suffit de trouver un nom pour votre projet ! + +Créer un projet privé +--------------------- + +- Tout le monde peut créer un projet privé (sauf si désactivé par l'administrateur) +- Il n'y a **pas** de gestion des utilisateurs +- Seuls le propriétaire et les administrateurs peuvent accéder au projet + +Depuis le tableau principal, cliquez sur le lien **Nouveau projet privé**. + +Créer un projet depuis un autre projet +-------------------------------------- + +Lorsque vous créez un nouveau projet, vous pouvez choisir de dupliquer les propriétés d'un projet existant : + +- Permissions +- Catégories +- Actions +- Swimlanes +- Tâches diff --git a/doc/fr_FR/creating-tasks.markdown b/doc/fr_FR/creating-tasks.markdown new file mode 100644 index 00000000..9b7fa274 --- /dev/null +++ b/doc/fr_FR/creating-tasks.markdown @@ -0,0 +1,27 @@ +Créer des tâches +============== + +Depuis le tableau, cliquez sur le signe plus + à côté du nom de la colonne : + +![Création de tâche à partir du tableau](https://kanboard.net/screenshots/documentation/task-creation-board.png) + +Le formulaire de création de tâche apparaît : + +![Formulaire de création de tâche](https://kanboard.net/screenshots/documentation/task-creation-form.png) + +Le seul champ obligatoire est le titre. + +Description des champs : + +- **Titre** : le titre de votre tâche, tel qu'il sera affiché sur le tableau. +- **Description** : vous permet d'ajouter davantage d'informations sur la tâche. Le contenu peut être écrit en [Markdown](https://kanboard.net/documentation/syntax-guide). +- **Créer une autre tâche** : cochez cette case si vous souhaitez créer une tâche similaire (les champs seront pré-remplis). +- **Assigné** : la personne qui va travailler sur la tâche. +- **Catégorie** : une seule catégorie peut être assignée à une tâche. +- **Colonne** : la colonne dans laquelle la tâche sera créée. La tâche sera positionnée en bas de cette colonne. +- **Couleur** : Choisissez la couleur de la carte. +- **Complexité** : utilisée dans la gestion de projet agile (Scrum), la complexité des points d'étape est un nombre qui montre à l'équipe le degré de difficulté de l'avancement du projet. Les utilisateurs se servent souvent des suites de Fibonacci. +- **Estimation originale** : estimation du nombre d'heures nécessaire pour terminer les tâches. +- **Date d'échéance** : les tâches dont la date d'échéance est dépassée auront une date d'échéance en rouge et les dates suivantes seront en noir dans le tableau. Plusieurs formats de date sont acceptés, outre le sélecteur de date. + +Avec le lien d'aperçu (« Prévisualiser »), vous pouvez voir la description de la tâche convertie depuis la syntaxe Markdown. diff --git a/doc/fr_FR/currency-rate.markdown b/doc/fr_FR/currency-rate.markdown new file mode 100644 index 00000000..e84acd31 --- /dev/null +++ b/doc/fr_FR/currency-rate.markdown @@ -0,0 +1,11 @@ +Taux de change des devises +============== + +Chaque utilisateur peut avoir un taux horaire prédéfini dans différentes devises. +Si vous avez à manipuler plusieurs devises, vous pouvez définir ici le taux en fonction de la devise de référence. + +Cette fonctionnalité est utilisée pour calculer le budget du projet. + +![Currency Rate](https://kanboard.net/screenshots/documentation/currency-rate.png) + +Les paramètres pour le taux de change des devises sont situés dans **Paramètres > Taux de change** diff --git a/doc/fr_FR/duplicate-move-tasks.markdown b/doc/fr_FR/duplicate-move-tasks.markdown new file mode 100644 index 00000000..07c863d0 --- /dev/null +++ b/doc/fr_FR/duplicate-move-tasks.markdown @@ -0,0 +1,58 @@ +Dupliquer et déplacer des tâches +======================== + +Dupliquer une tâche dans le même projet +-------------------------------------- + +Allez à la vue par tâche et choisissez **Dupliquer** sur la gauche. + +![Duplication de tâche](https://kanboard.net/screenshots/documentation/task-duplication.png) + +Une nouvelle tâche sera créée avec les mêmes propriétés que celles de la tâche originale. + +Dupliquer une tâche vers un autre projet +----------------------------------- + +Allez à la vue par tâches et choisissez **Dupliquer dans un autre projet**. + +![Duplication d'une tâche dans un autre projet](https://kanboard.net/screenshots/documentation/task-duplication-another-project.png) + +Seuls les projets dont vous êtes membre apparaîtront dans le menu déroulant. + +Avant de copier les tâches, Kanboard vous demandera les propriétés de la destination qui ne sont pas communes entre les projets source et destination. + +Vous devez essentiellement définir : + +- La swimlane de destination +- La colonne +- La catégorie +- L'assigné + +Déplacer une tâche vers un autre projet +------------------------------ + +Allez à la vue par tâches et choisissez **Déplacer vers un autre projet**. + +Déplacer vers un autre projet est semblable à l'opération de duplication, vous devez choisir les nouvelles propriétés de la tâche. + +Liste des champs dupliqués +------------------------- +Voici la liste des champs dupliqués : + +- title +- description +- date_due +- color_id +- project_id +- column_id +- owner_id +- score +- category_id +- time_estimated +- swimlane_id +- recurrence_status +- recurrence_trigger +- recurrence_factor +- recurrence_timeframe +- recurrence_basedate + diff --git a/doc/fr_FR/editing-projects.markdown b/doc/fr_FR/editing-projects.markdown new file mode 100644 index 00000000..2186a1b9 --- /dev/null +++ b/doc/fr_FR/editing-projects.markdown @@ -0,0 +1,15 @@ +Modifier des projets +==================== + +Les projets peuvent être renommés et désactivés à tout moment. + +Pour renommer un projet, il suffit de cliquer sur le lien « Modifier un projet » sur la gauche. + +![Modification de projet](screenshots/project-edition.png) + +- Les dates de début et de fin sont utilisées pour créer le diagramme de Gantt du projet +- La description est visible en infobulle sur le tableau et sur la page qui liste les projets +- Les administrateurs et administrateurs de projets peuvent convertir un projet privé en projet multi-utilisateur en décochant la case « Projet privé ». +- Vous pouvez également convertir un projet multi-utilisateur en projet privé. + +Remarque : quand vous rendez un projet privé, tous les utilisateurs existants auront accès au projet. Ajustez la liste des utilisateurs selon vos besoins. diff --git a/doc/fr_FR/gantt-chart-projects.markdown b/doc/fr_FR/gantt-chart-projects.markdown new file mode 100644 index 00000000..3801dc88 --- /dev/null +++ b/doc/fr_FR/gantt-chart-projects.markdown @@ -0,0 +1,17 @@ +Diagramme de Gantt pour tous les projets +============================ + +Le but de ce diagramme de Gantt est d'afficher une vue d'ensemble de tous les projets basée sur les dates de début et de fin. + +- Ce diagramme de Gantt est disponible dans la section de gestion du projet +- Seuls les administrateurs et administrateurs de projet peuvent accéder à cette section +- Les administrateurs de projet ne verront que les projets dans lesquels il y a des membres +- Les objets privés ne sont pas affichés dans ce graphique + +![Diagramme de Gantt pour tous les projets](https://kanboard.net/screenshots/documentation/gantt-chart-all-projects.png) + +- La **date de début** et la **date de fin** des projets est utilisée pour construire le graphique +- Les barres horizontales peuvent être redimensionnées et déplacées latéralement avec votre souris +- Il n'y a pas de glisser-déposer vertical +- Les barres de projet sont affichées en noir quand il n'y a ni date de début ni date de fin définies +- L'infobulle affiche la liste des gestionnaires de projets et les membres ordinaires diff --git a/doc/fr_FR/gantt-chart-tasks.markdown b/doc/fr_FR/gantt-chart-tasks.markdown new file mode 100644 index 00000000..fbd1b587 --- /dev/null +++ b/doc/fr_FR/gantt-chart-tasks.markdown @@ -0,0 +1,20 @@ +Diagramme de Gantt pour les tâches +====================== + +Le but de ce diagramme de Gantt est de montrer une vue d'ensemble du temps utilisé en fonction de l'ensemble des tâches d'un projet donné. + +- Le diagramme de Gantt est disponible depuis le « sélecteur de vue » +- Seuls les gestionnaires de projet peuvent accéder à cette section + +![Gantt Chart](https://kanboard.net/screenshots/documentation/gantt-chart-project.png) + +- La **date de début** et la **date de fin** des tâches sont utilisées pour créer le graphique +- Les tâches peuvent être redimensionnées et déplacées horizontalement avec votre souris +- Il n'y a pas de glisser-déposer vertical +- La barre est de la même couleur que la tâche +- Chaque barre affiche un niveau de progression en pourcentage, qui est calculé en utilisant la position de la colonne dans le tableau +- Pour correspondre au modèle du Kanban, les tâches peuvent être ordonnées suivant leur position dans le tableau ou suivant les dates de début +- Les nouvelles tâches crées avec cette vue seront affichées sur le tableau en position 1 de la première colonne +- Les tâches sont affichées en noir quand il n'existe ni date de début ni date d'échéance définies + +![Tâche non définie](https://kanboard.net/screenshots/documentation/gantt-chart-not-defined.png) diff --git a/doc/fr_FR/index.markdown b/doc/fr_FR/index.markdown new file mode 100644 index 00000000..f74c3fce --- /dev/null +++ b/doc/fr_FR/index.markdown @@ -0,0 +1,63 @@ +Documentation +============= + +Utiliser Kanboard +----------------- + +### Introduction + +- [Qu'est-ce que Kanban ?](what-is-kanban.markdown) +- [Comparons Kanban aux Todo listes et à Scrum](kanban-vs-todo-and-scrum.markdown) +- [Exemples d'utilisation](usage-examples.markdown) + +### Utiliser un tableau + +- [Vues Tableau, Agenda et Liste](project-views.markdown) +- [Mode Replié et Déplié](board-collapsed-expanded.markdown) +- [Défilement horizontal et mode compact](board-horizontal-scrolling-and-compact-view.markdown) +- [Afficher ou cacher des colonnes dans le tableau](board-show-hide-columns.markdown) + +### Travailler avec les projets + +- [Types de projets](project-types.markdown) +- [Créer des projets](creating-projects.markdown) +- [Modifier des projets](editing-projects.markdown) +- [Partager des tableaux et des tâches](sharing-projects.markdown) +- [Actions automatiques](automatic-actions.markdown) +- [Permissions des projets](project-permissions.markdown) +- [Swimlanes](swimlanes.markdown) +- [Calendriers](calendar.markdown) +- [Analytique](analytics.markdown) +- [Diagramme de Gantt pour les tâches](gantt-chart-tasks.markdown) +- [Diagramme de Gantt pour tous les projets](gantt-chart-projects.markdown) + +### Travailler avec les tâches + +- [Créer des tâches](creating-tasks.markdown) +- [Fermer des tâches](closing-tasks.markdown) +- [Dupliquer et déplacer des tâches](duplicate-move-tasks.markdown) +- [Ajouter des captures d'écran](screenshots.markdown) +- [Liens entre les tâches](task-links.markdown) +- [Transitions](transitions.markdown) +- [Suivi du temps](time-tracking.markdown) +- [Tâches récurrentes](recurring-tasks.markdown) +- [Créer des tâches par email](create-tasks-by-email.markdown) +- [Sous-tâches](subtasks.markdown) +- [Analytique des tâches](analytics-tasks.markdown) + +### Travailler avec les utilisateurs + +- [Rôles](roles.markdown) +- [Gestion des utilisateurs](user-management.markdown) +- [Notifications](notifications.markdown) +- [Authentification à deux facteurs](2fa.markdown) + +### Paramètres + +- [Raccourcis clavier](keyboard-shortcuts.markdown) +- [Paramètres de l'application](application-configuration.markdown) +- [Paramètres du projet](project-configuration.markdown) +- [Paramètres du tableau](board-configuration.markdown) +- [Paramètres du calendrier](calendar-configuration.markdown) +- [Paramètres du lien](link-labels.markdown) +- [Taux de change](currency-rate.markdown) diff --git a/doc/fr_FR/kanban-vs-todo-and-scrum.markdown b/doc/fr_FR/kanban-vs-todo-and-scrum.markdown new file mode 100644 index 00000000..b6f5bc1f --- /dev/null +++ b/doc/fr_FR/kanban-vs-todo-and-scrum.markdown @@ -0,0 +1,36 @@ +Comparons Kanban aux Todo listes et à Scrum +============================== + +Kanban et les Todo listes +-------------------- + +### Todo listes : + +- Une seule phase (une simple liste d'éléments) +- La possibilité de multitâche (moins efficace) + +### Kanban: + +- Multiples phases, chaque colonne représente une étape +- Permet de se concentrer sans se disperser sur de multiples tâches, puisque l'on peut poser une limite au travail en cours par colonne + +Kanban et Scrum +--------------- +### Scrum : + +- Limite les Sprints dans le temps, généralement à 2 ou 4 semaines +- N'accepte pas de modifications pendant l'itération +- Nécessite une estimation +- Utilise la vélocité comme métrique par défaut +- Le tableau Scrum est remis à zéro entre chaque Sprint +- Scrum a des rôles prédéfinis comme Scrum Master, Product Owner et l'équipe +- Beaucoup de réunions : planification, consolidation du backlog, quotidienne, rétrospective + +### Kanban : +- Flux continu +- Des modifications peuvent arriver à n'importe quel moment +- L'estimation est facultative +- Utilise le temps *lead* et *cycle* pour mesurer l'efficacité +- Le tableau Kanban est permanent +- Kanban n'impose aucune contrainte stricte ni de réunion, le processus est plus flexible + diff --git a/doc/fr_FR/keyboard-shortcuts.markdown b/doc/fr_FR/keyboard-shortcuts.markdown new file mode 100644 index 00000000..28a131d8 --- /dev/null +++ b/doc/fr_FR/keyboard-shortcuts.markdown @@ -0,0 +1,37 @@ +Raccourcis clavier +================== + +La disponibilité des raccourcis clavier dépend de la page sur laquelle vous êtes couramment. + +Vues par projets (Tableau, Agenda, Liste, Gantt) +-------------------------------------------- + +- Passer à la vue tableau = **v b** (appuyer sur **v** puis **b**) +- Passer à la vue agenda = **v c** +- Passer à la vue liste = **v l** +- Passer à la vue Gantt = **v g** + +Vue tableau +---------- + +- Nouvelle tâche = **n** +- Étendre / replier une tâche = **s** +- Vue compacte / vue étendue = **c** + +Vue détaillée d'une tâche +------------------------- + +- Modifier une tâche = **e** +- Nouvelle sous-tâche = **s** +- Nouveau commentaire = **c** +- Nouveau lien interne = **l** + +Application +----------- + +- Afficher la liste des raccourcis clavier = **?** +- Ouvrir le changement de tableau = **b** +- Aller au moteur de recherche = **f** +- Restaurer la boîte de recherche = **r** +- Fermer la fenêtre de dialogue = **ESC** +- Soumettre un formulaire = **CTRL+ENTER** ou **⌘+ENTER** diff --git a/doc/fr_FR/link-labels.markdown b/doc/fr_FR/link-labels.markdown new file mode 100644 index 00000000..9c266b5a --- /dev/null +++ b/doc/fr_FR/link-labels.markdown @@ -0,0 +1,13 @@ +Paramètres des liens +============= + +Les relations entre les tâches peuvent être modifiées depuis les paramètres de l'application (**Paramètres > Paramètres des liens**) + +![Libellé des liens](https://kanboard.net/screenshots/documentation/link-labels.png) + +Chaque nom du libellé peut avoir un nom du libellé opposé. + +Si il n'y a pas d'opposé, le nom du libellé sera considéré comme étant bidirectionnel. + +![Création d'un libellé de lien](https://kanboard.net/screenshots/documentation/link-label-creation.png) + diff --git a/doc/fr_FR/notifications.markdown b/doc/fr_FR/notifications.markdown new file mode 100644 index 00000000..43f34a8e --- /dev/null +++ b/doc/fr_FR/notifications.markdown @@ -0,0 +1,45 @@ +Notifications +============= + +Kanboard est capable d'envoyer des notifications via différents canaux : + +- Email +- Web (Liste de message non lus) + +Vous pouvez ajouter d'autres canaux en ajoutant des extensions comme par exemple Hipchat, Slack ou encore Jabber. + +Configuration +-------------- + +Chaque utilisateur doit autoriser les notifications dans son profil : **Profil Utilisateur > Notifications**. Cette option est désactivée par défaut. + +Vous devez, bien sûr, avoir renseigné une adresse email valide dans votre profil et l'application doit être configurée pour envoyer des emails. + +![Notifications](https://kanboard.net/screenshots/documentation/notifications.png) + +Vous pouvez choisir votre méthode favorite de notification : + +- Email +- Web + +Pour chaque projet dont vous êtes membre, vous pouvez choisir de recevoir des notifications pour : + +- Toutes les tâches +- Seulement les tâches qui vous sont assignées +- Seulement les tâches que vous avez créées +- Seulement les tâches que vous avez créées et celles qui vous sont assignées + +Vous pouvez aussi sélectionner certain projets, par défaut tous les projets dont vous êtes membre sont sélectionnés. + +Notifications web +----------------- + +Les notifications web sont accessibles depuis le tableau de bord ou depuis l'icône en haut de la page : + +![Icône des notifications web](https://kanboard.net/screenshots/documentation/web-notifications-icon.png) + +Les notifications sont affichées sous forme de liste. Vous pouvez marquer comme lu chacune d'entre-elle ou toutes en même temps. + +![Notifications web](https://kanboard.net/screenshots/documentation/web-notifications.png) + +Avec cette méthode vous pouvez quand même rester avertis de ce que se passe sans pour autant être inondé d'emails. diff --git a/doc/fr_FR/project-configuration.markdown b/doc/fr_FR/project-configuration.markdown new file mode 100644 index 00000000..22db5bf1 --- /dev/null +++ b/doc/fr_FR/project-configuration.markdown @@ -0,0 +1,42 @@ + +Paramètres du projet +================ + +Aller dans le menu **Préférences**; puis choisissez **Paramètres du projet** sur la gauche + +![Paramètres du projet](https://kanboard.net/screenshots/documentation/project-settings.png) + +###Colonnes par défaut pour les nouveaux projets + +Vous pouvez changer le nom des colonnes par défaut. +C'est utile si vous créez toujours des projets comprenant les même colonnes + +Chaque nom de colonne doit être séparé par une virgule. + +Par défaut, Kanboard utilise les noms de colonne suivants : en attente, prêt, en cours, terminé. + +###Catégories par défaut pour les nouveaux projets + +Les catégories ne sont pas globales à l'application mais rattachées à un projet. +Chaque projet peut avoir plusieurs catégories. + +De plus, si vous créez toujours la même catégorie pour tous vos projets, vous pouvez définir ici la liste des catégories à créer automatiquement + +### Autoriser une seule sous-tâche en cours à la fois pour un utilisateur + +Lorsque cette option est sélectionnée, un utilisateur ne peut travailler que sur une seule sous-tâche à la fois + +Si une autre sous-tâche possède le statut « en cours », l'utilisateur verra cette boite de dialogue : + +![Limite des sous-tâches pour l'utilisateur](https://kanboard.net/screenshots/documentation/subtask-user-restriction.png) + +### Déclencher automatiquement le suivi du temps pour les sous-tâches + +- Si activé, lorsque le statut d'une sous-tâche devient « en cours », le chrono va démarrer automatiquement +- Désactivez cette option si vous n'utilisez pas le suivi du temps. + +### Inclure les tâches fermées dans le diagramme de flux cumulé + +- Si l'option est activée, les tâches fermées seront incluses dans le diagramme de flux cumulé +- Si l'option est désactivée, seules les tâches ouvertes seront incluses dans le diagramme de flux cumulé +- Cette option affecte la colonne "total" de la table "project_daily_column_stats" diff --git a/doc/fr_FR/project-permissions.markdown b/doc/fr_FR/project-permissions.markdown new file mode 100644 index 00000000..c4ef4df4 --- /dev/null +++ b/doc/fr_FR/project-permissions.markdown @@ -0,0 +1,22 @@ +Permissions des projets +======================= + +Chaque projet est isolé des autres. +Les accès au projet doivent être autorisés par le chef de projet. + +Chaque utilisateur et chaque groupe peut avoir un rôle différent. +Il y a 3 types de [rôles pour les projets](roles.markdown) : + +- Chef de projet +- Membre du projet +- Visualiseur + +L'assignation des rôles est disponible depuis **Paramètres du projet > Permissions**: + +![Permissions du projet](screenshots/project-permissions.png) + +Si vous choisissez d'autoriser tout le monde, tous les utilisateurs de Kanboard seront considérés comme **Membre du projet**. +Ce qui signifie qu'il n'y a plus des gestion de rôles. +Les permissions par utilisateur ou par groupe ne peuvent plus être appliquées. + +Les projets privés ne peuvent pas définir de permissions. diff --git a/doc/fr_FR/project-types.markdown b/doc/fr_FR/project-types.markdown new file mode 100644 index 00000000..70434ec8 --- /dev/null +++ b/doc/fr_FR/project-types.markdown @@ -0,0 +1,14 @@ +Types de projets +================ + +Il y a deux types de projets : + +| Type | Description | +|-------------------|-------------------------------------------------------------------------------------| +| Projet d'équipe | La gestion des utilisateurs est activée | +| Projet privé | Projet qui appartient à une seule personne, il n'y a pas de gestion d'utilisateurs | + +- Seulement les administrateurs et les gestionnaires peuvent créer des projets d'équipe. +- Les projets privés peuvent être créé par tout le monde. + +[Lire la documentation à propos des rôles dans Kanboard](roles.markdown) diff --git a/doc/fr_FR/project-views.markdown b/doc/fr_FR/project-views.markdown new file mode 100644 index 00000000..603108f6 --- /dev/null +++ b/doc/fr_FR/project-views.markdown @@ -0,0 +1,61 @@ +Vues Tableau, Agenda et Liste +============================= + +Pour chaque projet, les tâches peuvent être visualisées dans différentes vues : **Tableau, Agenda, Liste ou Gantt**. +Chaque vue affiche le résultat filtré par le champ de recherche en haut de page. +Le moteur de recherche utilise la [syntaxe avancée](search.markdown). + +Vue Tableau +----------- + +![Vue Tableau](screenshots/board-view.png) + +- Dans cette vue, il est possible de glisser-déposer facilement des tâches d'une colonne à l'autre. +- Il est également possible d'utiliser le raccourci clavier **« v b »** pour afficher la vue Tableau. +- Les tâches avec une ombre ont été modifiées récemment. + +![Tableau Limite de tâches](screenshots/board-task-limit.png) + +Lorsque la limite de tâches est atteinte pour une colonne, l'arrière-plan devient rouge. +Ce qui signifie qu'il y a trop de tâches en cours en même temps. + +[En apprendre plus sur la configuration du Tableau](board-configuration.markdown) + +Vue Agenda +---------- + +![Vue Agenda](screenshots/calendar-view.png) + +- Dans cette vue, il est possible de voir les tâches avec des dates d'échéance. +- Selon les paramètres, il est également possible de voir les tâches en cours. +- Il est également possible d'utiliser le raccourci clavier **« v c »** pour afficher la vue Agenda. +- [En apprendre plus sur la configuration de l'Agenda](calendar-configuration.markdown) + +Vue Liste +--------- + +![Vue liste](screenshots/list-view.png) + +- Dans cette vue, tous les résultats de votre recherche sont affichés dans un tableau. +- Il est également possible d'utiliser le raccourci clavier **« v l »** pour afficher la vue Liste. + +Vue Gantt +--------- + +![Vue Gantt](screenshots/gantt-view.png) + +- La vue Gantt affiche les tâches dans une fresque horizontale +- Le diagramme utilise la date de début et la date d'échéance pour afficher les tâches +- Il est également possible d'utiliser le raccourci clavier **« v g »** pour afficher la vue Gantt. + +Aperçu du projet +---------------- + +![Aperçu du projet](screenshots/project-view.png) + +Ce mode permet d'afficher une vue d'ensemble du projet : + +- Vous pouvez voir la description du projet +- Attacher et visualiser des pièces-jointes au projet +- Visualiser la liste des membres +- Voir les dernières activités du projet diff --git a/doc/fr_FR/recurring-tasks.markdown b/doc/fr_FR/recurring-tasks.markdown new file mode 100644 index 00000000..95f24c40 --- /dev/null +++ b/doc/fr_FR/recurring-tasks.markdown @@ -0,0 +1,24 @@ +Tâches récurrentes +=============== + +Pour convenir à ma méthodologie de Kanban, les tâches récurrentes ne sont pas basées sur une date mais sur les évènements du tableau. + +- Les tâches récurrentes sont dupliquées dans la première colonne du tableau quand les évènements sélectionnés se produisent +- La date d'échéance peut être automatiquement recalculée +- Chaque tâche enregistre l'identifiant de tâche de la tâche parente qui l'a créée et la tâche enfant qui a été créée. + +Configuration +------------- + +Allez à la page de vue par tâches ou utilisez le menu déroulant du tableau, puis choisissez **Modifier la récurrence**. + +![Tâche récurrente](https://kanboard.net/screenshots/documentation/recurring-tasks.png) + +il existe trois façons de déclencher la création d'une nouvelle tâche récurrente : + +- Déplacer une tâche depuis la première colonne +- Déplacer une tâche vers la dernière colonne +- Fermer la tâche + +Les dates d'échéance, si elles concernent la tâche courante, peuvent être recalculées en fonction d'un nombre donné de jours, mois ou années. +La date de base pour le calcul de la nouvelle date d'échéance peut être soit la date d'échéance existante, soit la date de l'action. diff --git a/doc/fr_FR/roles.markdown b/doc/fr_FR/roles.markdown new file mode 100644 index 00000000..e55a3969 --- /dev/null +++ b/doc/fr_FR/roles.markdown @@ -0,0 +1,24 @@ +Rôles des utilisateurs +====================== + +Rôles au niveau de l'application +-------------------------------- + +Chaque utilisateur possède un de ces rôles : + +| Rôle | Description | +|----------------|----------------------------------------------------------------------------------------| +| Administrateur | Accès à tout | +| Gestionnaire | Peut créer des projets d'équipe mais ne peut pas changer les réglages de l'application | +| Utilisateur | Peut créer des projets privés | + +Rôles au niveau des projets +--------------------------- + +Chaque membre d'un projet peut avoir un rôle différent : + +| Rôle | Description | +|------------------------|----------------------------------------------------------------------| +| Chef de projet | Peut changer les paramètres du projet, accéder aux rapports | +| Membre du projet | Peut créer des tâches et utiliser le tableau Kanban | +| Visualiseur de projet | Accès en lecture seule au projet | diff --git a/doc/fr_FR/screenshots.markdown b/doc/fr_FR/screenshots.markdown new file mode 100644 index 00000000..e634bd1b --- /dev/null +++ b/doc/fr_FR/screenshots.markdown @@ -0,0 +1,26 @@ +Ajouter des captures d'écran +================== + +Vous pouvez copier-coller des images directement dans Kanboard pour gagner du temps. +Ces images sont mises en ligne en tant que pièces jointes à une tâche. + +Ceci est particulièrement utile pour prendre des captures d'écran, quand il faut par exemple décrire un problème. + +Vous pouvez ajouter directement des captures depuis le tableau en cliquant sur le menu déroulant ou sur la page de visualisation des tâches. + +![La capture d'écran dans le menu déroulant](https://kanboard.net/screenshots/documentation/dropdown-screenshot.png) + +Pour ajouter une nouvelle image, prenez votre capture et collez-la avec CTRL+V ou Command+V: + +![Page de capture](https://kanboard.net/screenshots/documentation/task-screenshot.png) + +Avec Mac OS X, vous pouvez utiliser les raccourcis suivants pour prendre des captures d'écran : + +- Command-Control-Maj-3 : prend une capture de l'écran entier et l'enregistre dans le presse-papiers +- Command-Control-Maj-4, puis choix d'une zone : prend une capture d'une zone définie et l'enregistre dans le presse-papiers +- Command-Control-Maj-4, puis touche espace, puis clic sur une fenêtre : prend une capture d'une fenêtre et l'enregistre dans le presse-papiers + +Il existe plusieurs applications tierces qui peuvent être utilisées pour prendre des captures d'écran avec des annotations et un choix de formes. + +**Remarque : cette fonctionnalité n'est pas disponible sur tous les navigateurs.** Elle n'existe pas pour Safari en raison de ce bug : https://bugs.webkit.org/show_bug.cgi?id=49141 + diff --git a/doc/fr_FR/screenshots/automatic-action-creation.png b/doc/fr_FR/screenshots/automatic-action-creation.png new file mode 100644 index 00000000..ad90590d Binary files /dev/null and b/doc/fr_FR/screenshots/automatic-action-creation.png differ diff --git a/doc/fr_FR/screenshots/board-collapsed-mode.png b/doc/fr_FR/screenshots/board-collapsed-mode.png new file mode 100644 index 00000000..a496faff Binary files /dev/null and b/doc/fr_FR/screenshots/board-collapsed-mode.png differ diff --git a/doc/fr_FR/screenshots/board-compact-mode.png b/doc/fr_FR/screenshots/board-compact-mode.png new file mode 100644 index 00000000..872ceae5 Binary files /dev/null and b/doc/fr_FR/screenshots/board-compact-mode.png differ diff --git a/doc/fr_FR/screenshots/board-expanded-mode.png b/doc/fr_FR/screenshots/board-expanded-mode.png new file mode 100644 index 00000000..19f61451 Binary files /dev/null and b/doc/fr_FR/screenshots/board-expanded-mode.png differ diff --git a/doc/fr_FR/screenshots/board-task-limit.png b/doc/fr_FR/screenshots/board-task-limit.png new file mode 100644 index 00000000..8353f33c Binary files /dev/null and b/doc/fr_FR/screenshots/board-task-limit.png differ diff --git a/doc/fr_FR/screenshots/board-view.png b/doc/fr_FR/screenshots/board-view.png new file mode 100644 index 00000000..0d1e18ea Binary files /dev/null and b/doc/fr_FR/screenshots/board-view.png differ diff --git a/doc/fr_FR/screenshots/calendar-view.png b/doc/fr_FR/screenshots/calendar-view.png new file mode 100644 index 00000000..1226162b Binary files /dev/null and b/doc/fr_FR/screenshots/calendar-view.png differ diff --git a/doc/fr_FR/screenshots/gantt-view.png b/doc/fr_FR/screenshots/gantt-view.png new file mode 100644 index 00000000..3caafa98 Binary files /dev/null and b/doc/fr_FR/screenshots/gantt-view.png differ diff --git a/doc/fr_FR/screenshots/hide-column.png b/doc/fr_FR/screenshots/hide-column.png new file mode 100644 index 00000000..61015f9a Binary files /dev/null and b/doc/fr_FR/screenshots/hide-column.png differ diff --git a/doc/fr_FR/screenshots/list-view.png b/doc/fr_FR/screenshots/list-view.png new file mode 100644 index 00000000..c40e807a Binary files /dev/null and b/doc/fr_FR/screenshots/list-view.png differ diff --git a/doc/fr_FR/screenshots/new-project.png b/doc/fr_FR/screenshots/new-project.png new file mode 100644 index 00000000..42e5f196 Binary files /dev/null and b/doc/fr_FR/screenshots/new-project.png differ diff --git a/doc/fr_FR/screenshots/new-user.png b/doc/fr_FR/screenshots/new-user.png new file mode 100644 index 00000000..116e9074 Binary files /dev/null and b/doc/fr_FR/screenshots/new-user.png differ diff --git a/doc/fr_FR/screenshots/project-disable-sharing.png b/doc/fr_FR/screenshots/project-disable-sharing.png new file mode 100644 index 00000000..58832045 Binary files /dev/null and b/doc/fr_FR/screenshots/project-disable-sharing.png differ diff --git a/doc/fr_FR/screenshots/project-edition.png b/doc/fr_FR/screenshots/project-edition.png new file mode 100644 index 00000000..ce8594fe Binary files /dev/null and b/doc/fr_FR/screenshots/project-edition.png differ diff --git a/doc/fr_FR/screenshots/project-enable-sharing.png b/doc/fr_FR/screenshots/project-enable-sharing.png new file mode 100644 index 00000000..147ccc53 Binary files /dev/null and b/doc/fr_FR/screenshots/project-enable-sharing.png differ diff --git a/doc/fr_FR/screenshots/project-permissions.png b/doc/fr_FR/screenshots/project-permissions.png new file mode 100644 index 00000000..54f38690 Binary files /dev/null and b/doc/fr_FR/screenshots/project-permissions.png differ diff --git a/doc/fr_FR/screenshots/project-view.png b/doc/fr_FR/screenshots/project-view.png new file mode 100644 index 00000000..ff9a7f76 Binary files /dev/null and b/doc/fr_FR/screenshots/project-view.png differ diff --git a/doc/fr_FR/screenshots/show-column.png b/doc/fr_FR/screenshots/show-column.png new file mode 100644 index 00000000..51f78ac8 Binary files /dev/null and b/doc/fr_FR/screenshots/show-column.png differ diff --git a/doc/fr_FR/screenshots/swimlane-configuration.png b/doc/fr_FR/screenshots/swimlane-configuration.png new file mode 100644 index 00000000..d0b25e9c Binary files /dev/null and b/doc/fr_FR/screenshots/swimlane-configuration.png differ diff --git a/doc/fr_FR/screenshots/swimlanes.png b/doc/fr_FR/screenshots/swimlanes.png new file mode 100644 index 00000000..e24a5b85 Binary files /dev/null and b/doc/fr_FR/screenshots/swimlanes.png differ diff --git a/doc/fr_FR/sharing-projects.markdown b/doc/fr_FR/sharing-projects.markdown new file mode 100644 index 00000000..f3db3c68 --- /dev/null +++ b/doc/fr_FR/sharing-projects.markdown @@ -0,0 +1,35 @@ +Partager des tableaux et des tâches +=================================== + +Par défaut, les tableaux sont privés, mais il est possible de rendre un tableau public. + +Un tableau public ne **peut pas être modifié, il est en lecture seule**. +Son accès est protégé par un jeton aléatoire, seules les personnes qui ont la bonne URL peuvent voir le tableau. + +Les tableaux publics sont automatiquement réactualisés toutes les minutes. +Les détails des tâches sont disponibles en lecture seule. + +Exemples d'utilisation : + +- Partager son tableau avec quelqu'un qui ne fait pas partie de votre organisation / entreprise / groupe +- Afficher le tableau sur un grand écran dans votre bureau + +Activer l'accès public +---------------------- + +Choisissez votre projet, puis cliquez sur « Accès public » et enfin sur le bouton « Activer l'accès public ». + +![Activer l'accès public](screenshots/project-enable-sharing.png) + +Lorsque l'accès public est activé, plusieurs liens sont créés : + +- Affichage du tableau public +- Lien de souscription au fil RSS +- Lien d'abonnement à iCalendar + +![Désactiver l'accès public](screenshots/project-disable-sharing.png) + +Vous pouvez désactiver l'accès public à tout moment. + +À chaque fois que vous activez ou désactivez l'accès public, un nouveau jeton aléatoire est créé. +**Les liens précédents ne fonctionneront pas**. diff --git a/doc/fr_FR/subtasks.markdown b/doc/fr_FR/subtasks.markdown new file mode 100644 index 00000000..02345c2a --- /dev/null +++ b/doc/fr_FR/subtasks.markdown @@ -0,0 +1,43 @@ +Sous-tâches +======== + +Les sous-tâches sont utiles pour se partager le travail que représente une tâche. + +Chaque sous-tâche : + +- peut être assignée à un membre du projet +- a trois différents statuts : **À faire**, **En cours**, **Terminé** +- dispose d'informations sur le temps de travail : **temps passé** et **temps estimé** +- est classée en fonction de sa position + +Créer des sous-tâches +----------------- + +Depuis la vue par tâche, cliquez sur **Ajouter une sous-tâche** dans le panneau latéral. + +![Ajouter une sous-tâche](https://kanboard.net/screenshots/documentation/add-subtask.png) + +Vous pouvez aussi ajouter rapidement une sous-tâche en saisissant seulement son titre : + +![Add a subtask from the task view](https://kanboard.net/screenshots/documentation/add-subtask-shortcut.png) + +Modifier le statut d'une sous-tâche +--------------------- + +Quand vous cliquez sur le titre d'une sous-tâche son statut change : + +![Sous-tâche en cours](https://kanboard.net/screenshots/documentation/subtask-status-inprogress.png) + +L'icône devant le titre est mise à jour en fonction du statut. + +![Sous-tâche effectuée](https://kanboard.net/screenshots/documentation/subtask-status-done.png) + +Remarque : quand la tâche est fermée, toutes les sous-tâches voient leur statut passer à **Terminé**. + +Chrono des sous-tâches +------------- + +- À chaque fois qu'une sous-tâche est en cours de réalisation, le chronomètre est également démarré. Il peut être lancé et interrompu à tout moment. +- Le chronomètre enregistre automatiquement le temps passé sur la sous-tâche. Vous pouvez aussi modifier manuellement la valeur du temps passé dans le champ adéquat quand vous modifiez une sous-tâche. +- Le temps passé est arrondi au quart d'heure le plus proche. Cette information est enregistrée dans un tableau distinct. +- Le temps passé à la tâche ainsi que le temps estimé sont automatiquement mis à jour en fonction de la somme de toutes les sous-tâches. diff --git a/doc/fr_FR/swimlanes.markdown b/doc/fr_FR/swimlanes.markdown new file mode 100644 index 00000000..92b4a9fa --- /dev/null +++ b/doc/fr_FR/swimlanes.markdown @@ -0,0 +1,29 @@ +Swimlanes +========= + +Les *swimlanes* sont des séparations horizontales de votre tableau (pensez à des « couloirs » ou « lignes d'eau » dans une piscine). + +Par exemple, cela peut servir à séparer les sorties des différentes versions d'un logiciel, à diviser vos tâches selon différents produits, équipes ou tout autre critère de votre choix. + +Tableau avec des swimlanes +-------------------------- + +![Swimlanes](screenshots/swimlanes.png) + +Gestion des swimlanes +------------------ + +- Tous les projets ont une swimlane par défaut. +- S'il existe plus d'une swimlane, le tableau les affichera toutes. +- Vous pouvez glisser-déposer les tâches d'une swimlane à l'autre. + +Pour configurer les swimlanes allez sur la page de **Configuration du projet** et choisissez la section **Swimlanes**. + +![Swimlanes Configuration](screenshots/swimlane-configuration.png) + +À partir de cet endroit, vous pouvez ajouter une nouvelle swimlane ou renommer celle qui existe par défaut. +Vous pouvez aussi désactiver et modifier la position des diverses swimlanes. + +- La swimlane par défaut est toujours en haut de tableau mais vous pouvez la cacher. +- Les swimlanes inactives ne sont pas affichées dans le tableau. +- **Supprimer une swimlane ne supprime pas les tâches qui lui sont assignées**, ces tâches seront transférées à la swimlane par défaut. diff --git a/doc/fr_FR/task-links.markdown b/doc/fr_FR/task-links.markdown new file mode 100644 index 00000000..f2756ac7 --- /dev/null +++ b/doc/fr_FR/task-links.markdown @@ -0,0 +1,22 @@ +Liens entre les tâches +========== + +Les tâches peuvent être liées ensemble avec des relations prédéfinies. + +![Task Links](https://kanboard.net/screenshots/documentation/task-links.png) + +Les relations établies par défaut sont les suivantes : + +- **fait référence à** +- **bloque** | est bloqué par +- **est bloqué par** | bloque +- **duplique** | est dupliqué par +- **est dupliqué par** | duplique +- **est un enfant de** | est un parent de +- **est un parent de** | est un enfant de +- **vise les étapes importantes** | est une étape importante de +- **est une étape importante de** | vise les étapes importantes +- **correctifs** | est réglé par +- **est réglé par** | correctifs + +Ces étiquettes peuvent être modifiées dans les paramètres de l'application. diff --git a/doc/fr_FR/time-tracking.markdown b/doc/fr_FR/time-tracking.markdown new file mode 100644 index 00000000..625bc26f --- /dev/null +++ b/doc/fr_FR/time-tracking.markdown @@ -0,0 +1,44 @@ +Suivi du temps +============= + +Les informations de la feuille de suivi du temps peuvent être définies au niveau des tâches ou des sous-tâches + +Suivi de temps des tâches +------------------ + +![Suivi de temps des tâches ](https://kanboard.net/screenshots/documentation/task-time-tracking.png) + +Les tâches ont deux champs: + +- Temps estimé +- Temps passé + +Ces valeurs représentent des heures de travail et doivent être entrées manuellement. + + +Suivi de temps des sous-tâches +--------------------- + +![Suivi de temps des sous-tâches](https://kanboard.net/screenshots/documentation/subtask-time-tracking.png) + +Les sous-tâches ont aussi les champs "temps passé" et "temps estimé" + +Lorsque vous changez la valeur de ces champs, **le suivi des tâches est mis à jour automatiquement et devient la somme des sous-tâches**. + +Kanboard enregistre le temps entre chaque changement de statut des sous-tâches dans une table séparée + +- Changer le statut de la sous-tâche de **à faire** à **en cours** marque le temps de début +- Changer le statut de la sous-tâche de **en cours** à **à faire** marque le temps de fin mais aussi met à jour le temps passé sur la sous-tâche et la tâche + +La répartition de tous les enregistrements est visible sur la page de la tâche + +![Feuille de suivi du temps pour les tâches](https://kanboard.net/screenshots/documentation/task-timesheet.png) + +Pour chaque sous-tâche, le chrono peut être à tout moment arrêté/démarré + +![Chrono des sous-tâches](https://kanboard.net/screenshots/documentation/subtask-timer.png) + +- Le chrono ne dépend pas du statut de la sous-tâche +- Chaque fois que vous démarrez le chrono, un nouvel enregistrement est créé dans la table de suivi des temps +- Chaque fois que vous arrêtez l'horloge, la date de fin est enregistrée dans la table de suivi des temps +- Le temps passé est arrondi au quart d’heure le plus proche diff --git a/doc/fr_FR/transitions.markdown b/doc/fr_FR/transitions.markdown new file mode 100644 index 00000000..94a14bbc --- /dev/null +++ b/doc/fr_FR/transitions.markdown @@ -0,0 +1,20 @@ +Transitions entre les tâches +================ + +Les transitions enregistrent tous les mouvements des tâches entre les colonnes + +![Transitions](https://kanboard.net/screenshots/documentation/transitions.png) + +Depuis la page des tâches, vous pouvez accéder à ces informations: + +- Date de l'action +- Colonne d'origine +- Colonne de destination +- Exécutant (Pour l'utilisateur qui a déplacé la tâche) +- Temps passé sur la colonne d’origine + +Les données de transition entre les tâches peuvent aussi être exportées depuis la page des paramètres du projet + +![Transitions Export](https://kanboard.net/screenshots/documentation/transitions-export.png) + +Pour la période spécifiée, vous allez générer un fichier CSV que vous pouvez utiliser avec n’importe quel tableur diff --git a/doc/fr_FR/usage-examples.markdown b/doc/fr_FR/usage-examples.markdown new file mode 100644 index 00000000..b91fa613 --- /dev/null +++ b/doc/fr_FR/usage-examples.markdown @@ -0,0 +1,69 @@ +Exemples d'utilisation +============== +Il est possible de personnaliser ses tableaux selon l'activité de votre entreprise : + +Développement logiciel +-------------------- + +- Prévu +- Prêt +- En cours +- À valider +- Validé +- En production + +Suivi de bogues +------------ + +- Rapporté +- Confirmé +- En cours +- Testé +- Résolu + +Ventes +----- + +- Objectifs +- Réunions +- Propositions +- Achats + +Gestion au plus juste +------------------------ + +- Idées +- Expression de la demande +- Étude de marché +- Analyses +- Fait + + +Procédure de recrutement +------------------ + +- Offres d'emploi +- Candidats +- Appels téléphoniques +- Entretiens +- Embauches + +Boutiques en ligne +------------ + +- Commande +- Empaquetage +- Prêt à envoyer +- Envoyé + +Artisanat +----------- + +- Commande +- Assemblage +- Tests +- Empaquetage +- Prêt à envoyer +- Envoyé + + diff --git a/doc/fr_FR/user-management.markdown b/doc/fr_FR/user-management.markdown new file mode 100644 index 00000000..bb9b0731 --- /dev/null +++ b/doc/fr_FR/user-management.markdown @@ -0,0 +1,35 @@ +Gestion des utilisateurs +======================== + +Ajouter un nouvel utilisateur +----------------------------- + +Pour ajouter un nouvel utilisateur, vous devez être administrateur. + +1. Depuis le menu déroulant situé en haut à droite, cliquez sur **Gestion des utilisateurs** +2. Dans la partie haute vous avez un lien **Créer un utilisateur local** ou **Créer un utilisateur distant** +3. Informez les champs de saisie et enregistrez + +![Nouvel utilisateur](screenshots/new-user.png) + +Quand vous créez un **utilisateur local**, vous devez préciser au moins deux valeurs : + +- **nom d'utilisateur** : c'est l'identifiant unique de votre utilisateur (login) +- **mot de passe** : le mot de passe de votre utilisateur doit comporter au moins 6 caractères + +Pour les **utilisateurs distants**, seul le nom d'utilisateur est obligatoire. + +Modifier des utilisateurs +------------------------- + +Quand vous allez au menu **utilisateurs**, vous disposez d'une liste d'utilisateurs. Pour modifier un utilisateur cliquez sur le lien **Modifier**. + +- si vous êtes un utilisateur ordinaire, vous ne pouvez modifier que votre propre profil +- vous devez être administrateur pour pouvoir modifier n'importe quel utilisateur + +Supprimer des utilisateurs +-------------------------- + +Depuis le menu **utilisateurs**, cliquez sur le lien **supprimer**. Ce lien n'est visible que si vous êtes administrateur. + +Si vous supprimez un utilisateur particulier, **les tâches assignées à cette personne ne lui seront plus assignées** après cette opération. diff --git a/doc/fr_FR/what-is-kanban.markdown b/doc/fr_FR/what-is-kanban.markdown new file mode 100644 index 00000000..f479927c --- /dev/null +++ b/doc/fr_FR/what-is-kanban.markdown @@ -0,0 +1,34 @@ +Qu'est-ce que Kanban? +=============== + + +Kanban est une méthodologie développée à l'origine par l'entreprise Toyota pour gagner en efficacité. + +Kanban n'impose que deux contraintes : + +- Visualiser votre flux d'activité +- Limiter votre travail en cours + +Visualiser votre flux d'activité +----------------------- + +- Votre activité est affichée sur un tableau, vous disposez ainsi d'une vue très nette sur l'ensemble de votre projet +- Chaque colonne représente une étape de votre flux d'activité + +Se concentrer sur une seule tâche à la fois sans disperser son activité +---------------------------------- + +- Chaque phase peut avoir sa date d'échéance +- Les limites fixées sont très utiles pour identifier les goulots d'étranglement +- Les limites évitent de travailler à un trop grand nombre de tâches à la fois + +Mesure des performances et des progrès +----------------------------------- + +Kanban utilise lead time et cycle times pour mesurer les performances : + +- **Lead time** : le *lead time* est la durée entre la création de la tâche et son achèvement. +- **Cycle time** : le *cycle time* est la durée entre la date de début et l'achèvement. + +Par exemple, vous pouvez avoir un *lead time* de 100 jours et n'avoir à travailler qu'une heure pour achever la tâche. + -- cgit v1.2.3 From 95751f391f336faf82ee2402a559247aef668e72 Mon Sep 17 00:00:00 2001 From: Frederic Guillot Date: Thu, 23 Jun 2016 15:43:37 -0400 Subject: Fixed broken CSV export --- ChangeLog | 4 ++++ app/Controller/ExportController.php | 33 +++++++++++++++++---------------- 2 files changed, 21 insertions(+), 16 deletions(-) (limited to 'app') diff --git a/ChangeLog b/ChangeLog index 20ffbca1..0277af69 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,10 @@ Improvements: * Make embedded documentation available in multiple languages +Bug fixes: + +* Fixed broken CSV exports + Version 1.0.30 -------------- diff --git a/app/Controller/ExportController.php b/app/Controller/ExportController.php index b2fe0ebd..27046c76 100644 --- a/app/Controller/ExportController.php +++ b/app/Controller/ExportController.php @@ -31,22 +31,23 @@ class ExportController extends BaseController $data = $this->$model->$method($project['id'], $from, $to); $this->response->withFileDownload($filename.'.csv'); $this->response->csv($data); - } + } else { - $this->response->html($this->helper->layout->project('export/'.$action, array( - 'values' => array( - 'controller' => 'ExportController', - 'action' => $action, - 'project_id' => $project['id'], - 'from' => $from, - 'to' => $to, - ), - 'errors' => array(), - 'date_format' => $this->configModel->get('application_date_format'), - 'date_formats' => $this->dateParser->getAvailableFormats($this->dateParser->getDateFormats()), - 'project' => $project, - 'title' => $page_title, - ), 'export/sidebar')); + $this->response->html($this->helper->layout->project('export/'.$action, array( + 'values' => array( + 'controller' => 'ExportController', + 'action' => $action, + 'project_id' => $project['id'], + 'from' => $from, + 'to' => $to, + ), + 'errors' => array(), + 'date_format' => $this->configModel->get('application_date_format'), + 'date_formats' => $this->dateParser->getAvailableFormats($this->dateParser->getDateFormats()), + 'project' => $project, + 'title' => $page_title, + ), 'export/sidebar')); + } } /** @@ -76,7 +77,7 @@ class ExportController extends BaseController */ public function summary() { - $this->common('projectDailyColumnStats', 'getAggregatedMetrics', t('Summary'), 'summary', t('Daily project summary export')); + $this->common('projectDailyColumnStatsModel', 'getAggregatedMetrics', t('Summary'), 'summary', t('Daily project summary export')); } /** -- cgit v1.2.3 From d560f84b374fa1b3345dc582eddd6bb7b9138674 Mon Sep 17 00:00:00 2001 From: Frederic Guillot Date: Thu, 23 Jun 2016 20:26:19 -0400 Subject: Added models for tags --- app/Core/Base.php | 2 + app/Model/TagModel.php | 139 +++++++++++++++++++++++++++++++++ app/Model/TaskTagModel.php | 125 +++++++++++++++++++++++++++++ app/Schema/Mysql.php | 25 +++++- app/Schema/Postgres.php | 24 +++++- app/Schema/Sqlite.php | 24 +++++- app/ServiceProvider/ClassProvider.php | 2 + tests/units/Model/TagModelTest.php | 120 ++++++++++++++++++++++++++++ tests/units/Model/TaskTagModelTest.php | 67 ++++++++++++++++ 9 files changed, 525 insertions(+), 3 deletions(-) create mode 100644 app/Model/TagModel.php create mode 100644 app/Model/TaskTagModel.php create mode 100644 tests/units/Model/TagModelTest.php create mode 100644 tests/units/Model/TaskTagModelTest.php (limited to 'app') diff --git a/app/Core/Base.php b/app/Core/Base.php index 7b4462e2..6712cbce 100644 --- a/app/Core/Base.php +++ b/app/Core/Base.php @@ -86,6 +86,7 @@ use Pimple\Container; * @property \Kanboard\Model\SubtaskModel $subtaskModel * @property \Kanboard\Model\SubtaskTimeTrackingModel $subtaskTimeTrackingModel * @property \Kanboard\Model\SwimlaneModel $swimlaneModel + * @property \Kanboard\Model\TagModel $tagModel * @property \Kanboard\Model\TaskModel $taskModel * @property \Kanboard\Model\TaskAnalyticModel $taskAnalyticModel * @property \Kanboard\Model\TaskCreationModel $taskCreationModel @@ -96,6 +97,7 @@ use Pimple\Container; * @property \Kanboard\Model\TaskModificationModel $taskModificationModel * @property \Kanboard\Model\TaskPositionModel $taskPositionModel * @property \Kanboard\Model\TaskStatusModel $taskStatusModel + * @property \Kanboard\Model\TaskTagModel $taskTagModel * @property \Kanboard\Model\TaskMetadataModel $taskMetadataModel * @property \Kanboard\Model\TimezoneModel $timezoneModel * @property \Kanboard\Model\TransitionModel $transitionModel diff --git a/app/Model/TagModel.php b/app/Model/TagModel.php new file mode 100644 index 00000000..1be05a66 --- /dev/null +++ b/app/Model/TagModel.php @@ -0,0 +1,139 @@ +db->table(self::TABLE)->asc('name')->findAll(); + } + + /** + * Get all tags by project + * + * @access public + * @param integer $project_id + * @return array + */ + public function getAllByProject($project_id) + { + return $this->db->table(self::TABLE)->eq('project_id', $project_id)->asc('name')->findAll(); + } + + /** + * Get one tag + * + * @access public + * @param integer $tag_id + * @return array|null + */ + public function getById($tag_id) + { + return $this->db->table(self::TABLE)->eq('id', $tag_id)->findOne(); + } + + /** + * Get tag id from tag name + * + * @access public + * @param int $project_id + * @param string $tag + * @return integer + */ + public function getIdByName($project_id, $tag) + { + return $this->db + ->table(self::TABLE) + ->beginOr() + ->eq('project_id', 0) + ->eq('project_id', $project_id) + ->closeOr() + ->ilike('name', $tag) + ->asc('project_id') + ->findOneColumn('id'); + } + + /** + * Return tag id and create a new tag if necessary + * + * @access public + * @param int $project_id + * @param string $tag + * @return bool|int + */ + public function findOrCreateTag($project_id, $tag) + { + $tag_id = $this->getIdByName($project_id, $tag); + + if (empty($tag_id)) { + $tag_id = $this->create($project_id, $tag); + } + + return $tag_id; + } + + /** + * Add a new tag + * + * @access public + * @param int $project_id + * @param string $tag + * @return bool|int + */ + public function create($project_id, $tag) + { + return $this->db->table(self::TABLE)->persist(array( + 'project_id' => $project_id, + 'name' => $tag, + )); + } + + /** + * Update a tag + * + * @access public + * @param integer $tag_id + * @param string $tag + * @return bool + */ + public function update($tag_id, $tag) + { + return $this->db->table(self::TABLE)->eq('id', $tag_id)->update(array( + 'name' => $tag, + )); + } + + /** + * Remove a tag + * + * @access public + * @param integer $tag_id + * @return bool + */ + public function remove($tag_id) + { + return $this->db->table(self::TABLE)->eq('id', $tag_id)->remove(); + } +} diff --git a/app/Model/TaskTagModel.php b/app/Model/TaskTagModel.php new file mode 100644 index 00000000..74d82539 --- /dev/null +++ b/app/Model/TaskTagModel.php @@ -0,0 +1,125 @@ +db->table(TagModel::TABLE) + ->columns(TagModel::TABLE.'.id', TagModel::TABLE.'.name') + ->eq(self::TABLE.'.task_id', $task_id) + ->join(self::TABLE, 'tag_id', 'id') + ->findAll(); + } + + /** + * Get dictionary of tags + * + * @access public + * @param integer $task_id + * @return array + */ + public function getList($task_id) + { + $tags = $this->getAll($task_id); + return array_column($tags, 'name', 'id'); + } + + /** + * Add or update a list of tags to a task + * + * @access public + * @param integer $project_id + * @param integer $task_id + * @param string[] $tags + * @return boolean + */ + public function save($project_id, $task_id, array $tags) + { + $task_tags = $this->getList($task_id); + + return $this->addTags($project_id, $task_id, $task_tags, $tags) && + $this->removeTags($task_id, $task_tags, $tags); + } + + /** + * Associate a tag to a task + * + * @access public + * @param integer $task_id + * @param integer $tag_id + * @return boolean + */ + public function associate($task_id, $tag_id) + { + return $this->db->table(self::TABLE)->insert(array( + 'task_id' => $task_id, + 'tag_id' => $tag_id, + )); + } + + /** + * Dissociate a tag from a task + * + * @access public + * @param integer $task_id + * @param integer $tag_id + * @return boolean + */ + public function dissociate($task_id, $tag_id) + { + return $this->db->table(self::TABLE) + ->eq('task_id', $task_id) + ->eq('tag_id', $tag_id) + ->remove(); + } + + private function addTags($project_id, $task_id, $task_tags, $tags) + { + foreach ($tags as $tag) { + $tag_id = $this->tagModel->findOrCreateTag($project_id, $tag); + + if (! isset($task_tags[$tag_id]) && ! $this->associate($task_id, $tag_id)) { + return false; + } + } + + return true; + } + + private function removeTags($task_id, $task_tags, $tags) + { + foreach ($task_tags as $tag_id => $tag) { + if (! in_array($tag, $tags)) { + if (! $this->dissociate($task_id, $tag_id)) { + return false; + } + } + } + + return true; + } +} diff --git a/app/Schema/Mysql.php b/app/Schema/Mysql.php index 934b063f..82ccb8c8 100644 --- a/app/Schema/Mysql.php +++ b/app/Schema/Mysql.php @@ -6,7 +6,30 @@ use PDO; use Kanboard\Core\Security\Token; use Kanboard\Core\Security\Role; -const VERSION = 110; +const VERSION = 111; + +function version_111(PDO $pdo) +{ + $pdo->exec(" + CREATE TABLE tags ( + id INT NOT NULL AUTO_INCREMENT, + name VARCHAR(255) NOT NULL, + project_id INT NOT NULL, + UNIQUE(project_id, name), + PRIMARY KEY(id) + ) ENGINE=InnoDB CHARSET=utf8 + "); + + $pdo->exec(" + CREATE TABLE task_has_tags ( + task_id INT NOT NULL, + tag_id INT NOT NULL, + FOREIGN KEY(task_id) REFERENCES tasks(id) ON DELETE CASCADE, + FOREIGN KEY(tag_id) REFERENCES tags(id) ON DELETE CASCADE, + UNIQUE(tag_id, task_id) + ) ENGINE=InnoDB CHARSET=utf8 + "); +} function version_110(PDO $pdo) { diff --git a/app/Schema/Postgres.php b/app/Schema/Postgres.php index 3ef49498..229cbd25 100644 --- a/app/Schema/Postgres.php +++ b/app/Schema/Postgres.php @@ -6,7 +6,29 @@ use PDO; use Kanboard\Core\Security\Token; use Kanboard\Core\Security\Role; -const VERSION = 89; +const VERSION = 90; + +function version_90(PDO $pdo) +{ + $pdo->exec(" + CREATE TABLE tags ( + id SERIAL PRIMARY KEY, + name VARCHAR(255) NOT NULL, + project_id INTEGER NOT NULL, + UNIQUE(project_id, name) + ) + "); + + $pdo->exec(" + CREATE TABLE task_has_tags ( + task_id INTEGER NOT NULL, + tag_id INTEGER NOT NULL, + FOREIGN KEY(task_id) REFERENCES tasks(id) ON DELETE CASCADE, + FOREIGN KEY(tag_id) REFERENCES tags(id) ON DELETE CASCADE, + UNIQUE(tag_id, task_id) + ) + "); +} function version_89(PDO $pdo) { diff --git a/app/Schema/Sqlite.php b/app/Schema/Sqlite.php index 9ded7ed9..dac348d4 100644 --- a/app/Schema/Sqlite.php +++ b/app/Schema/Sqlite.php @@ -6,7 +6,29 @@ use Kanboard\Core\Security\Token; use Kanboard\Core\Security\Role; use PDO; -const VERSION = 101; +const VERSION = 102; + +function version_102(PDO $pdo) +{ + $pdo->exec(" + CREATE TABLE tags ( + id INTEGER PRIMARY KEY, + name TEXT NOT NULL, + project_id INTEGER NOT NULL, + UNIQUE(project_id, name) + ) + "); + + $pdo->exec(" + CREATE TABLE task_has_tags ( + task_id INTEGER NOT NULL, + tag_id INTEGER NOT NULL, + FOREIGN KEY(task_id) REFERENCES tasks(id) ON DELETE CASCADE, + FOREIGN KEY(tag_id) REFERENCES tags(id) ON DELETE CASCADE, + UNIQUE(tag_id, task_id) + ) + "); +} function version_101(PDO $pdo) { diff --git a/app/ServiceProvider/ClassProvider.php b/app/ServiceProvider/ClassProvider.php index 3e6efb02..778b4f9e 100644 --- a/app/ServiceProvider/ClassProvider.php +++ b/app/ServiceProvider/ClassProvider.php @@ -60,6 +60,7 @@ class ClassProvider implements ServiceProviderInterface 'SubtaskModel', 'SubtaskTimeTrackingModel', 'SwimlaneModel', + 'TagModel', 'TaskModel', 'TaskAnalyticModel', 'TaskCreationModel', @@ -71,6 +72,7 @@ class ClassProvider implements ServiceProviderInterface 'TaskModificationModel', 'TaskPositionModel', 'TaskStatusModel', + 'TaskTagModel', 'TaskMetadataModel', 'TimezoneModel', 'TransitionModel', diff --git a/tests/units/Model/TagModelTest.php b/tests/units/Model/TagModelTest.php new file mode 100644 index 00000000..f090ab4a --- /dev/null +++ b/tests/units/Model/TagModelTest.php @@ -0,0 +1,120 @@ +container); + $projectModel = new ProjectModel($this->container); + + $this->assertEquals(1, $projectModel->create(array('name' => 'Test'))); + $this->assertEquals(1, $tagModel->create(0, 'Tag 1')); + $this->assertEquals(2, $tagModel->create(1, 'Tag 1')); + $this->assertEquals(3, $tagModel->create(1, 'Tag 2')); + $this->assertFalse($tagModel->create(0, 'Tag 1')); + $this->assertFalse($tagModel->create(1, 'Tag 2')); + } + + public function testGetById() + { + $tagModel = new TagModel($this->container); + $this->assertEquals(1, $tagModel->create(0, 'Tag 1')); + + $tag = $tagModel->getById(1); + $this->assertEquals(0, $tag['project_id']); + $this->assertEquals('Tag 1', $tag['name']); + + $tag = $tagModel->getById(3); + $this->assertEmpty($tag); + } + + public function testGetAll() + { + $tagModel = new TagModel($this->container); + $projectModel = new ProjectModel($this->container); + + $this->assertEquals(1, $projectModel->create(array('name' => 'Test'))); + $this->assertEquals(1, $tagModel->create(0, 'Tag 1')); + $this->assertEquals(2, $tagModel->create(1, 'Tag 2')); + + $tags = $tagModel->getAll(); + $this->assertCount(2, $tags); + $this->assertEquals(0, $tags[0]['project_id']); + $this->assertEquals('Tag 1', $tags[0]['name']); + + $this->assertEquals(1, $tags[1]['project_id']); + $this->assertEquals('Tag 2', $tags[1]['name']); + } + + public function testGetAllByProjectId() + { + $tagModel = new TagModel($this->container); + $projectModel = new ProjectModel($this->container); + + $this->assertEquals(1, $projectModel->create(array('name' => 'Test'))); + $this->assertEquals(1, $tagModel->create(0, 'Tag 1')); + $this->assertEquals(2, $tagModel->create(1, 'B')); + $this->assertEquals(3, $tagModel->create(1, 'A')); + + $tags = $tagModel->getAllByProject(1); + $this->assertCount(2, $tags); + $this->assertEquals(1, $tags[0]['project_id']); + $this->assertEquals('A', $tags[0]['name']); + + $this->assertEquals(1, $tags[1]['project_id']); + $this->assertEquals('B', $tags[1]['name']); + } + + public function testGetIdByName() + { + $tagModel = new TagModel($this->container); + $projectModel = new ProjectModel($this->container); + + $this->assertEquals(1, $projectModel->create(array('name' => 'Test'))); + $this->assertEquals(1, $tagModel->create(0, 'Tag 1')); + $this->assertEquals(2, $tagModel->create(1, 'Tag 1')); + $this->assertEquals(3, $tagModel->create(1, 'Tag 3')); + + $this->assertEquals(1, $tagModel->getIdByName(1, 'tag 1')); + $this->assertEquals(1, $tagModel->getIdByName(0, 'tag 1')); + $this->assertEquals(3, $tagModel->getIdByName(1, 'TaG 3')); + } + + public function testFindOrCreateTag() + { + $tagModel = new TagModel($this->container); + $projectModel = new ProjectModel($this->container); + + $this->assertEquals(1, $projectModel->create(array('name' => 'Test'))); + $this->assertEquals(1, $tagModel->create(0, 'Tag 1')); + + $this->assertEquals(2, $tagModel->findOrCreateTag(1, 'Tag 2')); + $this->assertEquals(2, $tagModel->findOrCreateTag(1, 'Tag 2')); + $this->assertEquals(1, $tagModel->findOrCreateTag(1, 'Tag 1')); + } + + public function testRemove() + { + $tagModel = new TagModel($this->container); + $this->assertEquals(1, $tagModel->create(0, 'Tag 1')); + + $this->assertTrue($tagModel->remove(1)); + $this->assertFalse($tagModel->remove(1)); + } + + public function testUpdate() + { + $tagModel = new TagModel($this->container); + $this->assertEquals(1, $tagModel->create(0, 'Tag 1')); + $this->assertTrue($tagModel->update(1, 'Tag Updated')); + + $tag = $tagModel->getById(1); + $this->assertEquals(0, $tag['project_id']); + $this->assertEquals('Tag Updated', $tag['name']); + } +} diff --git a/tests/units/Model/TaskTagModelTest.php b/tests/units/Model/TaskTagModelTest.php new file mode 100644 index 00000000..c08b571f --- /dev/null +++ b/tests/units/Model/TaskTagModelTest.php @@ -0,0 +1,67 @@ +container); + $taskCreationModel = new TaskCreationModel($this->container); + $taskTagModel = new TaskTagModel($this->container); + $tagModel = new TagModel($this->container); + + $this->assertEquals(1, $projectModel->create(array('name' => 'Test'))); + $this->assertEquals(1, $taskCreationModel->create(array('project_id' => 1, 'title' => 'test'))); + + $this->assertEquals(1, $tagModel->create(0, 'My tag 1')); + $this->assertEquals(2, $tagModel->create(0, 'My tag 2')); + + $this->assertTrue($taskTagModel->save(1, 1, array('My tag 1', 'My tag 2', 'My tag 3'))); + + $tags = $taskTagModel->getAll(1); + $this->assertCount(3, $tags); + + $this->assertEquals(1, $tags[0]['id']); + $this->assertEquals('My tag 1', $tags[0]['name']); + + $this->assertEquals(2, $tags[1]['id']); + $this->assertEquals('My tag 2', $tags[1]['name']); + + $this->assertEquals(3, $tags[2]['id']); + $this->assertEquals('My tag 3', $tags[2]['name']); + + $this->assertTrue($taskTagModel->save(1, 1, array('My tag 3', 'My tag 1', 'My tag 4'))); + + $tags = $taskTagModel->getAll(1); + $this->assertCount(3, $tags); + + $this->assertEquals(1, $tags[0]['id']); + $this->assertEquals('My tag 1', $tags[0]['name']); + + $this->assertEquals(3, $tags[1]['id']); + $this->assertEquals('My tag 3', $tags[1]['name']); + + $this->assertEquals(4, $tags[2]['id']); + $this->assertEquals('My tag 4', $tags[2]['name']); + + $tags = $tagModel->getAll(); + $this->assertCount(4, $tags); + $this->assertEquals('My tag 1', $tags[0]['name']); + $this->assertEquals(0, $tags[0]['project_id']); + + $this->assertEquals('My tag 2', $tags[1]['name']); + $this->assertEquals(0, $tags[1]['project_id']); + + $this->assertEquals('My tag 3', $tags[2]['name']); + $this->assertEquals(1, $tags[2]['project_id']); + + $this->assertEquals('My tag 4', $tags[3]['name']); + $this->assertEquals(1, $tags[3]['project_id']); + } +} -- cgit v1.2.3 From 9e278a9370e3b651a4a545c0c0c0c256088ed187 Mon Sep 17 00:00:00 2001 From: Frederic Guillot Date: Fri, 24 Jun 2016 08:50:57 -0400 Subject: Use BoardFormatter to generate the board --- app/Api/BoardApi.php | 8 +- app/Controller/BoardAjaxController.php | 2 +- app/Controller/BoardViewController.php | 8 +- app/Filter/BaseFilter.php | 3 +- app/Formatter/BaseFormatter.php | 17 +- app/Formatter/BoardColumnFormatter.php | 79 +++++++ app/Formatter/BoardFormatter.php | 19 +- app/Formatter/BoardSwimlaneFormatter.php | 105 +++++++++ app/Formatter/BoardTaskFormatter.php | 80 +++++++ app/Model/BoardModel.php | 60 ------ app/Model/TaskFinderModel.php | 20 -- app/Template/board/table_column.php | 4 +- app/functions.php | 26 +++ tests/units/Formatter/BoardFormatterTest.php | 311 +++++++++++++++++++++++++++ tests/units/FunctionTest.php | 21 ++ tests/units/Model/BoardTest.php | 121 ----------- 16 files changed, 667 insertions(+), 217 deletions(-) create mode 100644 app/Formatter/BoardColumnFormatter.php create mode 100644 app/Formatter/BoardSwimlaneFormatter.php create mode 100644 app/Formatter/BoardTaskFormatter.php create mode 100644 tests/units/Formatter/BoardFormatterTest.php create mode 100644 tests/units/FunctionTest.php (limited to 'app') diff --git a/app/Api/BoardApi.php b/app/Api/BoardApi.php index aa5942af..70f21c0e 100644 --- a/app/Api/BoardApi.php +++ b/app/Api/BoardApi.php @@ -2,6 +2,8 @@ namespace Kanboard\Api; +use Kanboard\Formatter\BoardFormatter; + /** * Board API controller * @@ -13,6 +15,10 @@ class BoardApi extends BaseApi public function getBoard($project_id) { $this->checkProjectPermission($project_id); - return $this->boardModel->getBoard($project_id); + + return BoardFormatter::getInstance($this->container) + ->withProjectId($project_id) + ->withQuery($this->taskFinderModel->getExtendedQuery()) + ->format(); } } diff --git a/app/Controller/BoardAjaxController.php b/app/Controller/BoardAjaxController.php index 24914671..9b721f06 100644 --- a/app/Controller/BoardAjaxController.php +++ b/app/Controller/BoardAjaxController.php @@ -134,7 +134,7 @@ class BoardAjaxController extends BaseController 'board_highlight_period' => $this->configModel->get('board_highlight_period'), 'swimlanes' => $this->taskLexer ->build($this->userSession->getFilters($project_id)) - ->format(BoardFormatter::getInstance($this->container)->setProjectId($project_id)) + ->format(BoardFormatter::getInstance($this->container)->withProjectId($project_id)) )); } } diff --git a/app/Controller/BoardViewController.php b/app/Controller/BoardViewController.php index 496fa995..97c99d11 100644 --- a/app/Controller/BoardViewController.php +++ b/app/Controller/BoardViewController.php @@ -30,7 +30,11 @@ class BoardViewController extends BaseController $this->response->html($this->helper->layout->app('board/view_public', array( 'project' => $project, - 'swimlanes' => $this->boardModel->getBoard($project['id']), + 'swimlanes' => BoardFormatter::getInstance($this->container) + ->withProjectId($project['id']) + ->withQuery($this->taskFinderModel->getExtendedQuery()) + ->format() + , 'title' => $project['name'], 'description' => $project['description'], 'no_layout' => true, @@ -59,7 +63,7 @@ class BoardViewController extends BaseController 'board_highlight_period' => $this->configModel->get('board_highlight_period'), 'swimlanes' => $this->taskLexer ->build($search) - ->format(BoardFormatter::getInstance($this->container)->setProjectId($project['id'])) + ->format(BoardFormatter::getInstance($this->container)->withProjectId($project['id'])) ))); } } diff --git a/app/Filter/BaseFilter.php b/app/Filter/BaseFilter.php index 79a664be..e029f4e1 100644 --- a/app/Filter/BaseFilter.php +++ b/app/Filter/BaseFilter.php @@ -43,8 +43,7 @@ abstract class BaseFilter */ public static function getInstance($value = null) { - $self = new static($value); - return $self; + return new static($value); } /** diff --git a/app/Formatter/BaseFormatter.php b/app/Formatter/BaseFormatter.php index a9f0ad15..89c48437 100644 --- a/app/Formatter/BaseFormatter.php +++ b/app/Formatter/BaseFormatter.php @@ -3,8 +3,8 @@ namespace Kanboard\Formatter; use Kanboard\Core\Base; -use Kanboard\Core\Filter\FormatterInterface; use PicoDb\Table; +use Pimple\Container; /** * Class BaseFormatter @@ -22,12 +22,25 @@ abstract class BaseFormatter extends Base */ protected $query; + /** + * Get object instance + * + * @static + * @access public + * @param Container $container + * @return static + */ + public static function getInstance(Container $container) + { + return new static($container); + } + /** * Set query * * @access public * @param Table $query - * @return FormatterInterface + * @return $this */ public function withQuery(Table $query) { diff --git a/app/Formatter/BoardColumnFormatter.php b/app/Formatter/BoardColumnFormatter.php new file mode 100644 index 00000000..3d8f6e67 --- /dev/null +++ b/app/Formatter/BoardColumnFormatter.php @@ -0,0 +1,79 @@ +swimlaneId = $swimlaneId; + return $this; + } + + /** + * Set columns + * + * @access public + * @param array $columns + * @return $this + */ + public function withColumns(array $columns) + { + $this->columns = $columns; + return $this; + } + + /** + * Set tasks + * + * @access public + * @param array $tasks + * @return $this + */ + public function withTasks(array $tasks) + { + $this->tasks = $tasks; + return $this; + } + + /** + * Apply formatter + * + * @access public + * @return array + */ + public function format() + { + foreach ($this->columns as &$column) { + $column['tasks'] = BoardTaskFormatter::getInstance($this->container) + ->withTasks($this->tasks) + ->withSwimlaneId($this->swimlaneId) + ->withColumnId($column['id']) + ->format(); + + $column['nb_tasks'] = count($column['tasks']); + $column['score'] = (int) array_column_sum($column['tasks'], 'score'); + } + + return $this->columns; + } +} diff --git a/app/Formatter/BoardFormatter.php b/app/Formatter/BoardFormatter.php index dbc7cf21..562a97bc 100644 --- a/app/Formatter/BoardFormatter.php +++ b/app/Formatter/BoardFormatter.php @@ -28,7 +28,7 @@ class BoardFormatter extends BaseFormatter implements FormatterInterface * @param integer $projectId * @return $this */ - public function setProjectId($projectId) + public function withProjectId($projectId) { $this->projectId = $projectId; return $this; @@ -42,15 +42,22 @@ class BoardFormatter extends BaseFormatter implements FormatterInterface */ public function format() { + $swimlanes = $this->swimlaneModel->getSwimlanes($this->projectId); + $columns = $this->columnModel->getAll($this->projectId); + $tasks = $this->query ->eq(TaskModel::TABLE.'.project_id', $this->projectId) ->asc(TaskModel::TABLE.'.position') ->findAll(); - return $this->boardModel->getBoard($this->projectId, function ($project_id, $column_id, $swimlane_id) use ($tasks) { - return array_filter($tasks, function (array $task) use ($column_id, $swimlane_id) { - return $task['column_id'] == $column_id && $task['swimlane_id'] == $swimlane_id; - }); - }); + if (empty($swimlanes) || empty($columns)) { + return array(); + } + + return BoardSwimlaneFormatter::getInstance($this->container) + ->withSwimlanes($swimlanes) + ->withColumns($columns) + ->withTasks($tasks) + ->format(); } } diff --git a/app/Formatter/BoardSwimlaneFormatter.php b/app/Formatter/BoardSwimlaneFormatter.php new file mode 100644 index 00000000..91b4bfd7 --- /dev/null +++ b/app/Formatter/BoardSwimlaneFormatter.php @@ -0,0 +1,105 @@ +swimlanes = $swimlanes; + return $this; + } + + /** + * Set columns + * + * @access public + * @param array $columns + * @return $this + */ + public function withColumns($columns) + { + $this->columns = $columns; + return $this; + } + + /** + * Set tasks + * + * @access public + * @param array $tasks + * @return $this + */ + public function withTasks(array $tasks) + { + $this->tasks = $tasks; + return $this; + } + + /** + * Apply formatter + * + * @access public + * @return array + */ + public function format() + { + $nb_swimlanes = count($this->swimlanes); + $nb_columns = count($this->columns); + + foreach ($this->swimlanes as &$swimlane) { + $swimlane['columns'] = BoardColumnFormatter::getInstance($this->container) + ->withSwimlaneId($swimlane['id']) + ->withColumns($this->columns) + ->withTasks($this->tasks) + ->format(); + + $swimlane['nb_swimlanes'] = $nb_swimlanes; + $swimlane['nb_columns'] = $nb_columns; + $swimlane['nb_tasks'] = array_column_sum($swimlane['columns'], 'nb_tasks'); + $swimlane['score'] = array_column_sum($swimlane['columns'], 'score'); + + $this->calculateStatsByColumnAcrossSwimlanes($swimlane['columns']); + } + + return $this->swimlanes; + } + + /** + * Calculate stats for each column acrosss all swimlanes + * + * @access protected + * @param array $columns + */ + protected function calculateStatsByColumnAcrossSwimlanes(array $columns) + { + foreach ($columns as $columnIndex => $column) { + if (! isset($this->swimlanes[0]['columns'][$columnIndex]['column_nb_tasks'])) { + $this->swimlanes[0]['columns'][$columnIndex]['column_nb_tasks'] = 0; + $this->swimlanes[0]['columns'][$columnIndex]['column_score'] = 0; + } + + $this->swimlanes[0]['columns'][$columnIndex]['column_nb_tasks'] += $column['nb_tasks']; + $this->swimlanes[0]['columns'][$columnIndex]['column_score'] += $column['score']; + } + } +} diff --git a/app/Formatter/BoardTaskFormatter.php b/app/Formatter/BoardTaskFormatter.php new file mode 100644 index 00000000..d9500710 --- /dev/null +++ b/app/Formatter/BoardTaskFormatter.php @@ -0,0 +1,80 @@ +tasks = $tasks; + return $this; + } + + /** + * Set columnId + * + * @access public + * @param integer $columnId + * @return $this + */ + public function withColumnId($columnId) + { + $this->columnId = $columnId; + return $this; + } + + /** + * Set swimlaneId + * + * @access public + * @param integer $swimlaneId + * @return $this + */ + public function withSwimlaneId($swimlaneId) + { + $this->swimlaneId = $swimlaneId; + return $this; + } + + /** + * Apply formatter + * + * @access public + * @return array + */ + public function format() + { + return array_values(array_filter($this->tasks, array($this, 'filterTasks'))); + } + + /** + * Keep only tasks of the given column and swimlane + * + * @access public + * @param array $task + * @return bool + */ + public function filterTasks(array $task) + { + return $task['column_id'] == $this->columnId && $task['swimlane_id'] == $this->swimlaneId; + } +} diff --git a/app/Model/BoardModel.php b/app/Model/BoardModel.php index d2718b47..4d559936 100644 --- a/app/Model/BoardModel.php +++ b/app/Model/BoardModel.php @@ -93,66 +93,6 @@ class BoardModel extends Base return $this->boardModel->create($project_to, $columns); } - /** - * Get all tasks sorted by columns and swimlanes - * - * @access public - * @param integer $project_id - * @param callable $callback - * @return array - */ - public function getBoard($project_id, $callback = null) - { - $swimlanes = $this->swimlaneModel->getSwimlanes($project_id); - $columns = $this->columnModel->getAll($project_id); - $nb_columns = count($columns); - - for ($i = 0, $ilen = count($swimlanes); $i < $ilen; $i++) { - $swimlanes[$i]['columns'] = $columns; - $swimlanes[$i]['nb_columns'] = $nb_columns; - $swimlanes[$i]['nb_tasks'] = 0; - $swimlanes[$i]['nb_swimlanes'] = $ilen; - - for ($j = 0; $j < $nb_columns; $j++) { - $column_id = $columns[$j]['id']; - $swimlane_id = $swimlanes[$i]['id']; - - if (! isset($swimlanes[0]['columns'][$j]['nb_column_tasks'])) { - $swimlanes[0]['columns'][$j]['nb_column_tasks'] = 0; - $swimlanes[0]['columns'][$j]['total_score'] = 0; - } - - $swimlanes[$i]['columns'][$j]['tasks'] = $callback === null ? $this->taskFinderModel->getTasksByColumnAndSwimlane($project_id, $column_id, $swimlane_id) : $callback($project_id, $column_id, $swimlane_id); - $swimlanes[$i]['columns'][$j]['nb_tasks'] = count($swimlanes[$i]['columns'][$j]['tasks']); - $swimlanes[$i]['columns'][$j]['score'] = $this->getColumnSum($swimlanes[$i]['columns'][$j]['tasks'], 'score'); - $swimlanes[$i]['nb_tasks'] += $swimlanes[$i]['columns'][$j]['nb_tasks']; - $swimlanes[0]['columns'][$j]['nb_column_tasks'] += $swimlanes[$i]['columns'][$j]['nb_tasks']; - $swimlanes[0]['columns'][$j]['total_score'] += $swimlanes[$i]['columns'][$j]['score']; - } - } - - return $swimlanes; - } - - /** - * Calculate the sum of the defined field for a list of tasks - * - * @access public - * @param array $tasks - * @param string $field - * @return integer - */ - public function getColumnSum(array &$tasks, $field) - { - $sum = 0; - - foreach ($tasks as $task) { - $sum += $task[$field]; - } - - return $sum; - } - /** * Get the total of tasks per column * diff --git a/app/Model/TaskFinderModel.php b/app/Model/TaskFinderModel.php index 8b636e28..0e99c407 100644 --- a/app/Model/TaskFinderModel.php +++ b/app/Model/TaskFinderModel.php @@ -152,26 +152,6 @@ class TaskFinderModel extends Base ->join(ProjectModel::TABLE, 'id', 'project_id', TaskModel::TABLE); } - /** - * Get all tasks shown on the board (sorted by position) - * - * @access public - * @param integer $project_id Project id - * @param integer $column_id Column id - * @param integer $swimlane_id Swimlane id - * @return array - */ - public function getTasksByColumnAndSwimlane($project_id, $column_id, $swimlane_id = 0) - { - return $this->getExtendedQuery() - ->eq(TaskModel::TABLE.'.project_id', $project_id) - ->eq(TaskModel::TABLE.'.column_id', $column_id) - ->eq(TaskModel::TABLE.'.swimlane_id', $swimlane_id) - ->eq(TaskModel::TABLE.'.is_active', TaskModel::STATUS_OPEN) - ->asc(TaskModel::TABLE.'.position') - ->findAll(); - } - /** * Get all tasks for a given project and status * diff --git a/app/Template/board/table_column.php b/app/Template/board/table_column.php index f7a9f6ad..6336234a 100644 --- a/app/Template/board/table_column.php +++ b/app/Template/board/table_column.php @@ -18,9 +18,9 @@ - 1 && ! empty($column['nb_column_tasks'])): ?> + 1 && ! empty($column['column_nb_tasks'])): ?> - () + () diff --git a/app/functions.php b/app/functions.php index b759763f..99431d9e 100644 --- a/app/functions.php +++ b/app/functions.php @@ -2,6 +2,32 @@ use Kanboard\Core\Translator; +/** + * Sum all values from a single column in the input array + * + * $input = [ + * ['column' => 2'], ['column' => 3'] + * ] + * + * array_column_sum($input, 'column') returns 5 + * + * @param array $input + * @param string $column + * @return double + */ +function array_column_sum(array &$input, $column) +{ + $sum = 0.0; + + foreach ($input as &$row) { + if (isset($row[$column])) { + $sum += (float) $row[$column]; + } + } + + return $sum; +} + /** * Build version number from git-archive output * diff --git a/tests/units/Formatter/BoardFormatterTest.php b/tests/units/Formatter/BoardFormatterTest.php new file mode 100644 index 00000000..02b0b518 --- /dev/null +++ b/tests/units/Formatter/BoardFormatterTest.php @@ -0,0 +1,311 @@ +container); + $swimlaneModel = new SwimlaneModel($this->container); + $taskCreationModel = new TaskCreationModel($this->container); + $taskFinderModel = new TaskFinderModel($this->container); + + $this->assertEquals(1, $projectModel->create(array('name' => 'Test'))); + $this->assertEquals(1, $swimlaneModel->create(array('name' => 'Swimlane 1', 'project_id' => 1))); + $this->assertEquals(2, $swimlaneModel->create(array('name' => 'Swimlane 2', 'project_id' => 1))); + + // 2 task within the same column but no score + $this->assertEquals(1, $taskCreationModel->create(array('title' => 'Task 1', 'project_id' => 1, 'swimlane_id' => 0, 'column_id' => 1))); + $this->assertEquals(2, $taskCreationModel->create(array('title' => 'Task 2', 'project_id' => 1, 'swimlane_id' => 0, 'column_id' => 1))); + + // 2 tasks in the same column with score + $this->assertEquals(3, $taskCreationModel->create(array('title' => 'Task 3', 'project_id' => 1, 'swimlane_id' => 0, 'column_id' => 1, 'score' => 4))); + $this->assertEquals(4, $taskCreationModel->create(array('title' => 'Task 4', 'project_id' => 1, 'swimlane_id' => 0, 'column_id' => 1, 'score' => 5))); + + // 1 task in 2nd column + $this->assertEquals(5, $taskCreationModel->create(array('title' => 'Task 5', 'project_id' => 1, 'swimlane_id' => 0, 'column_id' => 2))); + + // tasks in same column but different swimlanes + $this->assertEquals(6, $taskCreationModel->create(array('title' => 'Task 6', 'project_id' => 1, 'swimlane_id' => 0, 'column_id' => 3, 'score' => 1))); + $this->assertEquals(7, $taskCreationModel->create(array('title' => 'Task 7', 'project_id' => 1, 'swimlane_id' => 1, 'column_id' => 3, 'score' => 2))); + $this->assertEquals(8, $taskCreationModel->create(array('title' => 'Task 8', 'project_id' => 1, 'swimlane_id' => 2, 'column_id' => 3, 'score' => 3))); + + $board = BoardFormatter::getInstance($this->container) + ->withQuery($taskFinderModel->getExtendedQuery()) + ->withProjectId(1) + ->format(); + + $this->assertCount(3, $board); + + $this->assertEquals('Default swimlane', $board[0]['name']); + $this->assertCount(4, $board[0]['columns']); + $this->assertEquals(3, $board[0]['nb_swimlanes']); + $this->assertEquals(4, $board[0]['nb_columns']); + $this->assertEquals(6, $board[0]['nb_tasks']); + $this->assertEquals(10, $board[0]['score']); + + $this->assertEquals(4, $board[0]['columns'][0]['column_nb_tasks']); + $this->assertEquals(1, $board[0]['columns'][1]['column_nb_tasks']); + $this->assertEquals(3, $board[0]['columns'][2]['column_nb_tasks']); + $this->assertEquals(0, $board[0]['columns'][3]['column_nb_tasks']); + + $this->assertEquals(9, $board[0]['columns'][0]['column_score']); + $this->assertEquals(0, $board[0]['columns'][1]['column_score']); + $this->assertEquals(6, $board[0]['columns'][2]['column_score']); + $this->assertEquals(0, $board[0]['columns'][3]['column_score']); + + $this->assertSame(9, $board[0]['columns'][0]['score']); + $this->assertSame(0, $board[0]['columns'][1]['score']); + $this->assertSame(1, $board[0]['columns'][2]['score']); + $this->assertSame(0, $board[0]['columns'][3]['score']); + + $this->assertSame(4, $board[0]['columns'][0]['nb_tasks']); + $this->assertSame(1, $board[0]['columns'][1]['nb_tasks']); + $this->assertSame(1, $board[0]['columns'][2]['nb_tasks']); + $this->assertSame(0, $board[0]['columns'][3]['nb_tasks']); + + $this->assertEquals('Task 1', $board[0]['columns'][0]['tasks'][0]['title']); + $this->assertEquals('Task 2', $board[0]['columns'][0]['tasks'][1]['title']); + $this->assertEquals('Task 3', $board[0]['columns'][0]['tasks'][2]['title']); + $this->assertEquals('Task 4', $board[0]['columns'][0]['tasks'][3]['title']); + $this->assertEquals('Task 5', $board[0]['columns'][1]['tasks'][0]['title']); + $this->assertEquals('Task 6', $board[0]['columns'][2]['tasks'][0]['title']); + + $this->assertEquals('Swimlane 1', $board[1]['name']); + $this->assertCount(4, $board[1]['columns']); + $this->assertEquals(3, $board[1]['nb_swimlanes']); + $this->assertEquals(4, $board[1]['nb_columns']); + $this->assertEquals(1, $board[1]['nb_tasks']); + $this->assertEquals(2, $board[1]['score']); + + $this->assertSame(0, $board[1]['columns'][0]['score']); + $this->assertSame(0, $board[1]['columns'][1]['score']); + $this->assertSame(2, $board[1]['columns'][2]['score']); + $this->assertSame(0, $board[1]['columns'][3]['score']); + + $this->assertSame(0, $board[1]['columns'][0]['nb_tasks']); + $this->assertSame(0, $board[1]['columns'][1]['nb_tasks']); + $this->assertSame(1, $board[1]['columns'][2]['nb_tasks']); + $this->assertSame(0, $board[1]['columns'][3]['nb_tasks']); + + $this->assertEquals('Task 7', $board[1]['columns'][2]['tasks'][0]['title']); + + $this->assertEquals('Swimlane 2', $board[2]['name']); + $this->assertCount(4, $board[2]['columns']); + $this->assertEquals(3, $board[2]['nb_swimlanes']); + $this->assertEquals(4, $board[2]['nb_columns']); + $this->assertEquals(1, $board[2]['nb_tasks']); + $this->assertEquals(3, $board[2]['score']); + + $this->assertSame(0, $board[2]['columns'][0]['score']); + $this->assertSame(0, $board[2]['columns'][1]['score']); + $this->assertSame(3, $board[2]['columns'][2]['score']); + $this->assertSame(0, $board[2]['columns'][3]['score']); + + $this->assertSame(0, $board[2]['columns'][0]['nb_tasks']); + $this->assertSame(0, $board[2]['columns'][1]['nb_tasks']); + $this->assertSame(1, $board[2]['columns'][2]['nb_tasks']); + $this->assertSame(0, $board[2]['columns'][3]['nb_tasks']); + + $this->assertEquals('Task 8', $board[2]['columns'][2]['tasks'][0]['title']); + } + + public function testFormatWithoutDefaultSwimlane() + { + $projectModel = new ProjectModel($this->container); + $swimlaneModel = new SwimlaneModel($this->container); + $taskCreationModel = new TaskCreationModel($this->container); + $taskFinderModel = new TaskFinderModel($this->container); + + $this->assertEquals(1, $projectModel->create(array('name' => 'Test'))); + $this->assertTrue($swimlaneModel->disableDefault(1)); + $this->assertEquals(1, $swimlaneModel->create(array('name' => 'Swimlane 1', 'project_id' => 1))); + $this->assertEquals(2, $swimlaneModel->create(array('name' => 'Swimlane 2', 'project_id' => 1))); + + $this->assertEquals(1, $taskCreationModel->create(array('title' => 'Task 1', 'project_id' => 1, 'swimlane_id' => 1, 'column_id' => 1))); + $this->assertEquals(2, $taskCreationModel->create(array('title' => 'Task 2', 'project_id' => 1, 'swimlane_id' => 2, 'column_id' => 2))); + $this->assertEquals(3, $taskCreationModel->create(array('title' => 'Task 3', 'project_id' => 1, 'swimlane_id' => 1, 'column_id' => 2, 'score' => 1))); + $this->assertEquals(4, $taskCreationModel->create(array('title' => 'Task 4', 'project_id' => 1, 'swimlane_id' => 2, 'column_id' => 1))); + + $board = BoardFormatter::getInstance($this->container) + ->withQuery($taskFinderModel->getExtendedQuery()) + ->withProjectId(1) + ->format(); + + $this->assertCount(2, $board); + + $this->assertEquals('Swimlane 1', $board[0]['name']); + $this->assertCount(4, $board[0]['columns']); + $this->assertEquals(2, $board[0]['nb_swimlanes']); + $this->assertEquals(4, $board[0]['nb_columns']); + $this->assertEquals(2, $board[0]['nb_tasks']); + $this->assertEquals(1, $board[0]['score']); + + $this->assertEquals(2, $board[0]['columns'][0]['column_nb_tasks']); + $this->assertEquals(2, $board[0]['columns'][1]['column_nb_tasks']); + $this->assertEquals(0, $board[0]['columns'][2]['column_nb_tasks']); + $this->assertEquals(0, $board[0]['columns'][3]['column_nb_tasks']); + + $this->assertEquals(0, $board[0]['columns'][0]['column_score']); + $this->assertEquals(1, $board[0]['columns'][1]['column_score']); + $this->assertEquals(0, $board[0]['columns'][2]['column_score']); + $this->assertEquals(0, $board[0]['columns'][3]['column_score']); + + $this->assertSame(0, $board[0]['columns'][0]['score']); + $this->assertSame(1, $board[0]['columns'][1]['score']); + $this->assertSame(0, $board[0]['columns'][2]['score']); + $this->assertSame(0, $board[0]['columns'][3]['score']); + + $this->assertSame(1, $board[0]['columns'][0]['nb_tasks']); + $this->assertSame(1, $board[0]['columns'][1]['nb_tasks']); + $this->assertSame(0, $board[0]['columns'][2]['nb_tasks']); + $this->assertSame(0, $board[0]['columns'][3]['nb_tasks']); + + $this->assertEquals('Task 1', $board[0]['columns'][0]['tasks'][0]['title']); + $this->assertEquals('Task 3', $board[0]['columns'][1]['tasks'][0]['title']); + + $this->assertEquals('Swimlane 2', $board[1]['name']); + $this->assertCount(4, $board[1]['columns']); + $this->assertEquals(2, $board[1]['nb_swimlanes']); + $this->assertEquals(4, $board[1]['nb_columns']); + $this->assertEquals(2, $board[1]['nb_tasks']); + $this->assertEquals(0, $board[1]['score']); + + $this->assertSame(0, $board[1]['columns'][0]['score']); + $this->assertSame(0, $board[1]['columns'][1]['score']); + $this->assertSame(0, $board[1]['columns'][2]['score']); + $this->assertSame(0, $board[1]['columns'][3]['score']); + + $this->assertSame(1, $board[1]['columns'][0]['nb_tasks']); + $this->assertSame(1, $board[1]['columns'][1]['nb_tasks']); + $this->assertSame(0, $board[1]['columns'][2]['nb_tasks']); + $this->assertSame(0, $board[1]['columns'][3]['nb_tasks']); + + $this->assertEquals('Task 4', $board[1]['columns'][0]['tasks'][0]['title']); + $this->assertEquals('Task 2', $board[1]['columns'][1]['tasks'][0]['title']); + } + + public function testFormatWithoutSwimlane() + { + $projectModel = new ProjectModel($this->container); + $taskFinderModel = new TaskFinderModel($this->container); + $swimlaneModel = new SwimlaneModel($this->container); + + $this->assertEquals(1, $projectModel->create(array('name' => 'Test'))); + $this->assertTrue($swimlaneModel->disableDefault(1)); + + $board = BoardFormatter::getInstance($this->container) + ->withQuery($taskFinderModel->getExtendedQuery()) + ->withProjectId(1) + ->format(); + + $this->assertCount(0, $board); + } + + public function testFormatWithoutColumn() + { + $projectModel = new ProjectModel($this->container); + $taskFinderModel = new TaskFinderModel($this->container); + $columnModel = new ColumnModel($this->container); + + $this->assertEquals(1, $projectModel->create(array('name' => 'Test'))); + $this->assertTrue($columnModel->remove(1)); + $this->assertTrue($columnModel->remove(2)); + $this->assertTrue($columnModel->remove(3)); + $this->assertTrue($columnModel->remove(4)); + + $board = BoardFormatter::getInstance($this->container) + ->withQuery($taskFinderModel->getExtendedQuery()) + ->withProjectId(1) + ->format(); + + $this->assertCount(0, $board); + } + + public function testFormatWithoutTask() + { + $projectModel = new ProjectModel($this->container); + $swimlaneModel = new SwimlaneModel($this->container); + $taskFinderModel = new TaskFinderModel($this->container); + + $this->assertEquals(1, $projectModel->create(array('name' => 'Test'))); + $this->assertEquals(1, $swimlaneModel->create(array('name' => 'Swimlane 1', 'project_id' => 1))); + $this->assertEquals(2, $swimlaneModel->create(array('name' => 'Swimlane 2', 'project_id' => 1))); + + $board = BoardFormatter::getInstance($this->container) + ->withQuery($taskFinderModel->getExtendedQuery()) + ->withProjectId(1) + ->format(); + + $this->assertCount(3, $board); + + $this->assertEquals('Default swimlane', $board[0]['name']); + $this->assertCount(4, $board[0]['columns']); + $this->assertEquals(3, $board[0]['nb_swimlanes']); + $this->assertEquals(4, $board[0]['nb_columns']); + $this->assertEquals(0, $board[0]['nb_tasks']); + $this->assertEquals(0, $board[0]['score']); + + $this->assertEquals(0, $board[0]['columns'][0]['column_nb_tasks']); + $this->assertEquals(0, $board[0]['columns'][1]['column_nb_tasks']); + $this->assertEquals(0, $board[0]['columns'][2]['column_nb_tasks']); + $this->assertEquals(0, $board[0]['columns'][3]['column_nb_tasks']); + + $this->assertEquals(0, $board[0]['columns'][0]['column_score']); + $this->assertEquals(0, $board[0]['columns'][1]['column_score']); + $this->assertEquals(0, $board[0]['columns'][2]['column_score']); + $this->assertEquals(0, $board[0]['columns'][3]['column_score']); + + $this->assertSame(0, $board[0]['columns'][0]['score']); + $this->assertSame(0, $board[0]['columns'][1]['score']); + $this->assertSame(0, $board[0]['columns'][2]['score']); + $this->assertSame(0, $board[0]['columns'][3]['score']); + + $this->assertSame(0, $board[0]['columns'][0]['nb_tasks']); + $this->assertSame(0, $board[0]['columns'][1]['nb_tasks']); + $this->assertSame(0, $board[0]['columns'][2]['nb_tasks']); + $this->assertSame(0, $board[0]['columns'][3]['nb_tasks']); + + $this->assertEquals('Swimlane 1', $board[1]['name']); + $this->assertCount(4, $board[1]['columns']); + $this->assertEquals(3, $board[1]['nb_swimlanes']); + $this->assertEquals(4, $board[1]['nb_columns']); + $this->assertEquals(0, $board[1]['nb_tasks']); + $this->assertEquals(0, $board[1]['score']); + + $this->assertSame(0, $board[1]['columns'][0]['score']); + $this->assertSame(0, $board[1]['columns'][1]['score']); + $this->assertSame(0, $board[1]['columns'][2]['score']); + $this->assertSame(0, $board[1]['columns'][3]['score']); + + $this->assertSame(0, $board[1]['columns'][0]['nb_tasks']); + $this->assertSame(0, $board[1]['columns'][1]['nb_tasks']); + $this->assertSame(0, $board[1]['columns'][2]['nb_tasks']); + $this->assertSame(0, $board[1]['columns'][3]['nb_tasks']); + + $this->assertEquals('Swimlane 2', $board[2]['name']); + $this->assertCount(4, $board[2]['columns']); + $this->assertEquals(3, $board[2]['nb_swimlanes']); + $this->assertEquals(4, $board[2]['nb_columns']); + $this->assertEquals(0, $board[2]['nb_tasks']); + $this->assertEquals(0, $board[2]['score']); + + $this->assertSame(0, $board[2]['columns'][0]['score']); + $this->assertSame(0, $board[2]['columns'][1]['score']); + $this->assertSame(0, $board[2]['columns'][2]['score']); + $this->assertSame(0, $board[2]['columns'][3]['score']); + + $this->assertSame(0, $board[2]['columns'][0]['nb_tasks']); + $this->assertSame(0, $board[2]['columns'][1]['nb_tasks']); + $this->assertSame(0, $board[2]['columns'][2]['nb_tasks']); + $this->assertSame(0, $board[2]['columns'][3]['nb_tasks']); + } +} diff --git a/tests/units/FunctionTest.php b/tests/units/FunctionTest.php new file mode 100644 index 00000000..72895845 --- /dev/null +++ b/tests/units/FunctionTest.php @@ -0,0 +1,21 @@ + 123 + ), + array( + 'my_column' => 456.7 + ), + array() + ); + + $this->assertSame(579.7, array_column_sum($input, 'my_column')); + } +} diff --git a/tests/units/Model/BoardTest.php b/tests/units/Model/BoardTest.php index 80587d89..9f540c63 100644 --- a/tests/units/Model/BoardTest.php +++ b/tests/units/Model/BoardTest.php @@ -3,12 +3,8 @@ require_once __DIR__.'/../Base.php'; use Kanboard\Model\ProjectModel; -use Kanboard\Model\BoardModel; use Kanboard\Model\ColumnModel; use Kanboard\Model\ConfigModel; -use Kanboard\Model\TaskCreationModel; -use Kanboard\Model\TaskFinderModel; -use Kanboard\Model\SwimlaneModel; class BoardTest extends Base { @@ -45,121 +41,4 @@ class BoardTest extends Base $this->assertEquals('column #1', $columns[5]); $this->assertEquals('column #2', $columns[6]); } - - public function testGetBoard() - { - $p = new ProjectModel($this->container); - $b = new BoardModel($this->container); - - $this->assertEquals(1, $p->create(array('name' => 'UnitTest1'))); - - $board = $b->getBoard(1); - $this->assertNotEmpty($board); - $this->assertEquals(1, count($board)); - $this->assertEquals(6, count($board[0])); - $this->assertArrayHasKey('name', $board[0]); - $this->assertArrayHasKey('nb_tasks', $board[0]); - $this->assertArrayHasKey('columns', $board[0]); - $this->assertArrayHasKey('tasks', $board[0]['columns'][2]); - $this->assertArrayHasKey('nb_tasks', $board[0]['columns'][2]); - $this->assertArrayHasKey('title', $board[0]['columns'][2]); - $this->assertArrayHasKey('nb_column_tasks', $board[0]['columns'][0]); - $this->assertArrayHasKey('total_score', $board[0]['columns'][0]); - } - - public function testGetBoardWithSwimlane() - { - $b = new BoardModel($this->container); - $tc = new TaskCreationModel($this->container); - $tf = new TaskFinderModel($this->container); - $p = new ProjectModel($this->container); - $s = new SwimlaneModel($this->container); - - $this->assertEquals(1, $p->create(array('name' => 'Project #1'))); - $this->assertEquals(1, $s->create(array('project_id' => 1, 'name' => 'test 1'))); - $this->assertEquals(1, $tc->create(array('title' => 'Task #1', 'project_id' => 1, 'column_id' => 1))); - $this->assertEquals(2, $tc->create(array('title' => 'Task #2', 'project_id' => 1, 'column_id' => 3))); - $this->assertEquals(3, $tc->create(array('title' => 'Task #3', 'project_id' => 1, 'column_id' => 2, 'swimlane_id' => 1))); - $this->assertEquals(4, $tc->create(array('title' => 'Task #4', 'project_id' => 1, 'column_id' => 3))); - $this->assertEquals(5, $tc->create(array('title' => 'Task #5', 'project_id' => 1, 'column_id' => 4, 'score' => 2))); - $this->assertEquals(6, $tc->create(array('title' => 'Task #6', 'project_id' => 1, 'column_id' => 4, 'score' => 3, 'swimlane_id' => 1))); - - $board = $b->getBoard(1); - $this->assertNotEmpty($board); - $this->assertEquals(2, count($board)); - $this->assertEquals(6, count($board[0])); - $this->assertArrayHasKey('name', $board[0]); - $this->assertArrayHasKey('nb_tasks', $board[0]); - $this->assertArrayHasKey('columns', $board[0]); - $this->assertArrayHasKey('tasks', $board[0]['columns'][2]); - $this->assertArrayHasKey('nb_tasks', $board[0]['columns'][2]); - $this->assertArrayHasKey('title', $board[0]['columns'][2]); - $this->assertArrayHasKey('nb_column_tasks', $board[0]['columns'][0]); - $this->assertArrayNotHasKey('nb_column_tasks', $board[1]['columns'][0]); - $this->assertArrayNotHasKey('total_score', $board[1]['columns'][0]); - $this->assertArrayHasKey('score', $board[0]['columns'][3]); - $this->assertArrayHasKey('total_score', $board[0]['columns'][3]); - $this->assertEquals(2, $board[0]['columns'][3]['score']); - $this->assertEquals(5, $board[0]['columns'][3]['total_score']); - - $task = $tf->getById(1); - $this->assertEquals(1, $task['id']); - $this->assertEquals(1, $task['column_id']); - $this->assertEquals(1, $task['position']); - $this->assertEquals(0, $task['swimlane_id']); - $this->assertEquals(1, $board[0]['columns'][0]['tasks'][0]['id']); - $this->assertEquals(1, $board[0]['columns'][0]['tasks'][0]['column_id']); - $this->assertEquals(1, $board[0]['columns'][0]['tasks'][0]['position']); - $this->assertEquals(0, $board[0]['columns'][0]['tasks'][0]['swimlane_id']); - - $task = $tf->getById(2); - $this->assertEquals(2, $task['id']); - $this->assertEquals(3, $task['column_id']); - $this->assertEquals(1, $task['position']); - $this->assertEquals(0, $task['swimlane_id']); - $this->assertEquals(2, $board[0]['columns'][2]['tasks'][0]['id']); - $this->assertEquals(3, $board[0]['columns'][2]['tasks'][0]['column_id']); - $this->assertEquals(1, $board[0]['columns'][2]['tasks'][0]['position']); - $this->assertEquals(0, $board[0]['columns'][2]['tasks'][0]['swimlane_id']); - - $task = $tf->getById(3); - $this->assertEquals(3, $task['id']); - $this->assertEquals(2, $task['column_id']); - $this->assertEquals(1, $task['position']); - $this->assertEquals(1, $task['swimlane_id']); - $this->assertEquals(3, $board[1]['columns'][1]['tasks'][0]['id']); - $this->assertEquals(2, $board[1]['columns'][1]['tasks'][0]['column_id']); - $this->assertEquals(1, $board[1]['columns'][1]['tasks'][0]['position']); - $this->assertEquals(1, $board[1]['columns'][1]['tasks'][0]['swimlane_id']); - - $task = $tf->getById(4); - $this->assertEquals(4, $task['id']); - $this->assertEquals(3, $task['column_id']); - $this->assertEquals(2, $task['position']); - $this->assertEquals(0, $task['swimlane_id']); - $this->assertEquals(4, $board[0]['columns'][2]['tasks'][1]['id']); - $this->assertEquals(3, $board[0]['columns'][2]['tasks'][1]['column_id']); - $this->assertEquals(2, $board[0]['columns'][2]['tasks'][1]['position']); - $this->assertEquals(0, $board[0]['columns'][2]['tasks'][1]['swimlane_id']); - - $task = $tf->getById(5); - $this->assertEquals(5, $task['id']); - $this->assertEquals(4, $task['column_id']); - $this->assertEquals(1, $task['position']); - $this->assertEquals(0, $task['swimlane_id']); - $this->assertEquals(5, $board[0]['columns'][3]['tasks'][0]['id']); - $this->assertEquals(4, $board[0]['columns'][3]['tasks'][0]['column_id']); - $this->assertEquals(1, $board[0]['columns'][3]['tasks'][0]['position']); - $this->assertEquals(0, $board[0]['columns'][3]['tasks'][0]['swimlane_id']); - - $task = $tf->getById(6); - $this->assertEquals(6, $task['id']); - $this->assertEquals(4, $task['column_id']); - $this->assertEquals(1, $task['position']); - $this->assertEquals(1, $task['swimlane_id']); - $this->assertEquals(6, $board[1]['columns'][3]['tasks'][0]['id']); - $this->assertEquals(4, $board[1]['columns'][3]['tasks'][0]['column_id']); - $this->assertEquals(1, $board[1]['columns'][3]['tasks'][0]['position']); - $this->assertEquals(1, $board[1]['columns'][3]['tasks'][0]['swimlane_id']); - } } -- cgit v1.2.3 From 700b4e8f0265e4eabd7a7c0eb6a06088d50554fe Mon Sep 17 00:00:00 2001 From: Frederic Guillot Date: Fri, 24 Jun 2016 10:05:45 -0400 Subject: Associate tags to tasks in BoardFormatter --- app/Formatter/BoardColumnFormatter.php | 15 ++++ app/Formatter/BoardFormatter.php | 5 +- app/Formatter/BoardSwimlaneFormatter.php | 15 ++++ app/Formatter/BoardTaskFormatter.php | 22 +++++- app/Model/TaskTagModel.php | 61 +++++++++++++--- app/functions.php | 52 +++++++++++++- tests/units/Formatter/BoardFormatterTest.php | 81 +++++++++++++++++++++ tests/units/FunctionTest.php | 102 +++++++++++++++++++++++++++ tests/units/Model/TaskTagModelTest.php | 50 ++++++++++++- 9 files changed, 386 insertions(+), 17 deletions(-) (limited to 'app') diff --git a/app/Formatter/BoardColumnFormatter.php b/app/Formatter/BoardColumnFormatter.php index 3d8f6e67..d49a577a 100644 --- a/app/Formatter/BoardColumnFormatter.php +++ b/app/Formatter/BoardColumnFormatter.php @@ -15,6 +15,7 @@ class BoardColumnFormatter extends BaseFormatter implements FormatterInterface protected $swimlaneId = 0; protected $columns = array(); protected $tasks = array(); + protected $tags = array(); /** * Set swimlaneId @@ -55,6 +56,19 @@ class BoardColumnFormatter extends BaseFormatter implements FormatterInterface return $this; } + /** + * Set tags + * + * @access public + * @param array $tags + * @return $this + */ + public function withTags(array $tags) + { + $this->tags = $tags; + return $this; + } + /** * Apply formatter * @@ -66,6 +80,7 @@ class BoardColumnFormatter extends BaseFormatter implements FormatterInterface foreach ($this->columns as &$column) { $column['tasks'] = BoardTaskFormatter::getInstance($this->container) ->withTasks($this->tasks) + ->withTags($this->tags) ->withSwimlaneId($this->swimlaneId) ->withColumnId($column['id']) ->format(); diff --git a/app/Formatter/BoardFormatter.php b/app/Formatter/BoardFormatter.php index 562a97bc..350dde6c 100644 --- a/app/Formatter/BoardFormatter.php +++ b/app/Formatter/BoardFormatter.php @@ -44,12 +44,14 @@ class BoardFormatter extends BaseFormatter implements FormatterInterface { $swimlanes = $this->swimlaneModel->getSwimlanes($this->projectId); $columns = $this->columnModel->getAll($this->projectId); - $tasks = $this->query ->eq(TaskModel::TABLE.'.project_id', $this->projectId) ->asc(TaskModel::TABLE.'.position') ->findAll(); + $task_ids = array_column($tasks, 'id'); + $tags = $this->taskTagModel->getTagsByTasks($task_ids); + if (empty($swimlanes) || empty($columns)) { return array(); } @@ -58,6 +60,7 @@ class BoardFormatter extends BaseFormatter implements FormatterInterface ->withSwimlanes($swimlanes) ->withColumns($columns) ->withTasks($tasks) + ->withTags($tags) ->format(); } } diff --git a/app/Formatter/BoardSwimlaneFormatter.php b/app/Formatter/BoardSwimlaneFormatter.php index 91b4bfd7..c2abb444 100644 --- a/app/Formatter/BoardSwimlaneFormatter.php +++ b/app/Formatter/BoardSwimlaneFormatter.php @@ -15,6 +15,7 @@ class BoardSwimlaneFormatter extends BaseFormatter implements FormatterInterface protected $swimlanes = array(); protected $columns = array(); protected $tasks = array(); + protected $tags = array(); /** * Set swimlanes @@ -55,6 +56,19 @@ class BoardSwimlaneFormatter extends BaseFormatter implements FormatterInterface return $this; } + /** + * Set tags + * + * @access public + * @param array $tags + * @return $this + */ + public function withTags(array $tags) + { + $this->tags = $tags; + return $this; + } + /** * Apply formatter * @@ -71,6 +85,7 @@ class BoardSwimlaneFormatter extends BaseFormatter implements FormatterInterface ->withSwimlaneId($swimlane['id']) ->withColumns($this->columns) ->withTasks($this->tasks) + ->withTags($this->tags) ->format(); $swimlane['nb_swimlanes'] = $nb_swimlanes; diff --git a/app/Formatter/BoardTaskFormatter.php b/app/Formatter/BoardTaskFormatter.php index d9500710..3bf171b1 100644 --- a/app/Formatter/BoardTaskFormatter.php +++ b/app/Formatter/BoardTaskFormatter.php @@ -13,9 +13,23 @@ use Kanboard\Core\Filter\FormatterInterface; class BoardTaskFormatter extends BaseFormatter implements FormatterInterface { protected $tasks = array(); + protected $tags = array(); protected $columnId = 0; protected $swimlaneId = 0; + /** + * Set tags + * + * @access public + * @param array $tags + * @return $this + */ + public function withTags(array $tags) + { + $this->tags = $tags; + return $this; + } + /** * Set tasks * @@ -63,17 +77,19 @@ class BoardTaskFormatter extends BaseFormatter implements FormatterInterface */ public function format() { - return array_values(array_filter($this->tasks, array($this, 'filterTasks'))); + $tasks = array_values(array_filter($this->tasks, array($this, 'filterTasks'))); + array_merge_relation($tasks, $this->tags, 'tags', 'id'); + return $tasks; } /** * Keep only tasks of the given column and swimlane * - * @access public + * @access protected * @param array $task * @return bool */ - public function filterTasks(array $task) + protected function filterTasks(array $task) { return $task['column_id'] == $this->columnId && $task['swimlane_id'] == $this->swimlaneId; } diff --git a/app/Model/TaskTagModel.php b/app/Model/TaskTagModel.php index 74d82539..3dd1dd88 100644 --- a/app/Model/TaskTagModel.php +++ b/app/Model/TaskTagModel.php @@ -26,7 +26,7 @@ class TaskTagModel extends Base * @param integer $task_id * @return array */ - public function getAll($task_id) + public function getTagsByTask($task_id) { return $this->db->table(TagModel::TABLE) ->columns(TagModel::TABLE.'.id', TagModel::TABLE.'.name') @@ -35,6 +35,28 @@ class TaskTagModel extends Base ->findAll(); } + /** + * Get all tags associated to a list of tasks + * + * @access public + * @param integer[] $task_ids + * @return array + */ + public function getTagsByTasks($task_ids) + { + if (empty($task_ids)) { + return array(); + } + + $tags = $this->db->table(TagModel::TABLE) + ->columns(TagModel::TABLE.'.id', TagModel::TABLE.'.name', self::TABLE.'.task_id') + ->in(self::TABLE.'.task_id', $task_ids) + ->join(self::TABLE, 'tag_id', 'id') + ->findAll(); + + return array_column_index($tags, 'task_id'); + } + /** * Get dictionary of tags * @@ -44,7 +66,7 @@ class TaskTagModel extends Base */ public function getList($task_id) { - $tags = $this->getAll($task_id); + $tags = $this->getTagsByTask($task_id); return array_column($tags, 'name', 'id'); } @@ -61,8 +83,8 @@ class TaskTagModel extends Base { $task_tags = $this->getList($task_id); - return $this->addTags($project_id, $task_id, $task_tags, $tags) && - $this->removeTags($task_id, $task_tags, $tags); + return $this->associateTags($project_id, $task_id, $task_tags, $tags) && + $this->dissociateTags($task_id, $task_tags, $tags); } /** @@ -73,7 +95,7 @@ class TaskTagModel extends Base * @param integer $tag_id * @return boolean */ - public function associate($task_id, $tag_id) + public function associateTag($task_id, $tag_id) { return $this->db->table(self::TABLE)->insert(array( 'task_id' => $task_id, @@ -89,7 +111,7 @@ class TaskTagModel extends Base * @param integer $tag_id * @return boolean */ - public function dissociate($task_id, $tag_id) + public function dissociateTag($task_id, $tag_id) { return $this->db->table(self::TABLE) ->eq('task_id', $task_id) @@ -97,12 +119,22 @@ class TaskTagModel extends Base ->remove(); } - private function addTags($project_id, $task_id, $task_tags, $tags) + /** + * Associate missing tags + * + * @access protected + * @param integer $project_id + * @param integer $task_id + * @param array $task_tags + * @param array $tags + * @return bool + */ + protected function associateTags($project_id, $task_id, $task_tags, $tags) { foreach ($tags as $tag) { $tag_id = $this->tagModel->findOrCreateTag($project_id, $tag); - if (! isset($task_tags[$tag_id]) && ! $this->associate($task_id, $tag_id)) { + if (! isset($task_tags[$tag_id]) && ! $this->associateTag($task_id, $tag_id)) { return false; } } @@ -110,11 +142,20 @@ class TaskTagModel extends Base return true; } - private function removeTags($task_id, $task_tags, $tags) + /** + * Dissociate removed tags + * + * @access protected + * @param integer $task_id + * @param array $task_tags + * @param array $tags + * @return bool + */ + protected function dissociateTags($task_id, $task_tags, $tags) { foreach ($task_tags as $tag_id => $tag) { if (! in_array($tag, $tags)) { - if (! $this->dissociate($task_id, $tag_id)) { + if (! $this->dissociateTag($task_id, $tag_id)) { return false; } } diff --git a/app/functions.php b/app/functions.php index 99431d9e..eaf33a52 100644 --- a/app/functions.php +++ b/app/functions.php @@ -2,11 +2,61 @@ use Kanboard\Core\Translator; +/** + * Associate another dict to a dict based on a common key + * + * @param array $input + * @param array $relations + * @param string $relation + * @param string $column + */ +function array_merge_relation(array &$input, array &$relations, $relation, $column) +{ + foreach ($input as &$row) { + if (isset($row[$column]) && isset($relations[$row[$column]])) { + $row[$relation] = $relations[$row[$column]]; + } else { + $row[$relation] = array(); + } + } +} + +/** + * Create indexed array from a list of dict + * + * $input = [ + * ['k1' => 1, 'k2' => 2], ['k1' => 3, 'k2' => 4], ['k1' => 2, 'k2' => 5] + * ] + * + * array_column_index($input, 'k1') will returns: + * + * [ + * 1 => [['k1' => 1, 'k2' => 2], ['k1' => 2, 'k2' => 5]], + * 3 => [['k1' => 3, 'k2' => 4]], + * ] + * + * @param array $input + * @param string $column + * @return array + */ +function array_column_index(array &$input, $column) +{ + $result = array(); + + foreach ($input as &$row) { + if (isset($row[$column])) { + $result[$row[$column]][] = $row; + } + } + + return $result; +} + /** * Sum all values from a single column in the input array * * $input = [ - * ['column' => 2'], ['column' => 3'] + * ['column' => 2], ['column' => 3] * ] * * array_column_sum($input, 'column') returns 5 diff --git a/tests/units/Formatter/BoardFormatterTest.php b/tests/units/Formatter/BoardFormatterTest.php index 02b0b518..c107eaf5 100644 --- a/tests/units/Formatter/BoardFormatterTest.php +++ b/tests/units/Formatter/BoardFormatterTest.php @@ -6,6 +6,7 @@ use Kanboard\Model\ProjectModel; use Kanboard\Model\SwimlaneModel; use Kanboard\Model\TaskCreationModel; use Kanboard\Model\TaskFinderModel; +use Kanboard\Model\TaskTagModel; require_once __DIR__.'/../Base.php'; @@ -308,4 +309,84 @@ class BoardFormatterTest extends Base $this->assertSame(0, $board[2]['columns'][2]['nb_tasks']); $this->assertSame(0, $board[2]['columns'][3]['nb_tasks']); } + + public function testFormatWithTags() + { + $projectModel = new ProjectModel($this->container); + $taskFinderModel = new TaskFinderModel($this->container); + $taskCreationModel = new TaskCreationModel($this->container); + $taskTagModel = new TaskTagModel($this->container); + + $this->assertEquals(1, $projectModel->create(array('name' => 'Test'))); + $this->assertEquals(1, $taskCreationModel->create(array('project_id' => 1, 'title' => 'test1'))); + $this->assertEquals(2, $taskCreationModel->create(array('project_id' => 1, 'title' => 'test2', 'column_id' => 3))); + $this->assertEquals(3, $taskCreationModel->create(array('project_id' => 1, 'title' => 'test3'))); + + $this->assertTrue($taskTagModel->save(1, 1, array('My tag 1', 'My tag 2'))); + $this->assertTrue($taskTagModel->save(1, 2, array('My tag 3'))); + + $board = BoardFormatter::getInstance($this->container) + ->withQuery($taskFinderModel->getExtendedQuery()) + ->withProjectId(1) + ->format(); + + $this->assertCount(1, $board); + + $this->assertEquals('Default swimlane', $board[0]['name']); + $this->assertCount(4, $board[0]['columns']); + $this->assertEquals(1, $board[0]['nb_swimlanes']); + $this->assertEquals(4, $board[0]['nb_columns']); + $this->assertEquals(3, $board[0]['nb_tasks']); + $this->assertEquals(0, $board[0]['score']); + + $this->assertEquals(2, $board[0]['columns'][0]['column_nb_tasks']); + $this->assertEquals(0, $board[0]['columns'][1]['column_nb_tasks']); + $this->assertEquals(1, $board[0]['columns'][2]['column_nb_tasks']); + $this->assertEquals(0, $board[0]['columns'][3]['column_nb_tasks']); + + $this->assertEquals(0, $board[0]['columns'][0]['column_score']); + $this->assertEquals(0, $board[0]['columns'][1]['column_score']); + $this->assertEquals(0, $board[0]['columns'][2]['column_score']); + $this->assertEquals(0, $board[0]['columns'][3]['column_score']); + + $this->assertSame(0, $board[0]['columns'][0]['score']); + $this->assertSame(0, $board[0]['columns'][1]['score']); + $this->assertSame(0, $board[0]['columns'][2]['score']); + $this->assertSame(0, $board[0]['columns'][3]['score']); + + $this->assertSame(2, $board[0]['columns'][0]['nb_tasks']); + $this->assertSame(0, $board[0]['columns'][1]['nb_tasks']); + $this->assertSame(1, $board[0]['columns'][2]['nb_tasks']); + $this->assertSame(0, $board[0]['columns'][3]['nb_tasks']); + + $this->assertEquals('test1', $board[0]['columns'][0]['tasks'][0]['title']); + $this->assertEquals('test3', $board[0]['columns'][0]['tasks'][1]['title']); + $this->assertEquals('test2', $board[0]['columns'][2]['tasks'][0]['title']); + + $expected = array( + array( + 'id' => 1, + 'name' => 'My tag 1', + 'task_id' => 1, + ), + array( + 'id' => 2, + 'name' => 'My tag 2', + 'task_id' => 1, + ), + ); + + $this->assertEquals($expected, $board[0]['columns'][0]['tasks'][0]['tags']); + $this->assertEquals(array(), $board[0]['columns'][0]['tasks'][1]['tags']); + + $expected = array( + array( + 'id' => 3, + 'name' => 'My tag 3', + 'task_id' => 2, + ), + ); + + $this->assertEquals($expected, $board[0]['columns'][2]['tasks'][0]['tags']); + } } diff --git a/tests/units/FunctionTest.php b/tests/units/FunctionTest.php index 72895845..1c5f971d 100644 --- a/tests/units/FunctionTest.php +++ b/tests/units/FunctionTest.php @@ -18,4 +18,106 @@ class FunctionTest extends Base $this->assertSame(579.7, array_column_sum($input, 'my_column')); } + + public function testArrayColumnIndex() + { + $input = array( + array( + 'k1' => 11, + 'k2' => 22, + ), + array( + 'k1' => 11, + 'k2' => 55, + ), + array( + 'k1' => 33, + 'k2' => 44, + ), + array() + ); + + $expected = array( + 11 => array( + array( + 'k1' => 11, + 'k2' => 22, + ), + array( + 'k1' => 11, + 'k2' => 55, + ) + ), + 33 => array( + array( + 'k1' => 33, + 'k2' => 44, + ) + ) + ); + + $this->assertSame($expected, array_column_index($input, 'k1')); + } + + public function testArrayMergeRelation() + { + $relations = array( + 88 => array( + 'id' => 123, + 'value' => 'test1', + ), + 99 => array( + 'id' => 456, + 'value' => 'test2', + ), + 55 => array() + ); + + $input = array( + array(), + array( + 'task_id' => 88, + 'title' => 'task1' + ), + array( + 'task_id' => 99, + 'title' => 'task2' + ), + array( + 'task_id' => 11, + 'title' => 'task3' + ) + ); + + $expected = array( + array( + 'my_relation' => array(), + ), + array( + 'task_id' => 88, + 'title' => 'task1', + 'my_relation' => array( + 'id' => 123, + 'value' => 'test1', + ), + ), + array( + 'task_id' => 99, + 'title' => 'task2', + 'my_relation' => array( + 'id' => 456, + 'value' => 'test2', + ), + ), + array( + 'task_id' => 11, + 'title' => 'task3', + 'my_relation' => array(), + ) + ); + + array_merge_relation($input, $relations, 'my_relation', 'task_id'); + + $this->assertSame($expected, $input); + } } diff --git a/tests/units/Model/TaskTagModelTest.php b/tests/units/Model/TaskTagModelTest.php index c08b571f..819f55b8 100644 --- a/tests/units/Model/TaskTagModelTest.php +++ b/tests/units/Model/TaskTagModelTest.php @@ -24,7 +24,7 @@ class TaskTagModelTest extends Base $this->assertTrue($taskTagModel->save(1, 1, array('My tag 1', 'My tag 2', 'My tag 3'))); - $tags = $taskTagModel->getAll(1); + $tags = $taskTagModel->getTagsByTask(1); $this->assertCount(3, $tags); $this->assertEquals(1, $tags[0]['id']); @@ -38,7 +38,7 @@ class TaskTagModelTest extends Base $this->assertTrue($taskTagModel->save(1, 1, array('My tag 3', 'My tag 1', 'My tag 4'))); - $tags = $taskTagModel->getAll(1); + $tags = $taskTagModel->getTagsByTask(1); $this->assertCount(3, $tags); $this->assertEquals(1, $tags[0]['id']); @@ -64,4 +64,50 @@ class TaskTagModelTest extends Base $this->assertEquals('My tag 4', $tags[3]['name']); $this->assertEquals(1, $tags[3]['project_id']); } + + public function testGetTagsForTasks() + { + $projectModel = new ProjectModel($this->container); + $taskCreationModel = new TaskCreationModel($this->container); + $taskTagModel = new TaskTagModel($this->container); + + $this->assertEquals(1, $projectModel->create(array('name' => 'Test'))); + $this->assertEquals(1, $taskCreationModel->create(array('project_id' => 1, 'title' => 'test1'))); + $this->assertEquals(2, $taskCreationModel->create(array('project_id' => 1, 'title' => 'test2'))); + $this->assertEquals(3, $taskCreationModel->create(array('project_id' => 1, 'title' => 'test3'))); + + $this->assertTrue($taskTagModel->save(1, 1, array('My tag 1', 'My tag 2', 'My tag 3'))); + $this->assertTrue($taskTagModel->save(1, 2, array('My tag 3'))); + + $tags = $taskTagModel->getTagsByTasks(array(1, 2, 3)); + + $expected = array( + 1 => array( + array( + 'id' => 1, + 'name' => 'My tag 1', + 'task_id' => 1 + ), + array( + 'id' => 2, + 'name' => 'My tag 2', + 'task_id' => 1 + ), + array( + 'id' => 3, + 'name' => 'My tag 3', + 'task_id' => 1 + ), + ), + 2 => array( + array( + 'id' => 3, + 'name' => 'My tag 3', + 'task_id' => 2, + ) + ) + ); + + $this->assertEquals($expected, $tags); + } } -- cgit v1.2.3 From b2e92480c29acb15586bc8ea305c8416927a667c Mon Sep 17 00:00:00 2001 From: Frederic Guillot Date: Fri, 24 Jun 2016 11:40:58 -0400 Subject: Added filter class for tags --- app/Filter/TaskTagFilter.php | 74 +++++++++++++++++++ app/Model/TaskTagModel.php | 20 ++--- app/ServiceProvider/FilterProvider.php | 4 + doc/search.markdown | 6 ++ tests/units/Base.php | 4 +- tests/units/Core/Filter/LexerTest.php | 12 +++ tests/units/Filter/TaskTagFilterTest.php | 121 +++++++++++++++++++++++++++++++ tests/units/Model/TaskTagModelTest.php | 14 ++++ 8 files changed, 243 insertions(+), 12 deletions(-) create mode 100644 app/Filter/TaskTagFilter.php create mode 100644 tests/units/Filter/TaskTagFilterTest.php (limited to 'app') diff --git a/app/Filter/TaskTagFilter.php b/app/Filter/TaskTagFilter.php new file mode 100644 index 00000000..01b6f625 --- /dev/null +++ b/app/Filter/TaskTagFilter.php @@ -0,0 +1,74 @@ +db = $db; + return $this; + } + + /** + * Apply filter + * + * @access public + * @return FilterInterface + */ + public function apply() + { + $task_ids = $this->db + ->table(TagModel::TABLE) + ->ilike(TagModel::TABLE.'.name', $this->value) + ->asc(TagModel::TABLE.'.project_id') + ->join(TaskTagModel::TABLE, 'tag_id', 'id') + ->findAllByColumn(TaskTagModel::TABLE.'.task_id'); + + if (empty($task_ids)) { + $task_ids = array(-1); + } + + $this->query->in(TaskModel::TABLE.'.id', $task_ids); + + return $this; + } +} diff --git a/app/Model/TaskTagModel.php b/app/Model/TaskTagModel.php index 3dd1dd88..91dfd224 100644 --- a/app/Model/TaskTagModel.php +++ b/app/Model/TaskTagModel.php @@ -74,9 +74,9 @@ class TaskTagModel extends Base * Add or update a list of tags to a task * * @access public - * @param integer $project_id - * @param integer $task_id - * @param string[] $tags + * @param integer $project_id + * @param integer $task_id + * @param string[] $tags * @return boolean */ public function save($project_id, $task_id, array $tags) @@ -123,10 +123,10 @@ class TaskTagModel extends Base * Associate missing tags * * @access protected - * @param integer $project_id - * @param integer $task_id - * @param array $task_tags - * @param array $tags + * @param integer $project_id + * @param integer $task_id + * @param array $task_tags + * @param string[] $tags * @return bool */ protected function associateTags($project_id, $task_id, $task_tags, $tags) @@ -146,9 +146,9 @@ class TaskTagModel extends Base * Dissociate removed tags * * @access protected - * @param integer $task_id - * @param array $task_tags - * @param array $tags + * @param integer $task_id + * @param array $task_tags + * @param string[] $tags * @return bool */ protected function dissociateTags($task_id, $task_tags, $tags) diff --git a/app/ServiceProvider/FilterProvider.php b/app/ServiceProvider/FilterProvider.php index cdef9ed8..20281a09 100644 --- a/app/ServiceProvider/FilterProvider.php +++ b/app/ServiceProvider/FilterProvider.php @@ -26,6 +26,7 @@ use Kanboard\Filter\TaskReferenceFilter; use Kanboard\Filter\TaskStatusFilter; use Kanboard\Filter\TaskSubtaskAssigneeFilter; use Kanboard\Filter\TaskSwimlaneFilter; +use Kanboard\Filter\TaskTagFilter; use Kanboard\Filter\TaskTitleFilter; use Kanboard\Model\ProjectModel; use Kanboard\Model\ProjectGroupRoleModel; @@ -163,6 +164,9 @@ class FilterProvider implements ServiceProviderInterface ->setDatabase($c['db']) ) ->withFilter(new TaskSwimlaneFilter()) + ->withFilter(TaskTagFilter::getInstance() + ->setDatabase($c['db']) + ) ->withFilter(new TaskTitleFilter(), true) ; diff --git a/doc/search.markdown b/doc/search.markdown index 37bb8625..ab8e0b5a 100644 --- a/doc/search.markdown +++ b/doc/search.markdown @@ -152,6 +152,12 @@ Attribute: **comment** - Find comments that contains this title: `comment:"My comment message"` +### Search by tags + +Attribute: **tag** + +- Example: `tag:"My tag"` + Activity stream search ---------------------- diff --git a/tests/units/Base.php b/tests/units/Base.php index f7bee241..9dbfb280 100644 --- a/tests/units/Base.php +++ b/tests/units/Base.php @@ -48,8 +48,8 @@ abstract class Base extends PHPUnit_Framework_TestCase new Stopwatch ); - $this->container['db']->logQueries = true; - $this->container['logger'] = new Logger; + $this->container['db']->getStatementHandler()->withLogging(); + $this->container['logger'] = new Logger(); $this->container['httpClient'] = $this ->getMockBuilder('\Kanboard\Core\Http\Client') diff --git a/tests/units/Core/Filter/LexerTest.php b/tests/units/Core/Filter/LexerTest.php index c72231c4..b777531d 100644 --- a/tests/units/Core/Filter/LexerTest.php +++ b/tests/units/Core/Filter/LexerTest.php @@ -202,4 +202,16 @@ class LexerTest extends Base $this->assertSame($expected, $lexer->tokenize('६Δↈ五一')); } + + public function testTokenizeWithMultipleValues() + { + $lexer = new Lexer(); + $lexer->addToken("/^(tag:)/", 'T_TAG'); + + $expected = array( + 'T_TAG' => array('tag 1', 'tag2'), + ); + + $this->assertSame($expected, $lexer->tokenize('tag:"tag 1" tag:tag2')); + } } diff --git a/tests/units/Filter/TaskTagFilterTest.php b/tests/units/Filter/TaskTagFilterTest.php new file mode 100644 index 00000000..a36d3475 --- /dev/null +++ b/tests/units/Filter/TaskTagFilterTest.php @@ -0,0 +1,121 @@ +container); + $projectModel = new ProjectModel($this->container); + $taskCreationModel = new TaskCreationModel($this->container); + $taskTagModel = new TaskTagModel($this->container); + $query = $taskFinderModel->getExtendedQuery(); + + $this->assertEquals(1, $projectModel->create(array('name' => 'Test'))); + $this->assertEquals(1, $taskCreationModel->create(array('project_id' => 1, 'title' => 'test1'))); + $this->assertEquals(2, $taskCreationModel->create(array('project_id' => 1, 'title' => 'test2'))); + $this->assertEquals(3, $taskCreationModel->create(array('project_id' => 1, 'title' => 'test3'))); + + $this->assertTrue($taskTagModel->save(1, 1, array('My tag 1', 'My tag 2', 'My tag 3'))); + $this->assertTrue($taskTagModel->save(1, 2, array('My tag 3'))); + + $filter = new TaskTagFilter(); + $filter->setDatabase($this->container['db']); + $filter->withQuery($query); + $filter->withValue('my tag 3'); + $filter->apply(); + + $tasks = $query->findAll(); + $this->assertCount(2, $tasks); + $this->assertEquals('test1', $tasks[0]['title']); + $this->assertEquals('test2', $tasks[1]['title']); + } + + public function testWithSingleMatch() + { + $taskFinderModel = new TaskFinderModel($this->container); + $projectModel = new ProjectModel($this->container); + $taskCreationModel = new TaskCreationModel($this->container); + $taskTagModel = new TaskTagModel($this->container); + $query = $taskFinderModel->getExtendedQuery(); + + $this->assertEquals(1, $projectModel->create(array('name' => 'Test'))); + $this->assertEquals(1, $taskCreationModel->create(array('project_id' => 1, 'title' => 'test1'))); + $this->assertEquals(2, $taskCreationModel->create(array('project_id' => 1, 'title' => 'test2'))); + $this->assertEquals(3, $taskCreationModel->create(array('project_id' => 1, 'title' => 'test3'))); + + $this->assertTrue($taskTagModel->save(1, 1, array('My tag 1', 'My tag 2', 'My tag 3'))); + $this->assertTrue($taskTagModel->save(1, 2, array('My tag 3'))); + + $filter = new TaskTagFilter(); + $filter->setDatabase($this->container['db']); + $filter->withQuery($query); + $filter->withValue('my tag 2'); + $filter->apply(); + + $tasks = $query->findAll(); + $this->assertCount(1, $tasks); + $this->assertEquals('test1', $tasks[0]['title']); + } + + public function testWithNoMatch() + { + $taskFinderModel = new TaskFinderModel($this->container); + $projectModel = new ProjectModel($this->container); + $taskCreationModel = new TaskCreationModel($this->container); + $taskTagModel = new TaskTagModel($this->container); + $query = $taskFinderModel->getExtendedQuery(); + + $this->assertEquals(1, $projectModel->create(array('name' => 'Test'))); + $this->assertEquals(1, $taskCreationModel->create(array('project_id' => 1, 'title' => 'test1'))); + $this->assertEquals(2, $taskCreationModel->create(array('project_id' => 1, 'title' => 'test2'))); + $this->assertEquals(3, $taskCreationModel->create(array('project_id' => 1, 'title' => 'test3'))); + + $this->assertTrue($taskTagModel->save(1, 1, array('My tag 1', 'My tag 2', 'My tag 3'))); + $this->assertTrue($taskTagModel->save(1, 2, array('My tag 3'))); + + $filter = new TaskTagFilter(); + $filter->setDatabase($this->container['db']); + $filter->withQuery($query); + $filter->withValue('my tag 42'); + $filter->apply(); + + $tasks = $query->findAll(); + $this->assertCount(0, $tasks); + } + + public function testWithSameTagInMultipleProjects() + { + $taskFinderModel = new TaskFinderModel($this->container); + $projectModel = new ProjectModel($this->container); + $taskCreationModel = new TaskCreationModel($this->container); + $taskTagModel = new TaskTagModel($this->container); + $query = $taskFinderModel->getExtendedQuery(); + + $this->assertEquals(1, $projectModel->create(array('name' => 'Test'))); + $this->assertEquals(2, $projectModel->create(array('name' => 'Test'))); + $this->assertEquals(1, $taskCreationModel->create(array('project_id' => 1, 'title' => 'test1'))); + $this->assertEquals(2, $taskCreationModel->create(array('project_id' => 2, 'title' => 'test2'))); + + $this->assertTrue($taskTagModel->save(1, 1, array('My tag'))); + $this->assertTrue($taskTagModel->save(2, 2, array('My tag'))); + + $filter = new TaskTagFilter(); + $filter->setDatabase($this->container['db']); + $filter->withQuery($query); + $filter->withValue('my tag'); + $filter->apply(); + + $tasks = $query->findAll(); + $this->assertCount(2, $tasks); + $this->assertEquals('test1', $tasks[0]['title']); + $this->assertEquals('test2', $tasks[1]['title']); + } +} diff --git a/tests/units/Model/TaskTagModelTest.php b/tests/units/Model/TaskTagModelTest.php index 819f55b8..73bbeac1 100644 --- a/tests/units/Model/TaskTagModelTest.php +++ b/tests/units/Model/TaskTagModelTest.php @@ -110,4 +110,18 @@ class TaskTagModelTest extends Base $this->assertEquals($expected, $tags); } + + public function testGetTagsForTasksWithEmptyList() + { + $projectModel = new ProjectModel($this->container); + $taskCreationModel = new TaskCreationModel($this->container); + $taskTagModel = new TaskTagModel($this->container); + + $this->assertEquals(1, $projectModel->create(array('name' => 'Test'))); + $this->assertEquals(1, $taskCreationModel->create(array('project_id' => 1, 'title' => 'test1'))); + $this->assertTrue($taskTagModel->save(1, 1, array('My tag 1', 'My tag 2', 'My tag 3'))); + + $tags = $taskTagModel->getTagsByTasks(array()); + $this->assertEquals(array(), $tags); + } } -- cgit v1.2.3 From 18cb7ad0a4a96be63030f5207b74a195c8b6cd6c Mon Sep 17 00:00:00 2001 From: Frederic Guillot Date: Fri, 24 Jun 2016 15:43:34 -0400 Subject: Expose tags to the user interface (first prototype) --- app/Controller/TaskModificationController.php | 1 + app/Controller/TaskViewController.php | 2 + app/Helper/TaskHelper.php | 28 +++ app/Model/TagModel.php | 18 ++ app/Model/TaskCreationModel.php | 14 +- app/Model/TaskModificationModel.php | 5 + app/Template/board/task_footer.php | 10 + app/Template/task/details.php | 259 ++++++++++++++------------ app/Template/task/public.php | 7 +- app/Template/task/show.php | 1 + app/Template/task_creation/show.php | 4 +- app/Template/task_gantt_creation/show.php | 5 +- app/Template/task_modification/edit_task.php | 4 +- assets/css/app.min.css | 2 +- assets/css/print.min.css | 2 +- assets/css/src/board.css | 13 -- assets/css/src/form.css | 10 +- assets/css/src/task.css | 31 +++ assets/css/vendor.min.css | 2 + assets/js/app.min.js | 4 +- assets/js/src/App.js | 7 + assets/js/src/Popover.js | 1 + assets/js/vendor.min.js | 3 + bower.json | 3 +- gulpfile.js | 2 + tests/units/Filter/TaskTagFilterTest.php | 5 +- 26 files changed, 286 insertions(+), 157 deletions(-) (limited to 'app') diff --git a/app/Controller/TaskModificationController.php b/app/Controller/TaskModificationController.php index f9c63c12..d55a7193 100644 --- a/app/Controller/TaskModificationController.php +++ b/app/Controller/TaskModificationController.php @@ -98,6 +98,7 @@ class TaskModificationController extends BaseController 'values' => $values, 'errors' => $errors, 'task' => $task, + 'tags' => $this->taskTagModel->getList($task['id']), 'users_list' => $this->projectUserRoleModel->getAssignableUsersList($task['project_id']), 'colors_list' => $this->colorModel->getList(), 'categories_list' => $this->categoryModel->getList($task['project_id']), diff --git a/app/Controller/TaskViewController.php b/app/Controller/TaskViewController.php index bd1e86ae..f40f8bea 100644 --- a/app/Controller/TaskViewController.php +++ b/app/Controller/TaskViewController.php @@ -45,6 +45,7 @@ class TaskViewController extends BaseController 'task' => $task, 'columns_list' => $this->columnModel->getList($task['project_id']), 'colors_list' => $this->colorModel->getList(), + 'tags' => $this->taskTagModel->getList($task['id']), 'title' => $task['title'], 'no_layout' => true, 'auto_refresh' => true, @@ -82,6 +83,7 @@ class TaskViewController extends BaseController 'internal_links' => $this->taskLinkModel->getAllGroupedByLabel($task['id']), 'external_links' => $this->taskExternalLinkModel->getAll($task['id']), 'link_label_list' => $this->linkModel->getList(0, false), + 'tags' => $this->taskTagModel->getList($task['id']), ))); } diff --git a/app/Helper/TaskHelper.php b/app/Helper/TaskHelper.php index e33438d6..f272059d 100644 --- a/app/Helper/TaskHelper.php +++ b/app/Helper/TaskHelper.php @@ -40,6 +40,34 @@ class TaskHelper extends Base return $this->taskModel->getRecurrenceBasedateList(); } + public function selectTitle(array $values, array $errors) + { + $html = $this->helper->form->label(t('Title'), 'title'); + $html .= $this->helper->form->text('title', $values, $errors, array('autofocus', 'required', 'maxlength="200"', 'tabindex="1"'), 'form-input-large'); + return $html; + } + + public function selectTags(array $project, array $tags = array()) + { + $options = $this->tagModel->getAssignableList($project['id']); + + $html = $this->helper->form->label(t('Tags'), 'tags[]'); + $html .= ''; + + return $html; + } + public function selectAssignee(array $users, array $values, array $errors = array(), array $attributes = array()) { $attributes = array_merge(array('tabindex="3"'), $attributes); diff --git a/app/Model/TagModel.php b/app/Model/TagModel.php index 1be05a66..8eb5e5ba 100644 --- a/app/Model/TagModel.php +++ b/app/Model/TagModel.php @@ -42,6 +42,24 @@ class TagModel extends Base return $this->db->table(self::TABLE)->eq('project_id', $project_id)->asc('name')->findAll(); } + /** + * Get assignable tags for a project + * + * @access public + * @param integer $project_id + * @return array + */ + public function getAssignableList($project_id) + { + return $this->db->hashtable(self::TABLE) + ->beginOr() + ->eq('project_id', $project_id) + ->eq('project_id', 0) + ->closeOr() + ->asc('name') + ->getAll('id', 'name'); + } + /** * Get one tag * diff --git a/app/Model/TaskCreationModel.php b/app/Model/TaskCreationModel.php index 3800f831..fa2d32c6 100644 --- a/app/Model/TaskCreationModel.php +++ b/app/Model/TaskCreationModel.php @@ -22,11 +22,13 @@ class TaskCreationModel extends Base */ public function create(array $values) { - if (! $this->projectModel->exists($values['project_id'])) { - return 0; - } - $position = empty($values['position']) ? 0 : $values['position']; + $tags = array(); + + if (isset($values['tags'])) { + $tags = $values['tags']; + unset($values['tags']); + } $this->prepare($values); $task_id = $this->db->table(TaskModel::TABLE)->persist($values); @@ -36,6 +38,10 @@ class TaskCreationModel extends Base $this->taskPositionModel->movePosition($values['project_id'], $task_id, $values['column_id'], $position, $values['swimlane_id'], false); } + if (! empty($tags)) { + $this->taskTagModel->save($values['project_id'], $task_id, $tags); + } + $this->fireEvents($task_id, $values); } diff --git a/app/Model/TaskModificationModel.php b/app/Model/TaskModificationModel.php index 762af2c5..0fc3617e 100644 --- a/app/Model/TaskModificationModel.php +++ b/app/Model/TaskModificationModel.php @@ -85,6 +85,11 @@ class TaskModificationModel extends Base */ public function prepare(array &$values) { + if (isset($values['tags'])) { + $this->taskTagModel->save($values['project_id'], $values['id'], $values['tags']); + unset($values['tags']); + } + $values = $this->dateParser->convert($values, array('date_due')); $values = $this->dateParser->convert($values, array('date_started'), true); diff --git a/app/Template/board/task_footer.php b/app/Template/board/task_footer.php index f6cbff70..37d13605 100644 --- a/app/Template/board/task_footer.php +++ b/app/Template/board/task_footer.php @@ -18,6 +18,16 @@ + +
+
    + +
  • text->e($tag['name']) ?>
  • + +
+
+ +
diff --git a/app/Template/task/details.php b/app/Template/task/details.php index fe2bba67..695957f9 100644 --- a/app/Template/task/details.php +++ b/app/Template/task/details.php @@ -4,146 +4,157 @@ hook->render('template:task:details:top', array('task' => $task)) ?>
-
-
    -
  • - - - - - - - - -
  • -
  • - -
  • - +
    +
    +
    • - text->e($task['reference']) ?> + + + + + + + +
    • - -
    • - text->e($task['score']) ?> +
    • - - -
    • - - url->link(t('Public link'), 'TaskViewController', 'readonly', array('task_id' => $task['id'], 'token' => $project['token']), false, '', '', true) ?> -
    • - - -
    • - - url->link(t('Back to the board'), 'BoardViewController', 'readonly', array('token' => $project['token'])) ?> -
    • - -
    • + +
    • + text->e($task['reference']) ?> +
    • + + +
    • + text->e($task['score']) ?> +
    • + + +
    • + + url->link(t('Public link'), 'TaskViewController', 'readonly', array('task_id' => $task['id'], 'token' => $project['token']), false, '', '', true) ?> +
    • + + +
    • + + url->link(t('Back to the board'), 'BoardViewController', 'readonly', array('token' => $project['token'])) ?> +
    • + +
    • - hook->render('template:task:details:first-column', array('task' => $task)) ?> -
    -
    -
    -
      - + hook->render('template:task:details:first-column', array('task' => $task)) ?> +
    +
    +
    +
      + +
    • + + text->e($task['category_name']) ?> +
    • + + +
    • + + text->e($task['swimlane_name']) ?> +
    • +
    • - - text->e($task['category_name']) ?> + + text->e($task['column_title']) ?>
    • - -
    • - - text->e($task['swimlane_name']) ?> + +
    • - -
    • - - text->e($task['column_title']) ?> -
    • -
    • - - -
    • - hook->render('template:task:details:second-column', array('task' => $task)) ?> -
    -
    -
    -
      -
    • - - - - text->e($task['assignee_name'] ?: $task['assignee_username']) ?> - - + hook->render('template:task:details:second-column', array('task' => $task)) ?> +
    +
    +
    +
      +
    • + + + + text->e($task['assignee_name'] ?: $task['assignee_username']) ?> + + + + +
    • + +
    • + + text->e($task['creator_name'] ?: $task['creator_username']) ?> +
    • + + +
    • + + dt->date($task['date_due']) ?> +
    • + + +
    • + + +
    • - - - +
    • - - text->e($task['creator_name'] ?: $task['creator_username']) ?> + +
    • - - -
    • - - dt->date($task['date_due']) ?> -
    • - - -
    • - - -
    • - - -
    • - - -
    • - + - hook->render('template:task:details:third-column', array('task' => $task)) ?> -
    -
    -
    -
      -
    • - - dt->datetime($task['date_creation']) ?> -
    • -
    • - - dt->datetime($task['date_modification']) ?> -
    • - -
    • - - dt->datetime($task['date_completed']) ?> -
    • - - -
    • - - dt->datetime($task['date_started']) ?> -
    • - - -
    • - - dt->datetime($task['date_moved']) ?> -
    • - + hook->render('template:task:details:third-column', array('task' => $task)) ?> +
    +
    +
    +
      +
    • + + dt->datetime($task['date_creation']) ?> +
    • +
    • + + dt->datetime($task['date_modification']) ?> +
    • + +
    • + + dt->datetime($task['date_completed']) ?> +
    • + + +
    • + + dt->datetime($task['date_started']) ?> +
    • + + +
    • + + dt->datetime($task['date_moved']) ?> +
    • + - hook->render('template:task:details:fourth-column', array('task' => $task)) ?> -
    + hook->render('template:task:details:fourth-column', array('task' => $task)) ?> +
+
+ +
+
    + +
  • text->e($tag) ?>
  • + +
+
+
diff --git a/app/Template/task/public.php b/app/Template/task/public.php index 94782163..b8405ff7 100644 --- a/app/Template/task/public.php +++ b/app/Template/task/public.php @@ -1,5 +1,10 @@
- render('task/details', array('task' => $task, 'project' => $project, 'editable' => false)) ?> + render('task/details', array( + 'task' => $task, + 'tags' => $tags, + 'project' => $project, + 'editable' => false, + )) ?> render('task/description', array( 'task' => $task, diff --git a/app/Template/task/show.php b/app/Template/task/show.php index 2b54eea8..80786715 100644 --- a/app/Template/task/show.php +++ b/app/Template/task/show.php @@ -2,6 +2,7 @@ render('task/details', array( 'task' => $task, + 'tags' => $tags, 'project' => $project, 'editable' => $this->user->hasProjectAccess('TaskModificationController', 'edit', $project['id']), )) ?> diff --git a/app/Template/task_creation/show.php b/app/Template/task_creation/show.php index 7bebbfe9..cd752eba 100644 --- a/app/Template/task_creation/show.php +++ b/app/Template/task_creation/show.php @@ -7,8 +7,7 @@ form->csrf() ?>
- form->label(t('Title'), 'title') ?> - form->text('title', $values, $errors, array('autofocus', 'required', 'maxlength="200"', 'tabindex="1"'), 'form-input-large') ?> + task->selectTitle($values, $errors) ?> form->label(t('Description'), 'description') ?> form->textarea( @@ -23,6 +22,7 @@ 'markdown-editor' ) ?> + task->selectTags($project) ?> render('task/color_picker', array('colors_list' => $colors_list, 'values' => $values)) ?> diff --git a/app/Template/task_gantt_creation/show.php b/app/Template/task_gantt_creation/show.php index 683bc8c8..d1bfa67c 100644 --- a/app/Template/task_gantt_creation/show.php +++ b/app/Template/task_gantt_creation/show.php @@ -8,12 +8,11 @@ form->hidden('position', $values) ?>
- form->label(t('Title'), 'title') ?> - form->text('title', $values, $errors, array('autofocus', 'required', 'maxlength="200"', 'tabindex="1"'), 'form-input-large') ?> + task->selectTitle($values, $errors) ?> form->label(t('Description'), 'description') ?> form->textarea('description', $values, $errors, array('placeholder="'.t('Leave a description').'"', 'tabindex="2"'), 'markdown-editor') ?> - + task->selectTags($project) ?> render('task/color_picker', array('colors_list' => $colors_list, 'values' => $values)) ?>
diff --git a/app/Template/task_modification/edit_task.php b/app/Template/task_modification/edit_task.php index 0707fd9a..d8f18743 100644 --- a/app/Template/task_modification/edit_task.php +++ b/app/Template/task_modification/edit_task.php @@ -7,8 +7,8 @@ form->hidden('project_id', $values) ?>
- form->label(t('Title'), 'title') ?> - form->text('title', $values, $errors, array('autofocus', 'required', 'maxlength="200"', 'tabindex="1"')) ?> + task->selectTitle($values, $errors) ?> + task->selectTags($project, $tags) ?> task->selectAssignee($users_list, $values, $errors) ?> task->selectCategory($categories_list, $values, $errors) ?> task->selectPriority($project, $values) ?> diff --git a/assets/css/app.min.css b/assets/css/app.min.css index 7d093952..49630a00 100644 --- a/assets/css/app.min.css +++ b/assets/css/app.min.css @@ -1 +1 @@ -a:focus,a:hover,th a{text-decoration:none}h3,label{margin-top:10px}.tooltip-arrow.bottom:after,.tooltip-arrow.top{top:-10px}.form-errors,.ui-tooltip li,ul.no-bullet li{list-style-type:none}.table-fixed td,.table-fixed th,.tooltip-arrow,header h1{overflow:hidden}#board td,td{vertical-align:top}.table-fixed td,.task-board-collapsed,div.ganttview-vtheader-series-name,header h1{text-overflow:ellipsis;white-space:nowrap}blockquote,body,li,ol,p,table,td,th,tr,ul{margin:0;padding:0;font-size:100%}form,table{margin-bottom:20px}body{margin-left:10px;margin-right:10px;padding-bottom:10px;color:#333;font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;text-rendering:optimizeLegibility}.page{clear:both}ul.no-bullet li{margin-left:0}.pull-right{text-align:right}hr{border:0;height:0;border-top:1px solid rgba(0,0,0,.1);border-bottom:1px solid rgba(255,255,255,.3)}.chosen-select{min-height:27px}#ui-datepicker-div{font-size:.8em}#app-loading-icon{position:fixed;right:3px;bottom:3px}.web-notification-icon{color:#36C}.web-notification-icon:focus,.web-notification-icon:hover{color:#000}a:hover,h1,h2,h3,th a{color:#333}.smaller{font-size:.85em}a{color:#36C;border:none}a:focus{outline:0;color:#DF5353;border:1px dotted #aaa}h1,h2,h3{font-weight:400}h2{font-size:1.3em;margin-bottom:10px}h3{font-size:1.2em}table{width:100%;border-collapse:collapse;border-spacing:0;font-size:.95em}#calendar table{margin-bottom:0}td,th{border:1px solid #eee;padding:.5em 3px}th{background:#fbfbfb;text-align:left}td li{margin-left:20px}.table-small{font-size:.8em}th a:focus,th a:hover{text-decoration:underline}.page-header h2 a,a.btn,header a{text-decoration:none}.table-fixed{table-layout:fixed;white-space:nowrap}.table-stripped tr:nth-child(odd){background:#fefefe}.column-3{width:3%}.column-5{width:5%}.column-8{width:7.5%}.column-10{width:10%}.column-12{width:12%}.column-15{width:15%}.column-18{width:18%}.column-20{width:20%}.column-25{width:25%}.column-30{width:30%}.column-35{width:35%}.column-40{width:40%}.column-50{width:50%}.column-60{width:60%}.column-70,.column-80{width:70%}.draggable-row-handle{cursor:move;color:#dedede}.btn,.color-square,.draggable-item,.task-board-change-assignee,label{cursor:pointer}.draggable-row-handle:hover{color:#333}tr.draggable-item-selected{background:#fff;border:2px solid #666;box-shadow:4px 2px 10px -4px rgba(0,0,0,.55)}tr.draggable-item-selected td{border-top:none;border-bottom:none}tr.draggable-item-selected td:first-child{border-left:none}tr.draggable-item-selected td:last-child{border-right:none}.table-stripped tr.draggable-item-hover,tr.draggable-item-hover{background:#FEFFF2}label{display:block}input[type=number],input[type=date],input[type=email],input[type=password],input[type=text]{color:#888;border:1px solid #ccc;width:300px;max-width:95%;font-size:100%;height:25px;padding-bottom:0;font-family:sans-serif;margin-top:10px;-webkit-appearance:none;appearance:none}input[type=number]:focus,input[type=date]:focus,input[type=email]:focus,input[type=password]:focus,input[type=text]:focus,textarea:focus{color:#000;border-color:rgba(82,168,236,.8);outline:0;box-shadow:0 0 8px rgba(82,168,236,.6)}input.form-numeric,input[type=number]{width:70px}textarea{border:1px solid #ccc;width:400px;max-width:99%;height:200px;font-size:100%;font-family:sans-serif}select{max-width:95%}select:focus{outline:0}::-webkit-input-placeholder{color:#ddd;padding-top:2px}::-ms-input-placeholder{color:#ddd;padding-top:2px}::-moz-placeholder{color:#ddd;padding-top:2px}.form-actions{padding-top:20px;clear:both}input.form-error,textarea.form-error{border:2px solid #b94a48}input.form-error:focus,textarea.form-error:focus{box-shadow:none;border:2px solid #b94a48}.form-required{color:red;padding-left:5px;font-weight:700}.form-errors{color:#b94a48}ul.form-errors li{margin-left:0}.form-help{font-size:.8em;color:brown;margin-bottom:15px}.form-inline{padding:0;margin:0;border:none}.form-inline label{display:inline}.form-inline input,.form-inline select{margin:0 15px 0 0}.form-inline .form-required{display:none}.form-inline-group{display:inline}input.form-date,input.form-datetime{width:150px}input.form-input-large{width:400px}.form-column{float:left;margin-right:3%;max-width:50%;min-width:40%}.form-column ul{margin-top:15px}.form-clear{clear:both;padding-top:20px;padding-bottom:10px}.form-login{width:350px;margin:8% auto 0}.form-column li,.form-login li{margin-left:25px;line-height:25px}.form-login h2{margin-bottom:30px;font-size:1.5em;font-weight:700}.popover-form{margin-bottom:0}.reset-password{margin-top:20px}.reset-password a{font-size:.8em;color:#999}.btn{font-size:1.1em;font-weight:400;-webkit-appearance:none;appearance:none;display:inline-block;color:#333;background:#f5f5f5;border:1px solid #ddd;border-radius:2px;padding:3px 10px;margin:0}.btn:hover{border:1px solid #bbb;color:#000;background:#fafafa}.btn-red{border-color:#b0281a;background:#d14836;color:#fff}.btn-red:focus,.btn-red:hover{color:#fff;background:#c53727}.btn-blue{border-color:#3079ed;background:#4d90fe;color:#fff}.btn-blue:focus,.btn-blue:hover{border-color:#2f5bb7;background:#357ae8;color:#fff}.btn:disabled{color:#ccc;border:1px solid #ccc;background:#f7f7f7}.buttons-header{font-size:.9em;margin-bottom:15px}.alert{padding:8px 35px 8px 14px;margin-top:5px;margin-bottom:5px;color:#c09853;background-color:#fcf8e3;border:1px solid #fbeed5;border-radius:4px}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-normal{color:#333;background-color:#f0f0f0;border-color:#ddd}.alert ul{margin-top:10px;margin-bottom:10px}.alert-fade-out,.ui-tooltip-content .markdown p{margin-bottom:0}.alert li{margin-left:25px}.alert-fade-out{text-align:center;position:fixed;bottom:0;left:20%;width:60%;padding-top:5px;padding-bottom:5px;border-width:1px 0 0;border-radius:4px 4px 0 0;z-index:9999}.tooltip-arrow.bottom,.tooltip-arrow.top:after{bottom:-10px}div.ui-tooltip{min-width:200px;max-width:600px;font-size:.85em}.tooltip-arrow{width:20px;height:10px;position:absolute}.tooltip-arrow.align-left{left:10px}.tooltip-arrow.align-right{right:10px}.tooltip-arrow:after{background:#fff;border:1px solid #aaa;box-shadow:0 0 5px #aaa;content:"";position:absolute;width:14px;height:14px;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg)}.tooltip-arrow.align-left:after{left:0}.tooltip-arrow.align-right:after{right:0}.tooltip-large{width:600px}.tooltip .fa-info-circle{color:#999;font-size:.95em}header{margin-top:10px;padding-bottom:10px;border-bottom:1px solid #dedede}header h1{margin:0;padding:0;max-width:70%;float:left}header ul{text-align:right;font-size:.9em}header li{display:inline;padding-left:30px}header a{color:#333}header a:hover{color:#666}nav .active a{color:#333;font-weight:700}.logo a{opacity:.5;color:#d40000}.logo span{color:#333}.logo a:hover{opacity:.8;color:#333}.logo a:focus span,.logo a:hover span{color:#d40000}header .user-links .dropdown{margin-left:15px}header h1 .tooltip{opacity:.3;font-size:.6em}.page-header{margin-bottom:20px}.page-header h2{margin:0;padding:0;font-size:1.4em;font-weight:700;border-bottom:1px dotted #ccc}.page-header h2 a{color:#333}.page-header h2 a:focus,.page-header h2 a:hover{color:#aaa}.page-header ul{text-align:left;margin-top:5px;display:inline-block}.menu-inline li,.page-header li{display:inline;padding-right:15px;font-size:.95em}.page-header li.active a{color:#333;text-decoration:none;font-weight:700}.page-header li.active a:focus,.page-header li.active a:hover{text-decoration:underline}.menu-inline{margin-bottom:5px}.public-board{margin-top:5px}.public-task{max-width:800px;margin:5px auto 0}#board-container{overflow-x:auto}#board{table-layout:fixed;margin-bottom:0}#board th.board-column-header{width:240px}.board-container-compact{overflow-x:initial}@media all and (-ms-high-contrast:active),(-ms-high-contrast:none){.board-container-compact #board{table-layout:auto}}#board th.board-column-header.board-column-compact{width:initial}.board-column-collapsed{display:none}td.board-column-task-collapsed{font-weight:700;background-color:#fbfbfb}#board th.board-column-header-collapsed{width:28px;min-width:28px;text-align:center;overflow:hidden}.board-rotation-wrapper{position:relative;padding:8px 4px;min-height:150px;overflow:hidden}.board-rotation{white-space:nowrap;-webkit-backface-visibility:hidden;-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg);-webkit-transform-origin:0 100%;-moz-transform-origin:0 100%;-ms-transform-origin:0 100%;transform-origin:0 100%}.board-column-title .dropdown-menu{text-decoration:none}.board-add-icon{float:left;padding:0 5px}.board-add-icon a{text-decoration:none;color:#36C;font-size:150%;line-height:70%}.board-add-icon a:focus,.board-add-icon a:hover{text-decoration:none;color:red}.board-column-header-task-count{color:#999;font-weight:400}th.board-column-header-collapsed .board-column-header-task-count{font-size:.85em}a.board-swimlane-toggle{font-size:.95em;text-decoration:none}a.board-swimlane-toggle:focus,a.board-swimlane-toggle:hover{color:#000;text-decoration:none;border:none}.board-task-list{overflow:auto;min-height:60px}.board-task-list-limit{background-color:#DF5353}.draggable-item{user-select:none;-webkit-user-select:none;-moz-user-select:none}.draggable-placeholder{border:2px dashed #000;background:#fafafa;height:70px;margin-bottom:10px}.task-board,div.draggable-item-selected{border:1px solid #000}.task-board-sort-handle{float:left;padding-right:5px}.task-board-saving-state{opacity:.3}.task-board-category:hover,.task-board-change-assignee:hover{opacity:.6}.task-board-saving-icon{position:absolute;margin:auto;width:100%;text-align:center;color:#000}.task-table .dropdown-menu{color:#000;text-decoration:none;font-weight:700}.task-table .dropdown-menu:focus,.task-table .dropdown-menu:hover{text-decoration:underline}td.task-table a{color:#000;text-decoration:none}td.task-table a:hover{text-decoration:underline}.task-board{position:relative;margin-bottom:4px;padding:2px;font-size:.85em;word-wrap:break-word}div.task-board-recent{border-width:2px}div.task-board-status-closed{user-select:none;border:1px dotted #555}.task-board a{color:#000;text-decoration:none}.task-board .dropdown-menu{font-weight:700}.task-board-collapsed{overflow:hidden}.task-board-title{font-size:1.15em;margin-top:5px;margin-bottom:8px}.task-board-title a:hover{text-decoration:underline}.task-board-category-container{text-align:right;margin-top:8px;margin-bottom:8px}.task-board-category{font-weight:500;color:#000;border:1px solid #555;padding:1px 2px;border-radius:4px}.task-board-avatars{text-align:right;float:right}.file-thumbnail img:hover,.task-board-icons a{opacity:.5}.task-board-icons{text-align:right;margin-top:4px;margin-bottom:2px}.task-board-icons span{opacity:.5;margin-left:2px}.task-board-icons a:hover,.task-board-icons span:hover{opacity:1}.task-board-date{font-weight:700;color:#000}span.task-board-date-today{color:#0000D9;opacity:1}span.task-board-date-overdue{color:#D90000;opacity:1}.task-board .task-score{font-weight:700}.task-board-age{display:inline-block;font-size:.9em}span.task-board-age-total{border:1px solid #666;padding:1px 3px;border-top-left-radius:3px;border-bottom-left-radius:3px}span.task-board-age-column{border:1px solid #666;border-left:none;margin-left:-5px;padding:1px 3px;border-top-right-radius:3px;border-bottom-right-radius:3px}#task-summary{margin-bottom:15px}#task-summary h2{color:#666;font-size:2.5em;margin-top:0;padding-top:0}.task-summary-buttons{margin-top:10px;font-size:.85em}.task-summary-container{border:2px solid #000;border-radius:8px;padding:15px;display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-justify-content:space-between;justify-content:space-between}.task-summary-column{font-size:.9em;color:#666}.task-summary-column span{color:#555}.task-summary-column li{line-height:23px}.task-show-title{border:2px solid #000;border-radius:8px;margin-bottom:20px}.task-show-title h2{color:#555;font-size:1.8em;margin:0;padding:8px}.comment-actions,.comment-content,.comment-title{margin-left:55px}.task-link-closed{text-decoration:line-through}.flag-milestone{color:green}.color-picker{min-height:35px}.color-square{display:inline-block;width:30px;height:30px;margin-right:5px;margin-bottom:5px;border:1px solid #000}.color-square:hover{border-style:dotted}div.color-square-selected{border-width:2px;width:28px;height:28px;box-shadow:3px 2px 10px 0 rgba(180,180,180,.9)}.textarea-dropdown,ul.dropdown-submenu-open{list-style:none;box-shadow:0 1px 3px rgba(0,0,0,.15)}.assign-me{font-size:.8em;vertical-align:bottom}.subtasks-table td,.task-links-table td{vertical-align:middle}.comment-sorting{text-align:right;font-size:.5em}.avatar-letter,.pagination,.project-overview-column,div.ganttview-hzheader-day,div.ganttview-hzheader-month{text-align:center}.comment-sorting a{color:#555;font-weight:400;text-decoration:none}.comment-sorting a:hover{color:#aaa}.comment{padding:5px;margin-bottom:15px}.comment-title,.form-column div.CodeMirror,.markdown blockquote,.markdown h1,.markdown p{margin-bottom:10px}.comment:hover{background:#fafafa}.comment-title{border-bottom:1px dotted #eee}.comment-username{font-weight:700;font-size:1.1em}.comment-date{color:#999;font-size:.7em;font-weight:200}.comment-actions{font-size:.8em;margin-top:8px}.subtasks-table,.task-links-table{font-size:.85em}.comment-actions li{display:inline}.comment-actions a{color:#999;text-decoration:none}.markdown h1,.markdown h2,.markdown h3,.markdown h4{text-decoration:underline}.comment-actions a:focus,.comment-actions a:hover{color:#333;text-decoration:underline}.task-links-task-count{color:#999}div.CodeMirror,div.CodeMirror-scroll{max-height:250px;min-height:200px}.markdown-editor-small div.CodeMirror,.markdown-editor-small div.CodeMirror-scroll{min-height:100px;max-height:180px}.markdown{line-height:1.4em}.markdown h1{margin-top:5px;font-size:1.5em;font-weight:700}.markdown h2{font-size:1.2em;font-weight:700}.markdown h3,.markdown h4{font-size:1.1em}.markdown ol,.markdown ul{margin-left:25px;margin-top:10px;margin-bottom:10px}.markdown pre{background:#fbfbfb;padding:10px;border-radius:5px;border:1px solid #ddd;overflow:auto;color:#444}.markdown blockquote{font-style:italic;border-left:3px solid #ddd;padding-left:10px;margin-left:20px}.markdown img{display:block;max-width:80%;margin-top:10px}.documentation{margin:0 auto;padding:20px;max-width:850px;background:#fefefe;border:1px solid #ccc;border-radius:5px;font-size:1.1em;color:#555}.documentation img{border:1px solid #333}.documentation h1{text-decoration:none;font-size:1.8em;margin-bottom:30px}.documentation h2{font-size:1.3em;text-decoration:none;border-bottom:1px solid #ccc;margin-bottom:25px}.documentation li{line-height:30px}.user-mention-link{font-weight:700;color:#000;text-decoration:none}.user-mention-link:hover{color:#555}.listing{border-radius:4px;padding:8px 35px 8px 14px;margin-bottom:20px;border:1px solid #ddd;color:#333;background-color:#fcfcfc;overflow:auto}.activity-title,.sidebar>ul li{border-bottom:1px dotted #efefef}.listing li{list-style-type:square;margin-left:20px;margin-bottom:3px}.activity-event,.listing ul,.sidebar>ul li:last-child{margin-bottom:15px}.listing ul{margin-top:15px}.activity-event{padding:10px}.activity-event:hover{background:#fafafa}.activity-date{margin-left:10px;font-weight:400;color:#999;font-size:.8em}.activity-content{margin-left:55px}.activity-title{font-weight:700;color:#000}.activity-description{font-size:.95em;color:#555;margin-top:10px}.activity-description li{list-style-type:circle}.activity-description ul{margin-top:10px;margin-left:20px}.dashboard-project-stats span{font-size:.75em;margin-right:10px;color:#999}.dashboard-project-stats strong{font-size:1.2em}.dashboard-table-link{font-weight:700;color:#444;text-decoration:none}.dashboard-table-link:focus,.dashboard-table-link:hover{color:#999}.pagination-next{margin-left:5px}.pagination-previous{margin-right:5px}#popover-container{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,.8);overflow:auto;z-index:100}#popover-content{position:absolute;width:70%;left:15%;top:1%;padding:15px;background:#fff;overflow:auto;max-height:90%}#main .confirm{max-width:700px;font-size:1.1em}.sidebar-container{margin-top:10px;height:100%;width:100%;display:-ms-flexbox;display:-webkit-box;display:-moz-box;display:-ms-box;display:box;-ms-flex-direction:row;-webkit-box-orient:horizontal;-moz-box-orient:horizontal;-ms-box-orient:horizontal;box-orient:horizontal}.sidebar-content{padding-left:10px;-ms-flex:1;-webkit-box-flex:1;-moz-box-flex:1;-ms-box-flex:1;box-flex:1}.sidebar{padding-right:10px;border-right:1px dotted #eee;font-size:.95em;max-width:240px;min-width:190px;width:18%;-ms-flex:0 100px;-webkit-box-flex:0;-moz-box-flex:0;-ms-box-flex:0;box-flex:0}.sidebar h2{margin-top:0}.sidebar>ul a{text-decoration:none;color:#999;font-weight:300}.sidebar>ul a:hover{color:#333}.sidebar>ul li{list-style-type:none;line-height:35px;padding-left:13px}.sidebar>ul li:hover{border-left:5px solid #555;padding-left:8px}.sidebar>ul li.active{border-left:5px solid #333;padding-left:8px}.sidebar>ul li.active a{color:#333;font-weight:700}.sidebar-icons>ul li{padding-left:0}.sidebar-icons>ul li.active,.sidebar-icons>ul li:hover{padding-left:0;border-left:none}.sidebar>ul li.active a:focus,.sidebar>ul li.active a:hover{color:#555}@media only screen and (max-width:1024px){body{font-size:.85em}.form-tab{max-width:404px}.form-inline-group input[type=submit],.form-inline-group label{display:block}.form-inline-group input[type=submit]{margin-top:20px}td>input[type=text]{max-width:150px}.page-header .form-input-large{width:300px}}@media only screen and (max-width:1024px) and (orientation:landscape){header{padding-bottom:4px}div.chosen-container{font-size:.9em}input[type=number],input[type=date],input[type=email],input[type=password],input[type=text]{height:18px}.page-header .form-input-large{width:300px}}@media only screen and (max-width:640px){.hide-mobile{display:none}}.dropdown{display:inline;position:relative}.dropdown ul{display:none}ul.dropdown-submenu-open{display:block;position:absolute;z-index:1000;min-width:285px;margin:3px 0 0 1px;padding:6px 0;background-color:#fff;border:1px solid #b2b2b2;border-radius:3px}.dropdown-submenu-open li,.textarea-dropdown li{display:block;margin:0;padding:8px 10px;font-size:.85em;border-bottom:1px solid #f8f8f8;cursor:pointer}.dropdown-submenu-open li.no-hover{cursor:default}.dropdown-submenu-open li:last-child,.textarea-dropdown li:last-child{border:none}.dropdown-submenu-open li:not(.no-hover):hover,.textarea-dropdown .active,.textarea-dropdown li:hover{background:#4078C0;color:#fff}.dropdown-submenu-open li:hover a,.textarea-dropdown .active a,.textarea-dropdown li:hover a{color:#fff}.dropdown-submenu-open a,.textarea-dropdown a{text-decoration:none;color:#333}.dropdown-submenu-open a:focus{text-decoration:underline}.page-header .dropdown{padding-right:10px}.dropdown-menu-link-icon,.dropdown-menu-link-text{color:#333;text-decoration:none}.dropdown-menu-link-text:hover{text-decoration:underline}.textarea-dropdown{margin:3px 0 0 1px;padding:6px 0;background-color:#fff;border:1px solid #b2b2b2;border-radius:3px}#file-dropzone,#screenshot-zone{position:relative;border:2px dashed #ccc;width:99%;height:250px;overflow:auto}#file-dropzone-inner,#screenshot-inner{position:absolute;left:0;bottom:48%;width:100%;text-align:center;color:#aaa}#screenshot-zone.screenshot-pasted{border:2px solid #333}#file-list{margin:20px}#file-list li{list-style-type:none;padding-top:8px;padding-bottom:8px;border-bottom:1px dotted #ddd;width:95%}#file-list li.file-error{font-weight:700;color:#b94a48}.project-header{margin-top:8px;margin-bottom:20px}.action-menu{color:#333;text-decoration:none}.action-menu:focus,.action-menu:hover{text-decoration:underline}.filter-box{display:inline-block;position:relative;font-size:0;margin-bottom:20px}.filter-box form,.project-header .filter-box{margin:0}.filter-box input[type=text]{margin:0;font-size:16px;height:26px;border-color:#ddd;border-top-left-radius:5px;border-bottom-left-radius:5px;vertical-align:top}.filter-box input[type=text]:focus{color:#000;border-color:rgba(82,168,236,.8);outline:0;box-shadow:0 0 8px rgba(82,168,236,.6)}.filter-box div.dropdown{background:#fafafa;display:inline-block;font-size:16px;border:1px solid #ddd;border-left:none;margin:0;padding:0 8px 0 5px;height:27px}.filter-box div.dropdown:last-child{border-top-right-radius:5px;border-bottom-right-radius:5px}.filter-box div.dropdown a{line-height:27px}div.ganttview-grid,div.ganttview-grid-row-cell,div.ganttview-hzheader-day,div.ganttview-hzheader-month,div.ganttview-vtheader,div.ganttview-vtheader-item-name,div.ganttview-vtheader-series{float:left}div.ganttview-grid-row-cell.last,div.ganttview-hzheader-day.last,div.ganttview-hzheader-month.last{border-right:none}div.ganttview{border:1px solid #999}div.ganttview-hzheader-month{width:60px;height:20px;border-right:1px solid #d0d0d0;line-height:20px;overflow:hidden}div.ganttview-hzheader-day{width:20px;height:20px;border-right:1px solid #f0f0f0;border-top:1px solid #d0d0d0;line-height:20px;color:#777}div.ganttview-vtheader{margin-top:41px;width:400px;overflow:hidden;background-color:#fff}div.ganttview-vtheader-item{color:#666}div.ganttview-vtheader-series-name{width:400px;height:31px;line-height:31px;padding-left:3px;border-top:1px solid #d0d0d0;font-size:.9em;overflow:hidden}div.ganttview-vtheader-series-name a{color:#666;text-decoration:none}div.ganttview-vtheader-series-name a:hover{color:#333;text-decoration:underline}div.ganttview-vtheader-series-name a i{color:#000}div.ganttview-vtheader-series-name a:hover i{color:#666}div.ganttview-slide-container{overflow:auto;border-left:1px solid #999}div.ganttview-grid-row-cell{width:20px;height:31px;border-right:1px solid #f0f0f0;border-top:1px solid #f0f0f0}div.ganttview-grid-row-cell.ganttview-weekend{background-color:#fafafa}div.ganttview-blocks{margin-top:40px}div.ganttview-block-container{height:28px;padding-top:4px}div.ganttview-block{position:relative;height:25px;background-color:#E5ECF9;border:1px solid silver;border-radius:3px}.ganttview-block-movable{cursor:move}div.ganttview-block-not-defined{border-color:#000;background-color:#000}div.ganttview-block-text{position:absolute;height:12px;font-size:.7em;color:#999;padding:2px 3px}div.ganttview-block div.ui-resizable-handle.ui-resizable-s{bottom:0}.project-creation-options{max-width:500px;border-left:3px dotted #efefef;margin-top:20px;padding-left:15px;padding-bottom:5px;padding-top:5px}.project-overview-columns{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;align-items:center;-webkit-justify-content:center;justify-content:center;margin-bottom:20px;font-size:1.4em}.project-overview-column{margin-right:80px;padding:3px 15px;border:1px dashed #ddd;border-radius:8px}.project-overview-column strong{font-size:1.3em;color:#444}.project-overview-column span{font-size:.8em;color:#777}.file-thumbnails{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;flex-wrap:wrap;-webkit-justify-content:flex-start;justify-content:flex-start}.file-thumbnail{width:250px;border:1px solid #efefef;border-radius:5px;margin-bottom:20px;box-shadow:4px 2px 10px -6px rgba(0,0,0,.55);margin-right:15px}.file-thumbnail img{border-top-left-radius:5px;border-top-right-radius:5px}.file-thumbnail-content{padding-left:8px;padding-right:8px}.file-thumbnail-title{font-weight:700;font-size:.9em;color:#555}.file-thumbnail-description{font-size:.8em;color:#aaa;margin-top:8px;margin-bottom:5px}.accordion-collapsed,.accordion-content{margin-bottom:25px}.file-viewer{position:relative}.file-viewer img{max-width:95%;max-height:85%;margin-top:10px}.views{display:inline-block;margin-left:10px;margin-right:10px;font-size:.9em}.views li{background:#fafafa;border-left:1px solid #ddd;border-top:1px solid #ddd;border-bottom:1px solid #ddd;display:inline;padding:5px 8px}.views a{color:#555;text-decoration:none}.views a:hover{color:#333;text-decoration:underline}.menu-inline li.active a,.views li.active a{font-weight:700;color:#000;text-decoration:none}.views li:first-child{border-top-left-radius:5px;border-bottom-left-radius:5px}.views li:last-child{border-right:1px solid #ddd;border-top-right-radius:5px;border-bottom-right-radius:5px}.accordion-title{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAADCAYAAABS3WWCAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NEQ5RDgxQzc2RjQ5MTFFMjhEMUNENzFGRUMwRjhBRTciIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NEQ5RDgxQzg2RjQ5MTFFMjhEMUNENzFGRUMwRjhBRTciPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo0RDlEODFDNTZGNDkxMUUyOEQxQ0Q3MUZFQzBGOEFFNyIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo0RDlEODFDNjZGNDkxMUUyOEQxQ0Q3MUZFQzBGOEFFNyIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PvXFWFAAAAAYSURBVHjaYvj//z8D0/Pnz/8zgFgAAQYAS5UJscReGMIAAAAASUVORK5CYII=) 0 10px repeat-x}.accordion-title h3{display:inline;padding-right:5px;background:#fff}.accordion-content{margin-top:15px}.accordion-toggle{color:#333;text-decoration:none}.accordion-toggle:focus,.accordion-toggle:hover{color:#999}.accordion-toggle:before{content:"\f0d7"}.accordion-collapsed .accordion-toggle:before{content:"\f0da"}.accordion-collapsed .accordion-content{display:none}.avatar img{vertical-align:bottom}.avatar-left{float:left;margin-right:10px}.avatar-inline{display:inline-block;margin-right:3px}.avatar-48 div,.avatar-48 img{border-radius:30px}.avatar-48 .avatar-letter{line-height:48px;width:48px;font-size:25px}.avatar-20 div,.avatar-20 img{border-radius:10px}.avatar-20 .avatar-letter{line-height:20px;width:20px;font-size:11px}.avatar-letter{color:#fff} \ No newline at end of file +a:focus,a:hover,th a{text-decoration:none}h3,label{margin-top:10px}.tooltip-arrow.bottom:after,.tooltip-arrow.top{top:-10px}.form-errors,.ui-tooltip li,ul.no-bullet li{list-style-type:none}.table-fixed td,.table-fixed th,.tooltip-arrow,header h1{overflow:hidden}#board td,td{vertical-align:top}.table-fixed td,.task-board-collapsed,div.ganttview-vtheader-series-name,header h1{text-overflow:ellipsis;white-space:nowrap}blockquote,body,li,ol,p,table,td,th,tr,ul{margin:0;padding:0;font-size:100%}form,table{margin-bottom:20px}body{margin-left:10px;margin-right:10px;padding-bottom:10px;color:#333;font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;text-rendering:optimizeLegibility}.page{clear:both}ul.no-bullet li{margin-left:0}.pull-right{text-align:right}hr{border:0;height:0;border-top:1px solid rgba(0,0,0,.1);border-bottom:1px solid rgba(255,255,255,.3)}.chosen-select{min-height:27px}#ui-datepicker-div{font-size:.8em}#app-loading-icon{position:fixed;right:3px;bottom:3px}.web-notification-icon{color:#36C}.web-notification-icon:focus,.web-notification-icon:hover{color:#000}a:hover,h1,h2,h3,th a{color:#333}.smaller{font-size:.85em}a{color:#36C;border:none}a:focus{outline:0;color:#DF5353;border:1px dotted #aaa}h1,h2,h3{font-weight:400}h2{font-size:1.3em;margin-bottom:10px}h3{font-size:1.2em}table{width:100%;border-collapse:collapse;border-spacing:0;font-size:.95em}#calendar table{margin-bottom:0}td,th{border:1px solid #eee;padding:.5em 3px}th{background:#fbfbfb;text-align:left}td li{margin-left:20px}.table-small{font-size:.8em}th a:focus,th a:hover{text-decoration:underline}.page-header h2 a,a.btn,header a{text-decoration:none}.table-fixed{table-layout:fixed;white-space:nowrap}.table-stripped tr:nth-child(odd){background:#fefefe}.column-3{width:3%}.column-5{width:5%}.column-8{width:7.5%}.column-10{width:10%}.column-12{width:12%}.column-15{width:15%}.column-18{width:18%}.column-20{width:20%}.column-25{width:25%}.column-30{width:30%}.column-35{width:35%}.column-40{width:40%}.column-50{width:50%}.column-60{width:60%}.column-70,.column-80{width:70%}.draggable-row-handle{cursor:move;color:#dedede}.btn,.color-square,.draggable-item,.task-board-change-assignee,label{cursor:pointer}.draggable-row-handle:hover{color:#333}tr.draggable-item-selected{background:#fff;border:2px solid #666;box-shadow:4px 2px 10px -4px rgba(0,0,0,.55)}tr.draggable-item-selected td{border-top:none;border-bottom:none}tr.draggable-item-selected td:first-child{border-left:none}tr.draggable-item-selected td:last-child{border-right:none}.table-stripped tr.draggable-item-hover,tr.draggable-item-hover{background:#FEFFF2}label{display:block}input[type=number],input[type=date],input[type=email],input[type=password],input[type=text]{color:#888;border:1px solid #ccc;width:300px;max-width:95%;font-size:100%;height:25px;padding-bottom:0;font-family:sans-serif;margin-top:10px;-webkit-appearance:none;appearance:none}input[type=number]:focus,input[type=date]:focus,input[type=email]:focus,input[type=password]:focus,input[type=text]:focus,textarea:focus{color:#000;border-color:rgba(82,168,236,.8);outline:0;box-shadow:0 0 8px rgba(82,168,236,.6)}input.form-numeric,input[type=number]{width:70px}.tag-autocomplete,textarea{width:400px}textarea{border:1px solid #ccc;max-width:99%;height:200px;font-size:100%;font-family:sans-serif}select{max-width:95%}select:focus{outline:0}span.select2-container{margin-top:3px;margin-bottom:10px}::-webkit-input-placeholder{color:#ddd;padding-top:2px}::-ms-input-placeholder{color:#ddd;padding-top:2px}::-moz-placeholder{color:#ddd;padding-top:2px}.form-actions{padding-top:20px;clear:both}input.form-error,textarea.form-error{border:2px solid #b94a48}input.form-error:focus,textarea.form-error:focus{box-shadow:none;border:2px solid #b94a48}.form-required{color:red;padding-left:5px;font-weight:700}.form-errors{color:#b94a48}ul.form-errors li{margin-left:0}.form-help{font-size:.8em;color:brown;margin-bottom:15px}.form-inline{padding:0;margin:0;border:none}.form-inline label{display:inline}.form-inline input,.form-inline select{margin:0 15px 0 0}.form-inline .form-required{display:none}.form-inline-group{display:inline}input.form-date,input.form-datetime{width:150px}input.form-input-large{width:400px}.form-column{float:left;margin-right:3%;max-width:50%;min-width:40%}.form-column ul{margin-top:15px}.form-clear{clear:both;padding-top:20px;padding-bottom:10px}.form-login{width:350px;margin:8% auto 0}.form-login li{margin-left:25px;line-height:25px}.form-login h2{margin-bottom:30px;font-size:1.5em;font-weight:700}.popover-form{margin-bottom:0}.reset-password{margin-top:20px}.reset-password a{font-size:.8em;color:#999}.btn{font-size:1.1em;font-weight:400;-webkit-appearance:none;appearance:none;display:inline-block;color:#333;background:#f5f5f5;border:1px solid #ddd;border-radius:2px;padding:3px 10px;margin:0}.btn:hover{border:1px solid #bbb;color:#000;background:#fafafa}.btn-red{border-color:#b0281a;background:#d14836;color:#fff}.btn-red:focus,.btn-red:hover{color:#fff;background:#c53727}.btn-blue{border-color:#3079ed;background:#4d90fe;color:#fff}.btn-blue:focus,.btn-blue:hover{border-color:#2f5bb7;background:#357ae8;color:#fff}.btn:disabled{color:#ccc;border:1px solid #ccc;background:#f7f7f7}.buttons-header{font-size:.9em;margin-bottom:15px}.alert{padding:8px 35px 8px 14px;margin-top:5px;margin-bottom:5px;color:#c09853;background-color:#fcf8e3;border:1px solid #fbeed5;border-radius:4px}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-normal{color:#333;background-color:#f0f0f0;border-color:#ddd}.alert ul{margin-top:10px;margin-bottom:10px}.alert-fade-out,.ui-tooltip-content .markdown p{margin-bottom:0}.alert li{margin-left:25px}.alert-fade-out{text-align:center;position:fixed;bottom:0;left:20%;width:60%;padding-top:5px;padding-bottom:5px;border-width:1px 0 0;border-radius:4px 4px 0 0;z-index:9999}.tooltip-arrow.bottom,.tooltip-arrow.top:after{bottom:-10px}div.ui-tooltip{min-width:200px;max-width:600px;font-size:.85em}.tooltip-arrow{width:20px;height:10px;position:absolute}.tooltip-arrow.align-left{left:10px}.tooltip-arrow.align-right{right:10px}.tooltip-arrow:after{background:#fff;border:1px solid #aaa;box-shadow:0 0 5px #aaa;content:"";position:absolute;width:14px;height:14px;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg)}.tooltip-arrow.align-left:after{left:0}.tooltip-arrow.align-right:after{right:0}.tooltip-large{width:600px}.tooltip .fa-info-circle{color:#999;font-size:.95em}header{margin-top:10px;padding-bottom:10px;border-bottom:1px solid #dedede}header h1{margin:0;padding:0;max-width:70%;float:left}header ul{text-align:right;font-size:.9em}header li{display:inline;padding-left:30px}header a{color:#333}header a:hover{color:#666}nav .active a{color:#333;font-weight:700}.logo a{opacity:.5;color:#d40000}.logo span{color:#333}.logo a:hover{opacity:.8;color:#333}.logo a:focus span,.logo a:hover span{color:#d40000}header .user-links .dropdown{margin-left:15px}header h1 .tooltip{opacity:.3;font-size:.6em}.page-header{margin-bottom:20px}.page-header h2{margin:0;padding:0;font-size:1.4em;font-weight:700;border-bottom:1px dotted #ccc}.page-header h2 a{color:#333}.page-header h2 a:focus,.page-header h2 a:hover{color:#aaa}.page-header ul{text-align:left;margin-top:5px;display:inline-block}.menu-inline li,.page-header li{display:inline;padding-right:15px;font-size:.95em}.page-header li.active a{color:#333;text-decoration:none;font-weight:700}.page-header li.active a:focus,.page-header li.active a:hover{text-decoration:underline}.menu-inline{margin-bottom:5px}.public-board{margin-top:5px}.public-task{max-width:800px;margin:5px auto 0}#board-container{overflow-x:auto}#board{table-layout:fixed;margin-bottom:0}#board th.board-column-header{width:240px}.board-container-compact{overflow-x:initial}@media all and (-ms-high-contrast:active),(-ms-high-contrast:none){.board-container-compact #board{table-layout:auto}}#board th.board-column-header.board-column-compact{width:initial}.board-column-collapsed{display:none}td.board-column-task-collapsed{font-weight:700;background-color:#fbfbfb}#board th.board-column-header-collapsed{width:28px;min-width:28px;text-align:center;overflow:hidden}.board-rotation-wrapper{position:relative;padding:8px 4px;min-height:150px;overflow:hidden}.board-rotation{white-space:nowrap;-webkit-backface-visibility:hidden;-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg);-webkit-transform-origin:0 100%;-moz-transform-origin:0 100%;-ms-transform-origin:0 100%;transform-origin:0 100%}.board-column-title .dropdown-menu{text-decoration:none}.board-add-icon{float:left;padding:0 5px}.board-add-icon a{text-decoration:none;color:#36C;font-size:150%;line-height:70%}.board-add-icon a:focus,.board-add-icon a:hover{text-decoration:none;color:red}.board-column-header-task-count{color:#999;font-weight:400}th.board-column-header-collapsed .board-column-header-task-count{font-size:.85em}a.board-swimlane-toggle{font-size:.95em;text-decoration:none}a.board-swimlane-toggle:focus,a.board-swimlane-toggle:hover{color:#000;text-decoration:none;border:none}.board-task-list{overflow:auto;min-height:60px}.board-task-list-limit{background-color:#DF5353}.draggable-item{user-select:none;-webkit-user-select:none;-moz-user-select:none}.draggable-placeholder{border:2px dashed #000;background:#fafafa;height:70px;margin-bottom:10px}.task-board,div.draggable-item-selected{border:1px solid #000}.task-board-sort-handle{float:left;padding-right:5px}.task-table .dropdown-menu{color:#000;text-decoration:none;font-weight:700}.task-table .dropdown-menu:focus,.task-table .dropdown-menu:hover{text-decoration:underline}td.task-table a{color:#000;text-decoration:none}td.task-table a:hover{text-decoration:underline}.task-board{position:relative;margin-bottom:4px;padding:2px;font-size:.85em;word-wrap:break-word}div.task-board-recent{border-width:2px}div.task-board-status-closed{user-select:none;border:1px dotted #555}.task-board a{color:#000;text-decoration:none}.task-board .dropdown-menu{font-weight:700}.task-board-collapsed{overflow:hidden}.task-board-saving-state{opacity:.3}.task-board-category:hover,.task-board-change-assignee:hover{opacity:.6}.task-board-saving-icon{position:absolute;margin:auto;width:100%;text-align:center;color:#000}.task-board-title{font-size:1.15em;margin-top:5px;margin-bottom:8px}.task-board-title a:hover{text-decoration:underline}.task-board-category-container{text-align:right;margin-top:8px;margin-bottom:8px}.task-board-category{font-weight:500;color:#000;border:1px solid #555;padding:1px 2px;border-radius:4px}.task-tags li{display:inline;margin:0 4px 0 0;padding:2px;color:#666;border:1px solid #666;border-radius:2px}.task-summary-container .task-tags{margin-top:10px}.task-board-avatars{text-align:right;float:right}.file-thumbnail img:hover,.task-board-icons a{opacity:.5}.task-board-icons{text-align:right;margin-top:4px;margin-bottom:2px}.task-board-icons span{opacity:.5;margin-left:2px}.task-board-icons a:hover,.task-board-icons span:hover{opacity:1}.task-board-date{font-weight:700;color:#000}span.task-board-date-today{color:#0000D9;opacity:1}span.task-board-date-overdue{color:#D90000;opacity:1}.task-board .task-score{font-weight:700}.task-board-age{display:inline-block;font-size:.9em}.project-overview-columns,.task-summary-columns{display:-webkit-flex;-webkit-flex-direction:row}span.task-board-age-total{border:1px solid #666;padding:1px 3px;border-top-left-radius:3px;border-bottom-left-radius:3px}span.task-board-age-column{border:1px solid #666;border-left:none;margin-left:-5px;padding:1px 3px;border-top-right-radius:3px;border-bottom-right-radius:3px}#task-summary{margin-bottom:15px}#task-summary h2{color:#666;font-size:2.5em;margin-top:0;padding-top:0}.task-summary-buttons{margin-top:10px;font-size:.85em}.task-summary-container{border:2px solid #000;border-radius:8px;padding:15px}.task-summary-columns{display:flex;flex-direction:row;-webkit-justify-content:space-between;justify-content:space-between}.task-summary-column{font-size:.9em;color:#666}.task-summary-column span{color:#555}.task-summary-column li{line-height:23px}.task-show-title{border:2px solid #000;border-radius:8px;margin-bottom:20px}.task-show-title h2{color:#555;font-size:1.8em;margin:0;padding:8px}.comment-actions,.comment-content,.comment-title{margin-left:55px}.task-link-closed{text-decoration:line-through}.flag-milestone{color:green}.color-picker{min-height:35px}.color-square{display:inline-block;width:30px;height:30px;margin-right:5px;margin-bottom:5px;border:1px solid #000}.color-square:hover{border-style:dotted}div.color-square-selected{border-width:2px;width:28px;height:28px;box-shadow:3px 2px 10px 0 rgba(180,180,180,.9)}.textarea-dropdown,ul.dropdown-submenu-open{list-style:none;box-shadow:0 1px 3px rgba(0,0,0,.15)}.assign-me{font-size:.8em;vertical-align:bottom}.subtasks-table td,.task-links-table td{vertical-align:middle}.comment-sorting{text-align:right;font-size:.5em}.avatar-letter,.pagination,.project-overview-column,div.ganttview-hzheader-day,div.ganttview-hzheader-month{text-align:center}.comment-sorting a{color:#555;font-weight:400;text-decoration:none}.comment-sorting a:hover{color:#aaa}.comment{padding:5px;margin-bottom:15px}.comment-title,.form-column div.CodeMirror,.markdown blockquote,.markdown h1,.markdown p{margin-bottom:10px}.comment:hover{background:#fafafa}.comment-title{border-bottom:1px dotted #eee}.comment-username{font-weight:700;font-size:1.1em}.comment-date{color:#999;font-size:.7em;font-weight:200}.comment-actions{font-size:.8em;margin-top:8px}.subtasks-table,.task-links-table{font-size:.85em}.comment-actions li{display:inline}.comment-actions a{color:#999;text-decoration:none}.markdown h1,.markdown h2,.markdown h3,.markdown h4{text-decoration:underline}.comment-actions a:focus,.comment-actions a:hover{color:#333;text-decoration:underline}.task-links-task-count{color:#999}div.CodeMirror,div.CodeMirror-scroll{max-height:250px;min-height:200px}.markdown-editor-small div.CodeMirror,.markdown-editor-small div.CodeMirror-scroll{min-height:100px;max-height:180px}.markdown{line-height:1.4em}.markdown h1{margin-top:5px;font-size:1.5em;font-weight:700}.markdown h2{font-size:1.2em;font-weight:700}.markdown h3,.markdown h4{font-size:1.1em}.markdown ol,.markdown ul{margin-left:25px;margin-top:10px;margin-bottom:10px}.markdown pre{background:#fbfbfb;padding:10px;border-radius:5px;border:1px solid #ddd;overflow:auto;color:#444}.markdown blockquote{font-style:italic;border-left:3px solid #ddd;padding-left:10px;margin-left:20px}.markdown img{display:block;max-width:80%;margin-top:10px}.documentation{margin:0 auto;padding:20px;max-width:850px;background:#fefefe;border:1px solid #ccc;border-radius:5px;font-size:1.1em;color:#555}.documentation img{border:1px solid #333}.documentation h1{text-decoration:none;font-size:1.8em;margin-bottom:30px}.documentation h2{font-size:1.3em;text-decoration:none;border-bottom:1px solid #ccc;margin-bottom:25px}.documentation li{line-height:30px}.user-mention-link{font-weight:700;color:#000;text-decoration:none}.user-mention-link:hover{color:#555}.listing{border-radius:4px;padding:8px 35px 8px 14px;margin-bottom:20px;border:1px solid #ddd;color:#333;background-color:#fcfcfc;overflow:auto}.activity-title,.sidebar>ul li{border-bottom:1px dotted #efefef}.listing li{list-style-type:square;margin-left:20px;margin-bottom:3px}.activity-event,.listing ul,.sidebar>ul li:last-child{margin-bottom:15px}.listing ul{margin-top:15px}.activity-event{padding:10px}.activity-event:hover{background:#fafafa}.activity-date{margin-left:10px;font-weight:400;color:#999;font-size:.8em}.activity-content{margin-left:55px}.activity-title{font-weight:700;color:#000}.activity-description{font-size:.95em;color:#555;margin-top:10px}.activity-description li{list-style-type:circle}.activity-description ul{margin-top:10px;margin-left:20px}.dashboard-project-stats span{font-size:.75em;margin-right:10px;color:#999}.dashboard-project-stats strong{font-size:1.2em}.dashboard-table-link{font-weight:700;color:#444;text-decoration:none}.dashboard-table-link:focus,.dashboard-table-link:hover{color:#999}.pagination-next{margin-left:5px}.pagination-previous{margin-right:5px}#popover-container{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,.8);overflow:auto;z-index:100}#popover-content{position:absolute;width:70%;left:15%;top:1%;padding:15px;background:#fff;overflow:auto;max-height:90%}#main .confirm{max-width:700px;font-size:1.1em}.sidebar-container{margin-top:10px;height:100%;width:100%;display:-ms-flexbox;display:-webkit-box;display:-moz-box;display:-ms-box;display:box;-ms-flex-direction:row;-webkit-box-orient:horizontal;-moz-box-orient:horizontal;-ms-box-orient:horizontal;box-orient:horizontal}.sidebar-content{padding-left:10px;-ms-flex:1;-webkit-box-flex:1;-moz-box-flex:1;-ms-box-flex:1;box-flex:1}.sidebar{padding-right:10px;border-right:1px dotted #eee;font-size:.95em;max-width:240px;min-width:190px;width:18%;-ms-flex:0 100px;-webkit-box-flex:0;-moz-box-flex:0;-ms-box-flex:0;box-flex:0}.sidebar h2{margin-top:0}.sidebar>ul a{text-decoration:none;color:#999;font-weight:300}.sidebar>ul a:hover{color:#333}.sidebar>ul li{list-style-type:none;line-height:35px;padding-left:13px}.sidebar>ul li:hover{border-left:5px solid #555;padding-left:8px}.sidebar>ul li.active{border-left:5px solid #333;padding-left:8px}.sidebar>ul li.active a{color:#333;font-weight:700}.sidebar-icons>ul li{padding-left:0}.sidebar-icons>ul li.active,.sidebar-icons>ul li:hover{padding-left:0;border-left:none}.sidebar>ul li.active a:focus,.sidebar>ul li.active a:hover{color:#555}@media only screen and (max-width:1024px){body{font-size:.85em}.form-tab{max-width:404px}.form-inline-group input[type=submit],.form-inline-group label{display:block}.form-inline-group input[type=submit]{margin-top:20px}td>input[type=text]{max-width:150px}.page-header .form-input-large{width:300px}}@media only screen and (max-width:1024px) and (orientation:landscape){header{padding-bottom:4px}div.chosen-container{font-size:.9em}input[type=number],input[type=date],input[type=email],input[type=password],input[type=text]{height:18px}.page-header .form-input-large{width:300px}}@media only screen and (max-width:640px){.hide-mobile{display:none}}.dropdown{display:inline;position:relative}.dropdown ul{display:none}ul.dropdown-submenu-open{display:block;position:absolute;z-index:1000;min-width:285px;margin:3px 0 0 1px;padding:6px 0;background-color:#fff;border:1px solid #b2b2b2;border-radius:3px}.dropdown-submenu-open li,.textarea-dropdown li{display:block;margin:0;padding:8px 10px;font-size:.85em;border-bottom:1px solid #f8f8f8;cursor:pointer}.dropdown-submenu-open li.no-hover{cursor:default}.dropdown-submenu-open li:last-child,.textarea-dropdown li:last-child{border:none}.dropdown-submenu-open li:not(.no-hover):hover,.textarea-dropdown .active,.textarea-dropdown li:hover{background:#4078C0;color:#fff}.dropdown-submenu-open li:hover a,.textarea-dropdown .active a,.textarea-dropdown li:hover a{color:#fff}.dropdown-submenu-open a,.textarea-dropdown a{text-decoration:none;color:#333}.dropdown-submenu-open a:focus{text-decoration:underline}.page-header .dropdown{padding-right:10px}.dropdown-menu-link-icon,.dropdown-menu-link-text{color:#333;text-decoration:none}.dropdown-menu-link-text:hover{text-decoration:underline}.textarea-dropdown{margin:3px 0 0 1px;padding:6px 0;background-color:#fff;border:1px solid #b2b2b2;border-radius:3px}#file-dropzone,#screenshot-zone{position:relative;border:2px dashed #ccc;width:99%;height:250px;overflow:auto}#file-dropzone-inner,#screenshot-inner{position:absolute;left:0;bottom:48%;width:100%;text-align:center;color:#aaa}#screenshot-zone.screenshot-pasted{border:2px solid #333}#file-list{margin:20px}#file-list li{list-style-type:none;padding-top:8px;padding-bottom:8px;border-bottom:1px dotted #ddd;width:95%}#file-list li.file-error{font-weight:700;color:#b94a48}.project-header{margin-top:8px;margin-bottom:20px}.action-menu{color:#333;text-decoration:none}.action-menu:focus,.action-menu:hover{text-decoration:underline}.filter-box{display:inline-block;position:relative;font-size:0;margin-bottom:20px}.filter-box form,.project-header .filter-box{margin:0}.filter-box input[type=text]{margin:0;font-size:16px;height:26px;border-color:#ddd;border-top-left-radius:5px;border-bottom-left-radius:5px;vertical-align:top}.filter-box input[type=text]:focus{color:#000;border-color:rgba(82,168,236,.8);outline:0;box-shadow:0 0 8px rgba(82,168,236,.6)}.filter-box div.dropdown{background:#fafafa;display:inline-block;font-size:16px;border:1px solid #ddd;border-left:none;margin:0;padding:0 8px 0 5px;height:27px}.filter-box div.dropdown:last-child{border-top-right-radius:5px;border-bottom-right-radius:5px}.filter-box div.dropdown a{line-height:27px}div.ganttview-grid,div.ganttview-grid-row-cell,div.ganttview-hzheader-day,div.ganttview-hzheader-month,div.ganttview-vtheader,div.ganttview-vtheader-item-name,div.ganttview-vtheader-series{float:left}div.ganttview-grid-row-cell.last,div.ganttview-hzheader-day.last,div.ganttview-hzheader-month.last{border-right:none}div.ganttview{border:1px solid #999}div.ganttview-hzheader-month{width:60px;height:20px;border-right:1px solid #d0d0d0;line-height:20px;overflow:hidden}div.ganttview-hzheader-day{width:20px;height:20px;border-right:1px solid #f0f0f0;border-top:1px solid #d0d0d0;line-height:20px;color:#777}div.ganttview-vtheader{margin-top:41px;width:400px;overflow:hidden;background-color:#fff}div.ganttview-vtheader-item{color:#666}div.ganttview-vtheader-series-name{width:400px;height:31px;line-height:31px;padding-left:3px;border-top:1px solid #d0d0d0;font-size:.9em;overflow:hidden}div.ganttview-vtheader-series-name a{color:#666;text-decoration:none}div.ganttview-vtheader-series-name a:hover{color:#333;text-decoration:underline}div.ganttview-vtheader-series-name a i{color:#000}div.ganttview-vtheader-series-name a:hover i{color:#666}div.ganttview-slide-container{overflow:auto;border-left:1px solid #999}div.ganttview-grid-row-cell{width:20px;height:31px;border-right:1px solid #f0f0f0;border-top:1px solid #f0f0f0}div.ganttview-grid-row-cell.ganttview-weekend{background-color:#fafafa}div.ganttview-blocks{margin-top:40px}div.ganttview-block-container{height:28px;padding-top:4px}div.ganttview-block{position:relative;height:25px;background-color:#E5ECF9;border:1px solid silver;border-radius:3px}.ganttview-block-movable{cursor:move}div.ganttview-block-not-defined{border-color:#000;background-color:#000}div.ganttview-block-text{position:absolute;height:12px;font-size:.7em;color:#999;padding:2px 3px}div.ganttview-block div.ui-resizable-handle.ui-resizable-s{bottom:0}.project-creation-options{max-width:500px;border-left:3px dotted #efefef;margin-top:20px;padding-left:15px;padding-bottom:5px;padding-top:5px}.project-overview-columns{display:flex;flex-direction:row;-webkit-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;align-items:center;-webkit-justify-content:center;justify-content:center;margin-bottom:20px;font-size:1.4em}.project-overview-column{margin-right:80px;padding:3px 15px;border:1px dashed #ddd;border-radius:8px}.project-overview-column strong{font-size:1.3em;color:#444}.project-overview-column span{font-size:.8em;color:#777}.file-thumbnails{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;flex-wrap:wrap;-webkit-justify-content:flex-start;justify-content:flex-start}.file-thumbnail{width:250px;border:1px solid #efefef;border-radius:5px;margin-bottom:20px;box-shadow:4px 2px 10px -6px rgba(0,0,0,.55);margin-right:15px}.file-thumbnail img{border-top-left-radius:5px;border-top-right-radius:5px}.file-thumbnail-content{padding-left:8px;padding-right:8px}.file-thumbnail-title{font-weight:700;font-size:.9em;color:#555}.file-thumbnail-description{font-size:.8em;color:#aaa;margin-top:8px;margin-bottom:5px}.accordion-collapsed,.accordion-content{margin-bottom:25px}.file-viewer{position:relative}.file-viewer img{max-width:95%;max-height:85%;margin-top:10px}.views{display:inline-block;margin-left:10px;margin-right:10px;font-size:.9em}.views li{background:#fafafa;border-left:1px solid #ddd;border-top:1px solid #ddd;border-bottom:1px solid #ddd;display:inline;padding:5px 8px}.views a{color:#555;text-decoration:none}.views a:hover{color:#333;text-decoration:underline}.menu-inline li.active a,.views li.active a{font-weight:700;color:#000;text-decoration:none}.views li:first-child{border-top-left-radius:5px;border-bottom-left-radius:5px}.views li:last-child{border-right:1px solid #ddd;border-top-right-radius:5px;border-bottom-right-radius:5px}.accordion-title{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAADCAYAAABS3WWCAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NEQ5RDgxQzc2RjQ5MTFFMjhEMUNENzFGRUMwRjhBRTciIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NEQ5RDgxQzg2RjQ5MTFFMjhEMUNENzFGRUMwRjhBRTciPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo0RDlEODFDNTZGNDkxMUUyOEQxQ0Q3MUZFQzBGOEFFNyIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo0RDlEODFDNjZGNDkxMUUyOEQxQ0Q3MUZFQzBGOEFFNyIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PvXFWFAAAAAYSURBVHjaYvj//z8D0/Pnz/8zgFgAAQYAS5UJscReGMIAAAAASUVORK5CYII=) 0 10px repeat-x}.accordion-title h3{display:inline;padding-right:5px;background:#fff}.accordion-content{margin-top:15px}.accordion-toggle{color:#333;text-decoration:none}.accordion-toggle:focus,.accordion-toggle:hover{color:#999}.accordion-toggle:before{content:"\f0d7"}.accordion-collapsed .accordion-toggle:before{content:"\f0da"}.accordion-collapsed .accordion-content{display:none}.avatar img{vertical-align:bottom}.avatar-left{float:left;margin-right:10px}.avatar-inline{display:inline-block;margin-right:3px}.avatar-48 div,.avatar-48 img{border-radius:30px}.avatar-48 .avatar-letter{line-height:48px;width:48px;font-size:25px}.avatar-20 div,.avatar-20 img{border-radius:10px}.avatar-20 .avatar-letter{line-height:20px;width:20px;font-size:11px}.avatar-letter{color:#fff} \ No newline at end of file diff --git a/assets/css/print.min.css b/assets/css/print.min.css index 5041beb8..a5b4407e 100644 --- a/assets/css/print.min.css +++ b/assets/css/print.min.css @@ -1 +1 @@ -a:hover,th a{text-decoration:none;color:#333}.table-fixed td,.table-fixed th{overflow:hidden}#board td,td{vertical-align:top}#comments form,.board-column-collapsed,.page-header,.sidebar,header{display:none}.table-fixed td,.task-board-collapsed{white-space:nowrap;text-overflow:ellipsis}a{color:#36C;border:none}a:focus{outline:0;color:#DF5353;text-decoration:none;border:1px dotted #aaa}table{width:100%;border-collapse:collapse;border-spacing:0;margin-bottom:20px;font-size:.95em}#calendar table{margin-bottom:0}td,th{border:1px solid #eee;padding:.5em 3px}th{background:#fbfbfb;text-align:left}td li{margin-left:20px}.table-small{font-size:.8em}th a:focus,th a:hover{text-decoration:underline}.table-fixed{table-layout:fixed;white-space:nowrap}.table-stripped tr:nth-child(odd){background:#fefefe}.column-3{width:3%}.column-5{width:5%}.column-8{width:7.5%}.column-10{width:10%}.column-12{width:12%}.column-15{width:15%}.column-18{width:18%}.column-20{width:20%}.column-25{width:25%}.column-30{width:30%}.column-35{width:35%}.column-40{width:40%}.column-50{width:50%}.column-60{width:60%}.column-70,.column-80{width:70%}.draggable-row-handle{cursor:move;color:#dedede}.color-square,.task-board-change-assignee{cursor:pointer}.draggable-row-handle:hover{color:#333}tr.draggable-item-selected{background:#fff;border:2px solid #666;box-shadow:4px 2px 10px -4px rgba(0,0,0,.55)}tr.draggable-item-selected td{border-top:none;border-bottom:none}tr.draggable-item-selected td:first-child{border-left:none}tr.draggable-item-selected td:last-child{border-right:none}.table-stripped tr.draggable-item-hover,tr.draggable-item-hover{background:#FEFFF2}.public-board{margin-top:5px}.public-task{max-width:800px;margin:5px auto 0}#board-container{overflow-x:auto}#board{table-layout:fixed;margin-bottom:0}#board th.board-column-header{width:240px}.board-container-compact{overflow-x:initial}@media all and (-ms-high-contrast:active),(-ms-high-contrast:none){.board-container-compact #board{table-layout:auto}}#board th.board-column-header.board-column-compact{width:initial}td.board-column-task-collapsed{font-weight:700;background-color:#fbfbfb}#board th.board-column-header-collapsed{width:28px;min-width:28px;text-align:center;overflow:hidden}.board-rotation-wrapper{position:relative;padding:8px 4px;min-height:150px;overflow:hidden}.board-rotation{white-space:nowrap;-webkit-backface-visibility:hidden;-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg);-webkit-transform-origin:0 100%;-moz-transform-origin:0 100%;-ms-transform-origin:0 100%;transform-origin:0 100%}.board-column-title .dropdown-menu{text-decoration:none}.board-add-icon{float:left;padding:0 5px}.board-add-icon a{text-decoration:none;color:#36C;font-size:150%;line-height:70%}.board-add-icon a:focus,.board-add-icon a:hover{text-decoration:none;color:red}.board-column-header-task-count{color:#999;font-weight:400}th.board-column-header-collapsed .board-column-header-task-count{font-size:.85em}a.board-swimlane-toggle{font-size:.95em;text-decoration:none}a.board-swimlane-toggle:focus,a.board-swimlane-toggle:hover{color:#000;text-decoration:none;border:none}.board-task-list{overflow:auto;min-height:60px}.board-task-list-limit{background-color:#DF5353}.draggable-item{cursor:pointer;user-select:none;-webkit-user-select:none;-moz-user-select:none}.draggable-placeholder{border:2px dashed #000;background:#fafafa;height:70px;margin-bottom:10px}.task-board,div.draggable-item-selected{border:1px solid #000}.task-board-sort-handle{float:left;padding-right:5px}.task-board-saving-state{opacity:.3}.task-board-category:hover,.task-board-change-assignee:hover{opacity:.6}.task-board-saving-icon{position:absolute;margin:auto;width:100%;text-align:center;color:#000}.task-table .dropdown-menu{color:#000;text-decoration:none;font-weight:700}.task-table .dropdown-menu:focus,.task-table .dropdown-menu:hover{text-decoration:underline}td.task-table a{color:#000;text-decoration:none}td.task-table a:hover{text-decoration:underline}.task-board{position:relative;margin-bottom:4px;padding:2px;font-size:.85em;word-wrap:break-word}div.task-board-recent{border-width:2px}div.task-board-status-closed{user-select:none;border:1px dotted #555}.task-board a{color:#000;text-decoration:none}.task-board .dropdown-menu{font-weight:700}.task-board-collapsed{overflow:hidden}.task-board-title{font-size:1.15em;margin-top:5px;margin-bottom:8px}.task-board-title a:hover{text-decoration:underline}.task-board-category-container{text-align:right;margin-top:8px;margin-bottom:8px}.task-board-category{font-weight:500;color:#000;border:1px solid #555;padding:1px 2px;border-radius:4px}.task-board-avatars{text-align:right;float:right}.task-board-icons{text-align:right;margin-top:4px;margin-bottom:2px}.task-board-icons a{opacity:.5}.task-board-icons span{opacity:.5;margin-left:2px}.task-board-icons a:hover,.task-board-icons span:hover{opacity:1}.task-board-date{font-weight:700;color:#000}span.task-board-date-today{color:#0000D9;opacity:1}span.task-board-date-overdue{color:#D90000;opacity:1}.task-board .task-score{font-weight:700}.task-board-age{display:inline-block;font-size:.9em}span.task-board-age-total{border:1px solid #666;padding:1px 3px;border-top-left-radius:3px;border-bottom-left-radius:3px}span.task-board-age-column{border:1px solid #666;border-left:none;margin-left:-5px;padding:1px 3px;border-top-right-radius:3px;border-bottom-right-radius:3px}#task-summary{margin-bottom:15px}#task-summary h2{color:#666;font-size:2.5em;margin-top:0;padding-top:0}.task-summary-buttons{margin-top:10px;font-size:.85em}.task-summary-container{border:2px solid #000;border-radius:8px;padding:15px;display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-justify-content:space-between;justify-content:space-between}.task-summary-column{font-size:.9em;color:#666}.task-summary-column span{color:#555}.task-summary-column li{line-height:23px}.task-show-title{border:2px solid #000;border-radius:8px;margin-bottom:20px}.task-show-title h2{color:#555;font-size:1.8em;margin:0;padding:8px}.comment-actions,.comment-content,.comment-title{margin-left:55px}.task-link-closed{text-decoration:line-through}.flag-milestone{color:green}.color-picker{min-height:35px}.color-square{display:inline-block;width:30px;height:30px;margin-right:5px;margin-bottom:5px;border:1px solid #000}.color-square:hover{border-style:dotted}div.color-square-selected{border-width:2px;width:28px;height:28px;box-shadow:3px 2px 10px 0 rgba(180,180,180,.9)}.assign-me{font-size:.8em;vertical-align:bottom}.subtasks-table td,.task-links-table td{vertical-align:middle}.comment-sorting{text-align:right;font-size:.5em}.comment-sorting a{color:#555;font-weight:400;text-decoration:none}.comment-sorting a:hover{color:#aaa}.comment{padding:5px;margin-bottom:15px}.comment-title,.form-column div.CodeMirror,.markdown blockquote,.markdown h1,.markdown p{margin-bottom:10px}.comment:hover{background:#fafafa}.comment-title{border-bottom:1px dotted #eee}.comment-username{font-weight:700;font-size:1.1em}.comment-date{color:#999;font-size:.7em;font-weight:200}.comment-actions{font-size:.8em;margin-top:8px}.subtasks-table,.task-links-table{font-size:.85em}.comment-actions li{display:inline}.comment-actions a{color:#999;text-decoration:none}.markdown h1,.markdown h2,.markdown h3,.markdown h4{text-decoration:underline}.comment-actions a:focus,.comment-actions a:hover{color:#333;text-decoration:underline}.task-links-task-count{color:#999}div.CodeMirror,div.CodeMirror-scroll{max-height:250px;min-height:200px}.markdown-editor-small div.CodeMirror,.markdown-editor-small div.CodeMirror-scroll{min-height:100px;max-height:180px}.markdown{line-height:1.4em}.markdown h1{margin-top:5px;font-size:1.5em;font-weight:700}.markdown h2{font-size:1.2em;font-weight:700}.markdown h3,.markdown h4{font-size:1.1em}.markdown ol,.markdown ul{margin-left:25px;margin-top:10px;margin-bottom:10px}.markdown pre{background:#fbfbfb;padding:10px;border-radius:5px;border:1px solid #ddd;overflow:auto;color:#444}.markdown blockquote{font-style:italic;border-left:3px solid #ddd;padding-left:10px;margin-left:20px}.markdown img{display:block;max-width:80%;margin-top:10px}.documentation{margin:0 auto;padding:20px;max-width:850px;background:#fefefe;border:1px solid #ccc;border-radius:5px;font-size:1.1em;color:#555}.documentation img{border:1px solid #333}.documentation h1{text-decoration:none;font-size:1.8em;margin-bottom:30px}.documentation h2{font-size:1.3em;text-decoration:none;border-bottom:1px solid #ccc;margin-bottom:25px}.documentation li{line-height:30px}.user-mention-link{font-weight:700;color:#000;text-decoration:none}.user-mention-link:hover{color:#555} \ No newline at end of file +a:hover,th a{text-decoration:none;color:#333}.table-fixed td,.table-fixed th{overflow:hidden}#board td,td{vertical-align:top}#comments form,.board-column-collapsed,.page-header,.sidebar,header{display:none}.table-fixed td,.task-board-collapsed{white-space:nowrap;text-overflow:ellipsis}a{color:#36C;border:none}a:focus{outline:0;color:#DF5353;text-decoration:none;border:1px dotted #aaa}table{width:100%;border-collapse:collapse;border-spacing:0;margin-bottom:20px;font-size:.95em}#calendar table{margin-bottom:0}td,th{border:1px solid #eee;padding:.5em 3px}th{background:#fbfbfb;text-align:left}td li{margin-left:20px}.table-small{font-size:.8em}th a:focus,th a:hover{text-decoration:underline}.table-fixed{table-layout:fixed;white-space:nowrap}.table-stripped tr:nth-child(odd){background:#fefefe}.column-3{width:3%}.column-5{width:5%}.column-8{width:7.5%}.column-10{width:10%}.column-12{width:12%}.column-15{width:15%}.column-18{width:18%}.column-20{width:20%}.column-25{width:25%}.column-30{width:30%}.column-35{width:35%}.column-40{width:40%}.column-50{width:50%}.column-60{width:60%}.column-70,.column-80{width:70%}.draggable-row-handle{cursor:move;color:#dedede}.color-square,.task-board-change-assignee{cursor:pointer}.draggable-row-handle:hover{color:#333}tr.draggable-item-selected{background:#fff;border:2px solid #666;box-shadow:4px 2px 10px -4px rgba(0,0,0,.55)}tr.draggable-item-selected td{border-top:none;border-bottom:none}tr.draggable-item-selected td:first-child{border-left:none}tr.draggable-item-selected td:last-child{border-right:none}.table-stripped tr.draggable-item-hover,tr.draggable-item-hover{background:#FEFFF2}.public-board{margin-top:5px}.public-task{max-width:800px;margin:5px auto 0}#board-container{overflow-x:auto}#board{table-layout:fixed;margin-bottom:0}#board th.board-column-header{width:240px}.board-container-compact{overflow-x:initial}@media all and (-ms-high-contrast:active),(-ms-high-contrast:none){.board-container-compact #board{table-layout:auto}}#board th.board-column-header.board-column-compact{width:initial}td.board-column-task-collapsed{font-weight:700;background-color:#fbfbfb}#board th.board-column-header-collapsed{width:28px;min-width:28px;text-align:center;overflow:hidden}.board-rotation-wrapper{position:relative;padding:8px 4px;min-height:150px;overflow:hidden}.board-rotation{white-space:nowrap;-webkit-backface-visibility:hidden;-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg);-webkit-transform-origin:0 100%;-moz-transform-origin:0 100%;-ms-transform-origin:0 100%;transform-origin:0 100%}.board-column-title .dropdown-menu{text-decoration:none}.board-add-icon{float:left;padding:0 5px}.board-add-icon a{text-decoration:none;color:#36C;font-size:150%;line-height:70%}.board-add-icon a:focus,.board-add-icon a:hover{text-decoration:none;color:red}.board-column-header-task-count{color:#999;font-weight:400}th.board-column-header-collapsed .board-column-header-task-count{font-size:.85em}a.board-swimlane-toggle{font-size:.95em;text-decoration:none}a.board-swimlane-toggle:focus,a.board-swimlane-toggle:hover{color:#000;text-decoration:none;border:none}.board-task-list{overflow:auto;min-height:60px}.board-task-list-limit{background-color:#DF5353}.draggable-item{cursor:pointer;user-select:none;-webkit-user-select:none;-moz-user-select:none}.draggable-placeholder{border:2px dashed #000;background:#fafafa;height:70px;margin-bottom:10px}.task-board,div.draggable-item-selected{border:1px solid #000}.task-board-sort-handle{float:left;padding-right:5px}.task-table .dropdown-menu{color:#000;text-decoration:none;font-weight:700}.task-table .dropdown-menu:focus,.task-table .dropdown-menu:hover{text-decoration:underline}td.task-table a{color:#000;text-decoration:none}td.task-table a:hover{text-decoration:underline}.task-board{position:relative;margin-bottom:4px;padding:2px;font-size:.85em;word-wrap:break-word}div.task-board-recent{border-width:2px}div.task-board-status-closed{user-select:none;border:1px dotted #555}.task-board a{color:#000;text-decoration:none}.task-board .dropdown-menu{font-weight:700}.task-board-collapsed{overflow:hidden}.task-board-saving-state{opacity:.3}.task-board-category:hover,.task-board-change-assignee:hover{opacity:.6}.task-board-saving-icon{position:absolute;margin:auto;width:100%;text-align:center;color:#000}.task-board-title{font-size:1.15em;margin-top:5px;margin-bottom:8px}.task-board-title a:hover{text-decoration:underline}.task-board-category-container{text-align:right;margin-top:8px;margin-bottom:8px}.task-board-category{font-weight:500;color:#000;border:1px solid #555;padding:1px 2px;border-radius:4px}.task-tags li{display:inline;margin:0 4px 0 0;padding:2px;color:#666;border:1px solid #666;border-radius:2px}.task-summary-container .task-tags{margin-top:10px}.task-board-avatars{text-align:right;float:right}.task-board-icons{text-align:right;margin-top:4px;margin-bottom:2px}.task-board-icons a{opacity:.5}.task-board-icons span{opacity:.5;margin-left:2px}.task-board-icons a:hover,.task-board-icons span:hover{opacity:1}.task-board-date{font-weight:700;color:#000}span.task-board-date-today{color:#0000D9;opacity:1}span.task-board-date-overdue{color:#D90000;opacity:1}.task-board .task-score{font-weight:700}.task-board-age{display:inline-block;font-size:.9em}span.task-board-age-total{border:1px solid #666;padding:1px 3px;border-top-left-radius:3px;border-bottom-left-radius:3px}span.task-board-age-column{border:1px solid #666;border-left:none;margin-left:-5px;padding:1px 3px;border-top-right-radius:3px;border-bottom-right-radius:3px}#task-summary{margin-bottom:15px}#task-summary h2{color:#666;font-size:2.5em;margin-top:0;padding-top:0}.task-summary-buttons{margin-top:10px;font-size:.85em}.task-summary-container{border:2px solid #000;border-radius:8px;padding:15px}.task-summary-columns{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-justify-content:space-between;justify-content:space-between}.task-summary-column{font-size:.9em;color:#666}.task-summary-column span{color:#555}.task-summary-column li{line-height:23px}.task-show-title{border:2px solid #000;border-radius:8px;margin-bottom:20px}.task-show-title h2{color:#555;font-size:1.8em;margin:0;padding:8px}.comment-actions,.comment-content,.comment-title{margin-left:55px}.task-link-closed{text-decoration:line-through}.flag-milestone{color:green}.color-picker{min-height:35px}.color-square{display:inline-block;width:30px;height:30px;margin-right:5px;margin-bottom:5px;border:1px solid #000}.color-square:hover{border-style:dotted}div.color-square-selected{border-width:2px;width:28px;height:28px;box-shadow:3px 2px 10px 0 rgba(180,180,180,.9)}.assign-me{font-size:.8em;vertical-align:bottom}.subtasks-table td,.task-links-table td{vertical-align:middle}.comment-sorting{text-align:right;font-size:.5em}.comment-sorting a{color:#555;font-weight:400;text-decoration:none}.comment-sorting a:hover{color:#aaa}.comment{padding:5px;margin-bottom:15px}.comment-title,.form-column div.CodeMirror,.markdown blockquote,.markdown h1,.markdown p{margin-bottom:10px}.comment:hover{background:#fafafa}.comment-title{border-bottom:1px dotted #eee}.comment-username{font-weight:700;font-size:1.1em}.comment-date{color:#999;font-size:.7em;font-weight:200}.comment-actions{font-size:.8em;margin-top:8px}.subtasks-table,.task-links-table{font-size:.85em}.comment-actions li{display:inline}.comment-actions a{color:#999;text-decoration:none}.markdown h1,.markdown h2,.markdown h3,.markdown h4{text-decoration:underline}.comment-actions a:focus,.comment-actions a:hover{color:#333;text-decoration:underline}.task-links-task-count{color:#999}div.CodeMirror,div.CodeMirror-scroll{max-height:250px;min-height:200px}.markdown-editor-small div.CodeMirror,.markdown-editor-small div.CodeMirror-scroll{min-height:100px;max-height:180px}.markdown{line-height:1.4em}.markdown h1{margin-top:5px;font-size:1.5em;font-weight:700}.markdown h2{font-size:1.2em;font-weight:700}.markdown h3,.markdown h4{font-size:1.1em}.markdown ol,.markdown ul{margin-left:25px;margin-top:10px;margin-bottom:10px}.markdown pre{background:#fbfbfb;padding:10px;border-radius:5px;border:1px solid #ddd;overflow:auto;color:#444}.markdown blockquote{font-style:italic;border-left:3px solid #ddd;padding-left:10px;margin-left:20px}.markdown img{display:block;max-width:80%;margin-top:10px}.documentation{margin:0 auto;padding:20px;max-width:850px;background:#fefefe;border:1px solid #ccc;border-radius:5px;font-size:1.1em;color:#555}.documentation img{border:1px solid #333}.documentation h1{text-decoration:none;font-size:1.8em;margin-bottom:30px}.documentation h2{font-size:1.3em;text-decoration:none;border-bottom:1px solid #ccc;margin-bottom:25px}.documentation li{line-height:30px}.user-mention-link{font-weight:700;color:#000;text-decoration:none}.user-mention-link:hover{color:#555} \ No newline at end of file diff --git a/assets/css/src/board.css b/assets/css/src/board.css index 586093b8..95e04108 100644 --- a/assets/css/src/board.css +++ b/assets/css/src/board.css @@ -157,16 +157,3 @@ div.draggable-item-selected { float: left; padding-right: 5px; } - -/* board saving state */ -.task-board-saving-state { - opacity: 0.3; -} - -.task-board-saving-icon { - position: absolute; - margin: auto; - width: 100%; - text-align: center; - color: #000; -} diff --git a/assets/css/src/form.css b/assets/css/src/form.css index fd778c88..27c19835 100644 --- a/assets/css/src/form.css +++ b/assets/css/src/form.css @@ -61,6 +61,15 @@ select:focus { outline: 0; } +.tag-autocomplete { + width: 400px; +} + +span.select2-container { + margin-top: 3px; + margin-bottom: 10px; +} + ::-webkit-input-placeholder { color: #ddd; padding-top: 2px; @@ -169,7 +178,6 @@ input.form-input-large { margin-top: 8%; } -.form-column li, .form-login li { margin-left: 25px; line-height: 25px; diff --git a/assets/css/src/task.css b/assets/css/src/task.css index 2a5f1e97..c134809c 100644 --- a/assets/css/src/task.css +++ b/assets/css/src/task.css @@ -53,6 +53,19 @@ div.task-board-status-closed { text-overflow: ellipsis; } +/* board saving state */ +.task-board-saving-state { + opacity: 0.3; +} + +.task-board-saving-icon { + position: absolute; + margin: auto; + width: 100%; + text-align: center; + color: #000; +} + /* title one the card */ .task-board-title { font-size: 1.15em; @@ -83,6 +96,21 @@ div.task-board-status-closed { opacity: 0.6; } +/* tags list */ +.task-tags li { + display: inline; + margin: 0; + margin-right: 4px; + padding: 2px; + color: #666; + border: 1px solid #666; + border-radius: 2px; +} + +.task-summary-container .task-tags { + margin-top: 10px; +} + /* avatars on the card */ .task-board-avatars { text-align: right; @@ -181,6 +209,9 @@ span.task-board-age-column { border: 2px solid #000; border-radius: 8px; padding: 15px; +} + +.task-summary-columns { display: -webkit-flex; display: flex; -webkit-flex-direction: row; diff --git a/assets/css/vendor.min.css b/assets/css/vendor.min.css index d5b238de..edd97352 100644 --- a/assets/css/vendor.min.css +++ b/assets/css/vendor.min.css @@ -459,6 +459,8 @@ This file is generated by `grunt build`, do not edit it by hand. } /* @end */ +.select2-container{box-sizing:border-box;display:inline-block;margin:0;position:relative;vertical-align:middle}.select2-container .select2-selection--single{box-sizing:border-box;cursor:pointer;display:block;height:28px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--single .select2-selection__rendered{display:block;padding-left:8px;padding-right:20px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.select2-container .select2-selection--single .select2-selection__clear{position:relative}.select2-container[dir="rtl"] .select2-selection--single .select2-selection__rendered{padding-right:8px;padding-left:20px}.select2-container .select2-selection--multiple{box-sizing:border-box;cursor:pointer;display:block;min-height:32px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--multiple .select2-selection__rendered{display:inline-block;overflow:hidden;padding-left:8px;text-overflow:ellipsis;white-space:nowrap}.select2-container .select2-search--inline{float:left}.select2-container .select2-search--inline .select2-search__field{box-sizing:border-box;border:none;font-size:100%;margin-top:5px;padding:0}.select2-container .select2-search--inline .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-dropdown{background-color:white;border:1px solid #aaa;border-radius:4px;box-sizing:border-box;display:block;position:absolute;left:-100000px;width:100%;z-index:1051}.select2-results{display:block}.select2-results__options{list-style:none;margin:0;padding:0}.select2-results__option{padding:6px;user-select:none;-webkit-user-select:none}.select2-results__option[aria-selected]{cursor:pointer}.select2-container--open .select2-dropdown{left:0}.select2-container--open .select2-dropdown--above{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--open .select2-dropdown--below{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-search--dropdown{display:block;padding:4px}.select2-search--dropdown .select2-search__field{padding:4px;width:100%;box-sizing:border-box}.select2-search--dropdown .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-search--dropdown.select2-search--hide{display:none}.select2-close-mask{border:0;margin:0;padding:0;display:block;position:fixed;left:0;top:0;min-height:100%;min-width:100%;height:auto;width:auto;opacity:0;z-index:99;background-color:#fff;filter:alpha(opacity=0)}.select2-hidden-accessible{border:0 !important;clip:rect(0 0 0 0) !important;height:1px !important;margin:-1px !important;overflow:hidden !important;padding:0 !important;position:absolute !important;width:1px !important}.select2-container--default .select2-selection--single{background-color:#fff;border:1px solid #aaa;border-radius:4px}.select2-container--default .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px}.select2-container--default .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:bold}.select2-container--default .select2-selection--single .select2-selection__placeholder{color:#999}.select2-container--default .select2-selection--single .select2-selection__arrow{height:26px;position:absolute;top:1px;right:1px;width:20px}.select2-container--default .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0}.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__clear{float:left}.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__arrow{left:1px;right:auto}.select2-container--default.select2-container--disabled .select2-selection--single{background-color:#eee;cursor:default}.select2-container--default.select2-container--disabled .select2-selection--single .select2-selection__clear{display:none}.select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px}.select2-container--default .select2-selection--multiple{background-color:white;border:1px solid #aaa;border-radius:4px;cursor:text}.select2-container--default .select2-selection--multiple .select2-selection__rendered{box-sizing:border-box;list-style:none;margin:0;padding:0 5px;width:100%}.select2-container--default .select2-selection--multiple .select2-selection__rendered li{list-style:none}.select2-container--default .select2-selection--multiple .select2-selection__placeholder{color:#999;margin-top:5px;float:left}.select2-container--default .select2-selection--multiple .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;margin-top:5px;margin-right:10px}.select2-container--default .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;border-radius:4px;cursor:default;float:left;margin-right:5px;margin-top:5px;padding:0 5px}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove{color:#999;cursor:pointer;display:inline-block;font-weight:bold;margin-right:2px}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover{color:#333}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice,.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__placeholder,.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-search--inline{float:right}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice{margin-left:5px;margin-right:auto}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove{margin-left:2px;margin-right:auto}.select2-container--default.select2-container--focus .select2-selection--multiple{border:solid black 1px;outline:0}.select2-container--default.select2-container--disabled .select2-selection--multiple{background-color:#eee;cursor:default}.select2-container--default.select2-container--disabled .select2-selection__choice__remove{display:none}.select2-container--default.select2-container--open.select2-container--above .select2-selection--single,.select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple{border-top-left-radius:0;border-top-right-radius:0}.select2-container--default.select2-container--open.select2-container--below .select2-selection--single,.select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--default .select2-search--dropdown .select2-search__field{border:1px solid #aaa}.select2-container--default .select2-search--inline .select2-search__field{background:transparent;border:none;outline:0;box-shadow:none;-webkit-appearance:textfield}.select2-container--default .select2-results>.select2-results__options{max-height:200px;overflow-y:auto}.select2-container--default .select2-results__option[role=group]{padding:0}.select2-container--default .select2-results__option[aria-disabled=true]{color:#999}.select2-container--default .select2-results__option[aria-selected=true]{background-color:#ddd}.select2-container--default .select2-results__option .select2-results__option{padding-left:1em}.select2-container--default .select2-results__option .select2-results__option .select2-results__group{padding-left:0}.select2-container--default .select2-results__option .select2-results__option .select2-results__option{margin-left:-1em;padding-left:2em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-2em;padding-left:3em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-3em;padding-left:4em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-4em;padding-left:5em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-5em;padding-left:6em}.select2-container--default .select2-results__option--highlighted[aria-selected]{background-color:#5897fb;color:white}.select2-container--default .select2-results__group{cursor:default;display:block;padding:6px}.select2-container--classic .select2-selection--single{background-color:#f7f7f7;border:1px solid #aaa;border-radius:4px;outline:0;background-image:-webkit-linear-gradient(top, #fff 50%, #eee 100%);background-image:-o-linear-gradient(top, #fff 50%, #eee 100%);background-image:linear-gradient(to bottom, #fff 50%, #eee 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0)}.select2-container--classic .select2-selection--single:focus{border:1px solid #5897fb}.select2-container--classic .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px}.select2-container--classic .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;margin-right:10px}.select2-container--classic .select2-selection--single .select2-selection__placeholder{color:#999}.select2-container--classic .select2-selection--single .select2-selection__arrow{background-color:#ddd;border:none;border-left:1px solid #aaa;border-top-right-radius:4px;border-bottom-right-radius:4px;height:26px;position:absolute;top:1px;right:1px;width:20px;background-image:-webkit-linear-gradient(top, #eee 50%, #ccc 100%);background-image:-o-linear-gradient(top, #eee 50%, #ccc 100%);background-image:linear-gradient(to bottom, #eee 50%, #ccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFCCCCCC', GradientType=0)}.select2-container--classic .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0}.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__clear{float:left}.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__arrow{border:none;border-right:1px solid #aaa;border-radius:0;border-top-left-radius:4px;border-bottom-left-radius:4px;left:1px;right:auto}.select2-container--classic.select2-container--open .select2-selection--single{border:1px solid #5897fb}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow{background:transparent;border:none}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--single{border-top:none;border-top-left-radius:0;border-top-right-radius:0;background-image:-webkit-linear-gradient(top, #fff 0%, #eee 50%);background-image:-o-linear-gradient(top, #fff 0%, #eee 50%);background-image:linear-gradient(to bottom, #fff 0%, #eee 50%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0)}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--single{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0;background-image:-webkit-linear-gradient(top, #eee 50%, #fff 100%);background-image:-o-linear-gradient(top, #eee 50%, #fff 100%);background-image:linear-gradient(to bottom, #eee 50%, #fff 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFFFFFFF', GradientType=0)}.select2-container--classic .select2-selection--multiple{background-color:white;border:1px solid #aaa;border-radius:4px;cursor:text;outline:0}.select2-container--classic .select2-selection--multiple:focus{border:1px solid #5897fb}.select2-container--classic .select2-selection--multiple .select2-selection__rendered{list-style:none;margin:0;padding:0 5px}.select2-container--classic .select2-selection--multiple .select2-selection__clear{display:none}.select2-container--classic .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;border-radius:4px;cursor:default;float:left;margin-right:5px;margin-top:5px;padding:0 5px}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove{color:#888;cursor:pointer;display:inline-block;font-weight:bold;margin-right:2px}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove:hover{color:#555}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice{float:right}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice{margin-left:5px;margin-right:auto}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove{margin-left:2px;margin-right:auto}.select2-container--classic.select2-container--open .select2-selection--multiple{border:1px solid #5897fb}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--multiple{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--classic .select2-search--dropdown .select2-search__field{border:1px solid #aaa;outline:0}.select2-container--classic .select2-search--inline .select2-search__field{outline:0;box-shadow:none}.select2-container--classic .select2-dropdown{background-color:#fff;border:1px solid transparent}.select2-container--classic .select2-dropdown--above{border-bottom:none}.select2-container--classic .select2-dropdown--below{border-top:none}.select2-container--classic .select2-results>.select2-results__options{max-height:200px;overflow-y:auto}.select2-container--classic .select2-results__option[role=group]{padding:0}.select2-container--classic .select2-results__option[aria-disabled=true]{color:grey}.select2-container--classic .select2-results__option--highlighted[aria-selected]{background-color:#3875d7;color:#fff}.select2-container--classic .select2-results__group{cursor:default;display:block;padding:6px}.select2-container--classic.select2-container--open .select2-dropdown{border-color:#5897fb} + /*! * FullCalendar v2.7.1 Stylesheet * Docs & License: http://fullcalendar.io/ diff --git a/assets/js/app.min.js b/assets/js/app.min.js index 075b6489..7f894359 100644 --- a/assets/js/app.min.js +++ b/assets/js/app.min.js @@ -1,2 +1,2 @@ -"use strict";var Kanboard={};Kanboard.Accordion=function(t){this.app=t},Kanboard.Accordion.prototype.listen=function(){$(document).on("click",".accordion-toggle",function(t){var e=$(this).parents(".accordion-section");t.preventDefault(),e.hasClass("accordion-collapsed")?(e.find(".accordion-content").show(),e.removeClass("accordion-collapsed")):(e.find(".accordion-content").hide(),e.addClass("accordion-collapsed"))})},Kanboard.App=function(){this.controllers={}},Kanboard.App.prototype.get=function(t){return this.controllers[t]},Kanboard.App.prototype.execute=function(){for(var t in Kanboard)if("App"!==t){var e=new Kanboard[t](this);this.controllers[t]=e,"function"==typeof e.execute&&e.execute(),"function"==typeof e.listen&&e.listen(),"function"==typeof e.focus&&e.focus(),"function"==typeof e.keyboardShortcuts&&e.keyboardShortcuts()}this.focus(),this.chosen(),this.keyboardShortcuts(),this.datePicker(),this.autoComplete()},Kanboard.App.prototype.keyboardShortcuts=function(){var t=this;Mousetrap.bindGlobal("mod+enter",function(){var e=$("form");1==e.length?e.submit():e.length>1&&("INPUT"===document.activeElement.tagName||"TEXTAREA"===document.activeElement.tagName?$(document.activeElement).parents("form").submit():t.get("Popover").isOpen()&&$("#popover-container form").submit())}),Mousetrap.bind("b",function(t){t.preventDefault(),$("#board-selector").trigger("chosen:open")}),Mousetrap.bindGlobal("esc",function(){t.get("Popover").close(),t.get("Dropdown").close()}),Mousetrap.bind("?",function(){t.get("Popover").open($("body").data("keyboard-shortcut-url"))})},Kanboard.App.prototype.focus=function(){$(document).on("focus",".auto-select",function(){$(this).select()}),$(document).on("mouseup",".auto-select",function(t){t.preventDefault()})},Kanboard.App.prototype.chosen=function(){$(".chosen-select").each(function(){var t=$(this).data("search-threshold");void 0===t&&(t=10),$(this).chosen({width:"180px",no_results_text:$(this).data("notfound"),disable_search_threshold:t})}),$(".select-auto-redirect").change(function(){var t=new RegExp($(this).data("redirect-regex"),"g");window.location=$(this).data("redirect-url").replace(t,$(this).val())})},Kanboard.App.prototype.datePicker=function(){var t=$("body"),e=t.data("js-date-format"),a=t.data("js-time-format"),o=t.data("js-lang");$.datepicker.setDefaults($.datepicker.regional[o]),$.timepicker.setDefaults($.timepicker.regional[o]),$(".form-date").datepicker({showOtherMonths:!0,selectOtherMonths:!0,dateFormat:e,constrainInput:!1}),$(".form-datetime").datetimepicker({dateFormat:e,timeFormat:a,constrainInput:!1})},Kanboard.App.prototype.autoComplete=function(){$(".autocomplete").each(function(){var t=$(this),e=t.data("dst-field"),a=t.data("dst-extra-field");""==$("#form-"+e).val()&&t.parent().find("button[type=submit]").attr("disabled","disabled"),t.autocomplete({source:t.data("search-url"),minLength:1,select:function(o,n){$("input[name="+e+"]").val(n.item.id),a&&$("input[name="+a+"]").val(n.item[a]),t.parent().find("button[type=submit]").removeAttr("disabled")}})})},Kanboard.App.prototype.hasId=function(t){return!!document.getElementById(t)},Kanboard.App.prototype.showLoadingIcon=function(){$("body").append(' ')},Kanboard.App.prototype.hideLoadingIcon=function(){$("#app-loading-icon").remove()},Kanboard.App.prototype.formatDuration=function(t){return t>=86400?Math.round(t/86400)+"d":t>=3600?Math.round(t/3600)+"h":t>=60?Math.round(t/60)+"m":t+"s"},Kanboard.App.prototype.isVisible=function(){var t="";return"undefined"!=typeof document.hidden?t="visibilityState":"undefined"!=typeof document.mozHidden?t="mozVisibilityState":"undefined"!=typeof document.msHidden?t="msVisibilityState":"undefined"!=typeof document.webkitHidden&&(t="webkitVisibilityState"),""!=t?"visible"==document[t]:!0},Kanboard.AvgTimeColumnChart=function(t){this.app=t},Kanboard.AvgTimeColumnChart.prototype.execute=function(){this.app.hasId("analytic-avg-time-column")&&this.show()},Kanboard.AvgTimeColumnChart.prototype.show=function(){var t=$("#chart"),e=t.data("metrics"),a=[t.data("label")],o=[];for(var n in e)a.push(e[n].average),o.push(e[n].title);c3.generate({data:{columns:[a],type:"bar"},bar:{width:{ratio:.5}},axis:{x:{type:"category",categories:o},y:{tick:{format:this.app.formatDuration}}},legend:{show:!1}})},Kanboard.BoardCollapsedMode=function(t){this.app=t},Kanboard.BoardCollapsedMode.prototype.keyboardShortcuts=function(){var t=this;t.app.hasId("board")&&Mousetrap.bind("s",function(){t.toggle()})},Kanboard.BoardCollapsedMode.prototype.toggle=function(){var t=this;this.app.showLoadingIcon(),$.ajax({cache:!1,url:$('.filter-display-mode:not([style="display: none;"]) a').attr("href"),success:function(e){$(".filter-display-mode").toggle(),t.app.get("BoardDragAndDrop").refresh(e)}})},Kanboard.BoardColumnScrolling=function(t){this.app=t},Kanboard.BoardColumnScrolling.prototype.execute=function(){this.app.hasId("board")&&(this.render(),$(window).on("load",this.render),$(window).resize(this.render))},Kanboard.BoardColumnScrolling.prototype.listen=function(){var t=this;$(document).on("click",".filter-toggle-height",function(e){e.preventDefault(),t.toggle()})},Kanboard.BoardColumnScrolling.prototype.onBoardRendered=function(){this.render()},Kanboard.BoardColumnScrolling.prototype.toggle=function(){var t=localStorage.getItem("column_scroll");void 0==t&&(t=1),localStorage.setItem("column_scroll",0==t?1:0),this.render()},Kanboard.BoardColumnScrolling.prototype.render=function(){var t=$(".board-task-list"),e=$(".board-rotation-wrapper"),a=$(".filter-max-height"),o=$(".filter-min-height");if(0==localStorage.getItem("column_scroll")){var n=80;a.show(),o.hide(),e.css("min-height",""),t.each(function(){var t=$(this).height();t>n&&(n=t)}),t.css("min-height",n),t.css("height","")}else if(a.hide(),o.show(),$(".board-swimlane").length>1)t.each(function(){$(this).height()>500?$(this).css("height",500):($(this).css("min-height",320),e.css("min-height",320))});else{var n=$(window).height()-170;t.css("height",n),e.css("min-height",n)}},Kanboard.BoardColumnView=function(t){this.app=t},Kanboard.BoardColumnView.prototype.execute=function(){this.app.hasId("board")&&this.render()},Kanboard.BoardColumnView.prototype.listen=function(){var t=this;$(document).on("click",".board-toggle-column-view",function(){t.toggle($(this).data("column-id"))})},Kanboard.BoardColumnView.prototype.onBoardRendered=function(){this.render()},Kanboard.BoardColumnView.prototype.render=function(){var t=this;$(".board-column-header").each(function(){var e=$(this).data("column-id");localStorage.getItem("hidden_column_"+e)&&t.hideColumn(e)})},Kanboard.BoardColumnView.prototype.toggle=function(t){localStorage.getItem("hidden_column_"+t)?this.showColumn(t):this.hideColumn(t)},Kanboard.BoardColumnView.prototype.hideColumn=function(t){$(".board-column-"+t+" .board-column-expanded").hide(),$(".board-column-"+t+" .board-column-collapsed").show(),$(".board-column-header-"+t+" .board-column-expanded").hide(),$(".board-column-header-"+t+" .board-column-collapsed").show(),$(".board-column-header-"+t).each(function(){$(this).removeClass("board-column-compact"),$(this).addClass("board-column-header-collapsed")}),$(".board-column-"+t).each(function(){$(this).addClass("board-column-task-collapsed")}),$(".board-column-"+t+" .board-rotation").each(function(){$(this).css("width",$(".board-column-"+t).height())}),localStorage.setItem("hidden_column_"+t,1)},Kanboard.BoardColumnView.prototype.showColumn=function(t){$(".board-column-"+t+" .board-column-expanded").show(),$(".board-column-"+t+" .board-column-collapsed").hide(),$(".board-column-header-"+t+" .board-column-expanded").show(),$(".board-column-header-"+t+" .board-column-collapsed").hide(),$(".board-column-header-"+t).removeClass("board-column-header-collapsed"),$(".board-column-"+t).removeClass("board-column-task-collapsed"),0==localStorage.getItem("horizontal_scroll")&&$(".board-column-header-"+t).addClass("board-column-compact"),localStorage.removeItem("hidden_column_"+t)},Kanboard.BoardHorizontalScrolling=function(t){this.app=t},Kanboard.BoardHorizontalScrolling.prototype.execute=function(){this.app.hasId("board")&&this.render()},Kanboard.BoardHorizontalScrolling.prototype.listen=function(){var t=this;$(document).on("click",".filter-toggle-scrolling",function(e){e.preventDefault(),t.toggle()})},Kanboard.BoardHorizontalScrolling.prototype.keyboardShortcuts=function(){var t=this;t.app.hasId("board")&&Mousetrap.bind("c",function(){t.toggle()})},Kanboard.BoardHorizontalScrolling.prototype.onBoardRendered=function(){this.render()},Kanboard.BoardHorizontalScrolling.prototype.toggle=function(){var t=localStorage.getItem("horizontal_scroll")||1;localStorage.setItem("horizontal_scroll",0==t?1:0),this.render()},Kanboard.BoardHorizontalScrolling.prototype.render=function(){0==localStorage.getItem("horizontal_scroll")?($(".filter-wide").show(),$(".filter-compact").hide(),$("#board-container").addClass("board-container-compact"),$("#board th:not(.board-column-header-collapsed)").addClass("board-column-compact")):($(".filter-wide").hide(),$(".filter-compact").show(),$("#board-container").removeClass("board-container-compact"),$("#board th").removeClass("board-column-compact"))},Kanboard.BoardPolling=function(t){this.app=t},Kanboard.BoardPolling.prototype.execute=function(){if(this.app.hasId("board")){var t=parseInt($("#board").attr("data-check-interval"));t>0&&window.setInterval(this.check.bind(this),1e3*t)}},Kanboard.BoardPolling.prototype.check=function(){if(this.app.isVisible()&&!this.app.get("BoardDragAndDrop").savingInProgress){var t=this;this.app.showLoadingIcon(),$.ajax({cache:!1,url:$("#board").data("check-url"),statusCode:{200:function(e){t.app.get("BoardDragAndDrop").refresh(e)},304:function(){t.app.hideLoadingIcon()}}})}},Kanboard.BoardTask=function(t){this.app=t},Kanboard.BoardTask.prototype.listen=function(){var t=this;$(document).on("click",".task-board-change-assignee",function(e){e.preventDefault(),e.stopPropagation(),t.app.get("Popover").open($(this).data("url"))}),$(document).on("click",".task-board",function(t){"A"!=t.target.tagName&&"IMG"!=t.target.tagName&&(window.location=$(this).data("task-url"))})},Kanboard.BoardTask.prototype.keyboardShortcuts=function(){var t=this;t.app.hasId("board")&&Mousetrap.bind("n",function(){t.app.get("Popover").open($("#board").data("task-creation-url"))})},Kanboard.BurndownChart=function(t){this.app=t},Kanboard.BurndownChart.prototype.execute=function(){this.app.hasId("analytic-burndown")&&this.show()},Kanboard.BurndownChart.prototype.show=function(){for(var t=$("#chart"),e=t.data("metrics"),a=[[t.data("label-total")]],o=[],n=d3.time.format("%Y-%m-%d"),r=d3.time.format(t.data("date-format")),i=0;i0&&(void 0==a[0][i]&&a[0].push(0),a[0][i]+=e[i][s]),0==s&&o.push(r(n.parse(e[i][s]))));c3.generate({data:{columns:a},axis:{x:{type:"category",categories:o}}})},Kanboard.Calendar=function(t){this.app=t},Kanboard.Calendar.prototype.execute=function(){var t=$("#calendar");1==t.length&&this.show(t)},Kanboard.Calendar.prototype.show=function(t){t.fullCalendar({lang:$("body").data("js-lang"),editable:!0,eventLimit:!0,defaultView:"month",header:{left:"prev,next today",center:"title",right:"month,agendaWeek,agendaDay"},eventDrop:function(e){$.ajax({cache:!1,url:t.data("save-url"),contentType:"application/json",type:"POST",processData:!1,data:JSON.stringify({task_id:e.id,date_due:e.start.format()})})},viewRender:function(){var e=t.data("check-url"),a={start:t.fullCalendar("getView").start.format(),end:t.fullCalendar("getView").end.format()};for(var o in a)e+="&"+o+"="+a[o];$.getJSON(e,function(e){t.fullCalendar("removeEvents"),t.fullCalendar("addEventSource",e),t.fullCalendar("rerenderEvents")})}})},Kanboard.Column=function(t){this.app=t},Kanboard.Column.prototype.listen=function(){this.dragAndDrop()},Kanboard.Column.prototype.dragAndDrop=function(){var t=this;$(".draggable-row-handle").mouseenter(function(){$(this).parent().parent().addClass("draggable-item-hover")}).mouseleave(function(){$(this).parent().parent().removeClass("draggable-item-hover")}),$(".columns-table tbody").sortable({forcePlaceholderSize:!0,handle:"td:first i",helper:function(t,e){return e.children().each(function(){$(this).width($(this).width())}),e},stop:function(e,a){var o=a.item;o.removeClass("draggable-item-selected"),t.savePosition(o.data("column-id"),o.index()+1)},start:function(t,e){e.item.addClass("draggable-item-selected")}}).disableSelection()},Kanboard.Column.prototype.savePosition=function(t,e){var a=$(".columns-table").data("save-position-url"),o=this;this.app.showLoadingIcon(),$.ajax({cache:!1,url:a,contentType:"application/json",type:"POST",processData:!1,data:JSON.stringify({column_id:t,position:e}),complete:function(){o.app.hideLoadingIcon()}})},Kanboard.CompareHoursColumnChart=function(t){this.app=t},Kanboard.CompareHoursColumnChart.prototype.execute=function(){this.app.hasId("analytic-compare-hours")&&this.show()},Kanboard.CompareHoursColumnChart.prototype.show=function(){var t=$("#chart"),e=t.data("metrics"),a=t.data("label-open"),o=t.data("label-closed"),n=[t.data("label-spent")],r=[t.data("label-estimated")],i=[];for(var s in e)n.push(parseFloat(e[s].time_spent)),r.push(parseFloat(e[s].time_estimated)),i.push("open"==s?a:o);c3.generate({data:{columns:[n,r],type:"bar"},bar:{width:{ratio:.2}},axis:{x:{type:"category",categories:i}},legend:{show:!0}})},Kanboard.CumulativeFlowDiagram=function(t){this.app=t},Kanboard.CumulativeFlowDiagram.prototype.execute=function(){this.app.hasId("analytic-cfd")&&this.show()},Kanboard.CumulativeFlowDiagram.prototype.show=function(){for(var t=$("#chart"),e=t.data("metrics"),a=[],o=[],n=[],r=d3.time.format("%Y-%m-%d"),i=d3.time.format(t.data("date-format")),s=0;s0&&o.push(e[s][d])):(a[d].push(e[s][d]),0==d&&n.push(i(r.parse(e[s][d]))));c3.generate({data:{columns:a,type:"area-spline",groups:[o]},axis:{x:{type:"category",categories:n}}})},Kanboard.Dropdown=function(t){this.app=t},Kanboard.Dropdown.prototype.listen=function(){var t=this;$(document).on("click",function(){t.close()}),$(document).on("click",".dropdown-menu",function(e){e.preventDefault(),e.stopImmediatePropagation(),t.close();var a=$(this).next("ul"),o=$(this).offset();$("body").append(jQuery("
",{id:"dropdown"})),a.clone().appendTo("#dropdown");var n=$("#dropdown ul");n.addClass("dropdown-submenu-open");var r=n.outerHeight(),i=n.outerWidth();o.top+r-$(window).scrollTop()<$(window).height()||$(window).scrollTop()+o.top$(window).width()?n.css("left",o.left-i+$(this).outerWidth()):n.css("left",o.left)}),$(document).on("click",".dropdown-submenu-open li",function(t){$(t.target).is("li")&&$(this).find("a:visible")[0].click()})},Kanboard.Dropdown.prototype.close=function(){$("#dropdown").remove()},Kanboard.Dropdown.prototype.onPopoverOpened=function(){this.close()},Kanboard.FileUpload=function(t){this.app=t,this.files=[],this.currentFile=0},Kanboard.FileUpload.prototype.onPopoverOpened=function(){var t=document.getElementById("file-dropzone"),e=this;t&&(t.ondragover=t.ondragenter=function(t){t.stopPropagation(),t.preventDefault()},t.ondrop=function(t){t.stopPropagation(),t.preventDefault(),e.files=t.dataTransfer.files,e.show(),$("#file-error-max-size").hide()},$(document).on("click","#file-browser",function(t){t.preventDefault(),$("#file-form-element").get(0).click()}),$(document).on("click","#file-upload-button",function(t){t.preventDefault(),e.currentFile=0,e.checkFiles()}),$("#file-form-element").change(function(){e.files=document.getElementById("file-form-element").files,e.show(),$("#file-error-max-size").hide()}))},Kanboard.FileUpload.prototype.show=function(){if($("#file-list").remove(),this.files.length>0){$("#file-upload-button").prop("disabled",!1),$("#file-dropzone-inner").hide();for(var t=jQuery("
diff --git a/assets/css/app.min.css b/assets/css/app.min.css index ae139039..5570afec 100644 --- a/assets/css/app.min.css +++ b/assets/css/app.min.css @@ -1 +1 @@ -h1,li,ul,ol,table,tr,td,th,p,blockquote,body{margin:0;padding:0;font-size:100%}body{margin-left:10px;margin-right:10px;padding-bottom:10px;color:#333;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;text-rendering:optimizeLegibility}small{font-size:0.8em}hr{border:0;height:0;border-top:1px solid rgba(0,0,0,0.1);border-bottom:1px solid rgba(255,255,255,0.3)}.pull-right{text-align:right}ul.no-bullet li{list-style-type:none;margin-left:0}.chosen-select{min-height:27px}#app-loading-icon{position:fixed;right:3px;bottom:3px}.assign-me{vertical-align:bottom}a{color:#36c;border:none}a:focus{outline:0;color:#DF5353;text-decoration:none}a:hover{color:#333;text-decoration:none}h1,h2,h3{font-weight:normal;color:#333}h1{font-size:1.5em}h2{font-size:1.4em;margin-bottom:10px}h3{margin-top:10px;font-size:1.2em}table{width:100%;border-collapse:collapse;border-spacing:0;margin-bottom:20px}th{border:1px solid #eee;padding:0.5em 3px}td{border:1px solid #eee;padding:0.5em 3px;vertical-align:top}th{background:#fbfbfb;text-align:left}td li{margin-left:20px}.table-small{font-size:0.8em}th a{text-decoration:none;color:#333}th a:focus,th a:hover{text-decoration:underline}.table-fixed{table-layout:fixed;white-space:nowrap}.table-fixed th{overflow:hidden}.table-fixed td{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.table-stripped tr:nth-child(odd){background:#fefefe}.column-3{width:3%}.column-5{width:5%}.column-8{width:7.5%}.column-10{width:10%}.column-12{width:12%}.column-15{width:15%}.column-18{width:18%}.column-20{width:20%}.column-25{width:25%}.column-30{width:30%}.column-35{width:35%}.column-40{width:40%}.column-50{width:50%}.column-60{width:60%}.column-70,.column-80{width:70%}.draggable-row-handle{cursor:move;color:#dedede}.draggable-row-handle:hover{color:#333}tr.draggable-item-selected{background:#fff;border:2px solid #666;box-shadow:4px 2px 10px -4px rgba(0,0,0,0.55)}tr.draggable-item-selected td{border-top:none;border-bottom:none}tr.draggable-item-selected td:first-child{border-left:none}tr.draggable-item-selected td:last-child{border-right:none}.table-stripped tr.draggable-item-hover,tr.draggable-item-hover{background:#FEFFF2}form{margin-bottom:20px}label{cursor:pointer;display:block;margin-top:10px}input[type="number"],input[type="date"],input[type="email"],input[type="password"],input[type="text"]:not(.input-addon-field){color:#999;border:1px solid #ccc;width:300px;max-width:95%;font-size:1em;height:25px;padding-bottom:0;font-family:sans-serif;margin-top:10px;-webkit-appearance:none;-moz-appearance:none}input[type="number"]:focus,input[type="date"]:focus,input[type="email"]:focus,input[type="password"]:focus,input[type="text"]:focus{color:#000;border-color:rgba(82,168,236,0.8);outline:0;box-shadow:0 0 8px rgba(82,168,236,0.6)}textarea:focus{color:#000;border-color:rgba(82,168,236,0.8);outline:0;box-shadow:0 0 8px rgba(82,168,236,0.6)}input.form-numeric,input[type="number"]{width:70px}textarea{border:1px solid #ccc;width:400px;max-width:99%;height:200px;font-family:sans-serif}select{max-width:95%}select:focus{outline:0}.tag-autocomplete{width:400px}span.select2-container{margin-top:2px}::-webkit-input-placeholder,::-ms-input-placeholder,::-moz-placeholder{color:#999;opacity:0.2;padding-top:2px}.form-actions{padding-top:20px;clear:both}input.form-error,textarea.form-error{border:2px solid #b94a48}input.form-error:focus,textarea.form-error:focus{box-shadow:none;border:2px solid #b94a48}.form-required{color:red;padding-left:5px;font-weight:bold}.form-errors{color:#b94a48;list-style-type:none}ul.form-errors li{margin-left:0}.form-help{font-size:0.8em;color:brown;margin-bottom:15px}.form-inline{padding:0;margin:0;border:none}.form-inline label{display:inline}.form-inline input,.form-inline select{margin:0 15px 0 0}.form-inline .form-required{display:none}.form-inline-group{display:inline}input.form-datetime,input.form-date{width:150px}input.form-input-large{width:400px}input.form-input-small{width:150px}.form-columns{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row}.form-column{margin-right:25px}.form-login{width:350px;margin:8% auto 0}.form-login li{margin-left:25px;line-height:25px}.form-login h2{margin-bottom:30px;font-weight:bold}.reset-password{margin-top:20px}.reset-password a{color:#999}.input-addon{display:flex}.input-addon-field{flex:1;font-size:1em;color:#999;margin:0;-webkit-appearance:none;-moz-appearance:none}.input-addon-item{background-color:rgba(147,128,108,0.1);color:#666;font:inherit;font-weight:normal}@media (max-width: 480px){.input-addon-item .dropdown .fa-caret-down{display:none}}.input-addon-field,.input-addon-item{border:1px solid rgba(147,128,108,0.25);padding:4px 0.75em}.input-addon-field:not(:first-child),.input-addon-item:not(:first-child){border-left:0}.input-addon-field:first-child,.input-addon-item:first-child{border-radius:5px 0 0 5px}.input-addon-field:last-child,.input-addon-item:last-child{border-radius:0 5px 5px 0}.alert{padding:8px 35px 8px 14px;margin-top:5px;margin-bottom:5px;color:#c09853;background-color:#fcf8e3;border:1px solid #fbeed5;border-radius:4px}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-normal{color:#333;background-color:#f0f0f0;border-color:#ddd}.alert ul{margin-top:10px;margin-bottom:10px}.alert li{margin-left:25px}.alert-fade-out{text-align:center;position:fixed;bottom:0;left:20%;width:60%;padding-top:5px;padding-bottom:5px;margin-bottom:0;border-width:1px 0 0;border-radius:4px 4px 0 0;z-index:9999}a.btn{text-decoration:none}.btn{-webkit-appearance:none;-moz-appearance:none;font-size:1.2em;font-weight:normal;cursor:pointer;display:inline-block;border-radius:2px;padding:3px 10px;margin:0;border:1px solid #ddd;background:#f5f5f5;color:#333}.btn:hover,.btn:focus{border-color:#bbb;background:#fafafa;color:#000}.btn-red{border-color:#b0281a;background:#d14836;color:#fff}.btn-red:hover,.btn-red:focus{border-color:#b0281a;background:#c53727;color:#fff}.btn-blue{border-color:#3079ed;background:#4d90fe;color:#fff}.btn-blue:hover,.btn-blue:focus{border-color:#3079ed;background:#357ae8;color:#fff}.btn:disabled{color:#ccc;border-color:#ccc;background:#f7f7f7}.buttons-header{font-size:0.8em;margin-top:5px;margin-bottom:15px}.tooltip-arrow:after{background:#fff;border:1px solid #aaaaaa;box-shadow:0 0 5px #aaa}div.ui-tooltip{min-width:200px;max-width:600px}.tooltip-arrow{width:20px;height:10px;overflow:hidden;position:absolute}.tooltip-arrow.top{top:-10px}.tooltip-arrow.bottom{bottom:-10px}.tooltip-arrow.align-left{left:10px}.tooltip-arrow.align-right{right:10px}.tooltip-arrow:after{content:"";position:absolute;width:14px;height:14px;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg)}.tooltip-arrow.bottom:after{top:-10px}.tooltip-arrow.top:after{bottom:-10px}.tooltip-arrow.align-left:after{left:0}.tooltip-arrow.align-right:after{right:0}.tooltip-large{width:600px}.ui-tooltip-content .markdown p{margin-bottom:0}.ui-tooltip li{list-style-type:none}.tooltip .fa-info-circle{color:#999}.dropdown{display:inline;position:relative}.dropdown ul{display:none}ul.dropdown-submenu-open{display:block;position:absolute;z-index:1000;min-width:285px;list-style:none;margin:3px 0 0 1px;padding:6px 0;background-color:#fff;border:1px solid #b2b2b2;border-radius:3px;box-shadow:0 1px 3px rgba(0,0,0,0.15)}.dropdown-submenu-open li{display:block;margin:0;padding:8px 10px;font-size:0.9em;border-bottom:1px solid #f8f8f8;cursor:pointer}.dropdown-submenu-open li.no-hover{cursor:default}.dropdown-submenu-open li:last-child{border:none}.dropdown-submenu-open li:not(.no-hover):hover{background:#4078C0;color:#fff}.dropdown-submenu-open li:hover a{color:#fff}.dropdown-submenu-open a{text-decoration:none;color:#333}.dropdown-submenu-open a:focus{text-decoration:underline}.dropdown-menu-link-text,.dropdown-menu-link-icon{color:#333;text-decoration:none}.dropdown-menu-link-text:hover{text-decoration:underline}.accordion-title{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAADCAYAAABS3WWCAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NEQ5RDgxQzc2RjQ5MTFFMjhEMUNENzFGRUMwRjhBRTciIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NEQ5RDgxQzg2RjQ5MTFFMjhEMUNENzFGRUMwRjhBRTciPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo0RDlEODFDNTZGNDkxMUUyOEQxQ0Q3MUZFQzBGOEFFNyIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo0RDlEODFDNjZGNDkxMUUyOEQxQ0Q3MUZFQzBGOEFFNyIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PvXFWFAAAAAYSURBVHjaYvj//z8D0/Pnz/8zgFgAAQYAS5UJscReGMIAAAAASUVORK5CYII=) repeat-x scroll 0 10px}.accordion-title h3{display:inline;padding-right:5px;background:#fff}.accordion-content{margin-top:15px;margin-bottom:25px}.accordion-toggle{color:#333;text-decoration:none}.accordion-toggle:focus{color:#333}.accordion-toggle:hover{color:#999}.accordion-toggle:before{content:"\f0d7"}.accordion-collapsed{margin-bottom:25px}.accordion-collapsed .accordion-toggle:before{content:"\f0da"}.accordion-collapsed .accordion-content{display:none}#main .confirm{max-width:700px}#popover-container{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.8);overflow:auto;z-index:100}#popover-content{position:absolute;width:70%;left:15%;top:1%;padding:15px;background:#fff;overflow:auto;max-height:90%}.popover-form{margin-bottom:0}.pagination{text-align:center}.pagination-next{margin-left:5px}.pagination-previous{margin-right:5px}header{box-sizing:border-box;display:flex;flex-wrap:wrap;margin-top:5px;margin-bottom:5px;border-bottom:1px solid #dedede}header>*{box-sizing:border-box}header>*{width:1%}header .menus-container{width:10%}@media (min-width: 768px) and (max-width: 1150px){header .menus-container{width:15%}}@media (max-width: 768px){header .menus-container{width:65%;order:2}}header .board-selector-container{width:15%}@media (min-width: 768px) and (max-width: 1150px){header .board-selector-container{width:20%}}@media (max-width: 768px){header .board-selector-container{width:35%;order:1;margin-bottom:5px}}header .title-container{width:75%}@media (min-width: 768px) and (max-width: 1150px){header .title-container{width:65%}}@media (max-width: 768px){header .title-container{width:100%;order:3}}header h1{font-size:1.5em}header h1 .tooltip{opacity:0.3;font-size:0.7em}.web-notification-icon{color:#36c}.web-notification-icon:focus,.web-notification-icon:hover{color:#000}.logo a{opacity:0.5;color:#d40000;text-decoration:none}.logo span{color:#333}.logo a:hover{opacity:0.8;color:#333}.logo a:focus span,.logo a:hover span{color:#d40000}.page-header{margin-bottom:20px}.page-header .dropdown{padding-right:10px}.page-header h2{margin:0;padding:0;font-weight:bold;border-bottom:1px dotted #ccc}.page-header h2 a{color:#333;text-decoration:none}.page-header h2 a:focus,.page-header h2 a:hover{color:#999}.page-header ul{text-align:left;margin-top:5px;display:inline-block}.page-header li{display:inline;padding-right:15px}.page-header li.active a{color:#333;text-decoration:none;font-weight:bold}.page-header li.active a:hover,.page-header li.active a:focus{text-decoration:underline}.menu-inline{margin-bottom:5px}.menu-inline li{display:inline;padding-right:15px}.menu-inline li .active a{font-weight:bold;color:#000;text-decoration:none}.sidebar-container{margin-top:10px;height:100%;width:100%;display:-ms-flexbox;display:-webkit-box;display:-moz-box;display:-ms-box;display:box;-ms-flex-direction:row;-webkit-box-orient:horizontal;-moz-box-orient:horizontal;-ms-box-orient:horizontal;box-orient:horizontal}.sidebar-content{padding-left:10px;-ms-flex:1;-webkit-box-flex:1;-moz-box-flex:1;-ms-box-flex:1;box-flex:1}.sidebar{padding-right:10px;border-right:1px dotted #eee;max-width:240px;min-width:190px;width:18%;-ms-flex:0 100px;-webkit-box-flex:0;-moz-box-flex:0;-ms-box-flex:0;box-flex:0}.sidebar h2{margin-top:0}.sidebar>ul a{text-decoration:none;color:#999;font-weight:300}.sidebar>ul a:hover{color:#333}.sidebar>ul li{list-style-type:none;line-height:35px;border-bottom:1px dotted #efefef;padding-left:13px}.sidebar>ul li:hover{border-left:5px solid #555;padding-left:8px}.sidebar>ul li.active{border-left:5px solid #333;padding-left:8px}.sidebar>ul li.active a{color:#333;font-weight:bold}.sidebar-icons>ul li{padding-left:0}.sidebar-icons>ul li:hover,.sidebar-icons>ul li.active{padding-left:0;border-left:none}.sidebar>ul li.active a:focus,.sidebar>ul li.active a:hover{color:#555}.sidebar>ul li:last-child{margin-bottom:15px}.avatar img{vertical-align:bottom}.avatar-left{float:left;margin-right:10px}.avatar-inline{display:inline-block;margin-right:3px}.avatar-48 img,.avatar-48 div{border-radius:30px}.avatar-48 .avatar-letter{line-height:48px;width:48px;font-size:25px}.avatar-20 img,.avatar-20 div{border-radius:10px}.avatar-20 .avatar-letter{line-height:20px;width:20px;font-size:11px}.avatar-letter{color:#fff;text-align:center}#file-dropzone,#screenshot-zone{position:relative;border:2px dashed #ccc;width:99%;height:250px;overflow:auto}#file-dropzone-inner,#screenshot-inner{position:absolute;left:0;bottom:48%;width:100%;text-align:center;color:#aaa}#screenshot-zone.screenshot-pasted{border:2px solid #333}#file-list{margin:20px}#file-list li{list-style-type:none;padding-top:8px;padding-bottom:8px;border-bottom:1px dotted #ddd;width:95%}#file-list li.file-error{font-weight:bold;color:#b94a48}.color-picker{width:180px}.color-picker-option{height:25px}.color-picker-square{display:inline-block;width:18px;height:18px;margin-right:5px;border:1px solid #000}.color-picker-label{display:inline-block;vertical-align:bottom;padding-bottom:3px}.file-thumbnails{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;flex-wrap:wrap;-webkit-justify-content:flex-start;justify-content:flex-start}.file-thumbnail{width:250px;border:1px solid #efefef;border-radius:5px;margin-bottom:20px;box-shadow:4px 2px 10px -6px rgba(0,0,0,0.55);margin-right:15px}.file-thumbnail img{border-top-left-radius:5px;border-top-right-radius:5px}.file-thumbnail img:hover{opacity:0.5}.file-thumbnail-content{padding-left:8px;padding-right:8px}.file-thumbnail-title{font-weight:700;font-size:0.9em;color:#555}.file-thumbnail-description{font-size:0.8em;color:#999;margin-top:8px;margin-bottom:5px}.file-viewer{position:relative}.file-viewer img{max-width:95%;max-height:85%;margin-top:10px}.filter-box{max-width:800px}.project-header{margin-top:8px;margin-bottom:20px}.action-menu{color:#333;text-decoration:none}.action-menu:hover,.action-menu:focus{text-decoration:underline}.project-creation-options{max-width:500px;border-left:3px dotted #efefef;margin-top:20px;padding-left:15px;padding-bottom:5px;padding-top:5px}.project-overview-columns{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;align-items:center;-webkit-justify-content:center;justify-content:center;margin-bottom:20px;font-size:1.4em}.project-overview-column{text-align:center;margin-right:3%;padding:3px 15px 3px 15px;border:1px dashed #ddd}.project-overview-column small{color:#999}.project-overview-column strong{color:#555}.project-header{box-sizing:border-box;display:flex;flex-wrap:wrap}.project-header>*{box-sizing:border-box}.project-header>*{width:1%}.project-header .dropdown-component{width:5%}@media (min-width: 768px) and (max-width: 1150px){.project-header .dropdown-component{width:8%}}@media (max-width: 768px){.project-header .dropdown-component{width:100%}}.project-header .views-switcher-component{width:38%}@media (max-width: 1300px){.project-header .views-switcher-component{width:45%}}@media (min-width: 768px) and (max-width: 1150px){.project-header .views-switcher-component{width:92%}}@media (max-width: 768px){.project-header .views-switcher-component{width:100%}}.project-header .filter-box-component{margin:0;width:55%}@media (max-width: 1300px){.project-header .filter-box-component{width:50%}}@media (min-width: 768px) and (max-width: 1150px){.project-header .filter-box-component{width:100%;margin-top:10px}.project-header .filter-box-component .filter-box{max-width:100%}}@media (max-width: 768px){.project-header .filter-box-component{width:100%;margin-top:10px}.project-header .filter-box-component .filter-box{max-width:100%}}.project-header .filter-box-component form{margin:0}.views{display:inline-block;margin-right:10px;font-size:0.9em}@media (max-width: 560px){.views{width:100%}}@media (max-width: 768px){.views{margin-top:10px;font-size:1em}}.views li{white-space:nowrap;background:#fafafa;border:1px solid #ddd;border-right:none;padding:4px 8px;display:inline}@media (max-width: 560px){.views li{display:block;margin-top:5px;border-radius:5px;border:1px solid #ddd}}.views li.active a{font-weight:bold;color:#000;text-decoration:none}.views li:first-child{border-top-left-radius:5px;border-bottom-left-radius:5px}.views li:last-child{border-right:1px solid #ddd;border-top-right-radius:5px;border-bottom-right-radius:5px}.views a{color:#555;text-decoration:none}.views a:hover{color:#333;text-decoration:underline}.dashboard-project-stats small{margin-right:10px;color:#999}.dashboard-table-link{font-weight:bold;color:#000;text-decoration:none}.dashboard-table-link:focus,.dashboard-table-link:hover{color:#999}.public-board{margin-top:5px}.public-task{max-width:800px;margin:5px auto 0}#board-container{overflow-x:auto}#board{table-layout:fixed;margin-bottom:0}#board th.board-column-header{width:240px}#board td{vertical-align:top}.board-container-compact{overflow-x:initial}@media all and (-ms-high-contrast: active), (-ms-high-contrast: none){.board-container-compact #board{table-layout:auto}}#board th.board-column-header.board-column-compact{width:initial}.board-column-collapsed{display:none}td.board-column-task-collapsed{font-weight:bold;background-color:#fbfbfb}#board th.board-column-header-collapsed{width:28px;min-width:28px;text-align:center;overflow:hidden}.board-rotation-wrapper{position:relative;padding:8px 4px;min-height:150px;overflow:hidden}.board-rotation{white-space:nowrap;-webkit-backface-visibility:hidden;-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg);-webkit-transform-origin:0 100%;-moz-transform-origin:0 100%;-ms-transform-origin:0 100%;transform-origin:0 100%}.board-column-title .dropdown-menu{text-decoration:none}.board-add-icon{float:left;padding:0 5px}.board-add-icon a{text-decoration:none;color:#36c;font-size:1.6em;line-height:70%}.board-add-icon a:focus,.board-add-icon a:hover{text-decoration:none;color:red}.board-column-header-task-count{color:#999;font-weight:normal}a.board-swimlane-toggle{text-decoration:none}a.board-swimlane-toggle:hover,a.board-swimlane-toggle:focus{color:#000;text-decoration:none;border:none}.board-task-list{min-height:60px}.board-task-list-limit{background-color:#DF5353}.draggable-item{cursor:pointer;user-select:none;-webkit-user-select:none;-moz-user-select:none}.draggable-placeholder{border:2px dashed #000;background:#fafafa;height:70px;margin-bottom:10px}div.draggable-item-selected{border:1px solid #000}.task-board-sort-handle{float:left;padding-right:5px}.task-board{position:relative;margin-bottom:4px;border:1px solid #000;padding:2px;word-wrap:break-word;font-size:0.9em}div.task-board-recent{border-width:2px}div.task-board-status-closed{user-select:none;border:1px dotted #555}.task-board a{color:#000;text-decoration:none}.task-board .dropdown-menu{font-weight:bold}.task-board .task-score{font-weight:bold}.task-board-collapsed{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.task-board-title{margin-top:5px;margin-bottom:8px}.task-board-title a:hover{text-decoration:underline}.task-board-saving-state{opacity:0.3}.task-board-saving-icon{position:absolute;margin:auto;width:100%;text-align:center;color:#000}.task-board-category-container{text-align:right;margin-top:8px;margin-bottom:8px}.task-board-category{font-weight:500;color:#000;border:1px solid #555;padding:1px 2px 1px 2px;border-radius:4px}.task-board-category:hover{opacity:0.6}.task-board-avatars{text-align:right;float:right}.task-board-change-assignee{cursor:pointer}.task-board-change-assignee:hover{opacity:0.6}.task-board-icons{font-size:0.8em;text-align:right;margin-top:4px;margin-bottom:2px}.task-board-icons a{opacity:0.5}.task-board-icons span{opacity:0.5;margin-left:2px}.task-board-icons a:hover,.task-board-icons span:hover{opacity:1.0}.flag-milestone{color:green}.task-board-age{display:inline-block}span.task-board-age-total{border:#666 1px solid;padding:1px 3px 1px 3px;border-top-left-radius:3px;border-bottom-left-radius:3px}span.task-board-age-column{border:#666 1px solid;border-left:none;margin-left:-5px;padding:1px 3px 1px 3px;border-top-right-radius:3px;border-bottom-right-radius:3px}.task-board-date{font-weight:bold;color:#000}span.task-board-date-today{opacity:1.0}span.task-board-date-overdue{opacity:1.0}.task-tags li{display:inline;margin:0;margin-right:4px;padding:2px;color:#555;border:1px solid #666;border-radius:2px}.task-summary-container .task-tags{margin-top:10px}#task-summary{margin-bottom:15px}#task-summary h2{color:#555;font-size:1.6em;margin-top:0;padding-top:0}.task-summary-container{border:2px solid #000;border-radius:8px;padding:15px}.task-summary-columns{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-justify-content:space-between;justify-content:space-between}.task-summary-column{color:#333}.task-summary-column span{color:#555}.task-summary-column li{line-height:23px}.task-show-title{border:2px solid #000;border-radius:8px;margin-bottom:20px}.task-show-title h2{color:#555;margin:0;padding:8px}.task-table .dropdown-menu{color:#000;text-decoration:none;font-weight:bold}.task-table .dropdown-menu:focus,.task-table .dropdown-menu:hover{text-decoration:underline}td.task-table a{color:#000;text-decoration:none}td.task-table a:hover{text-decoration:underline}.comment-sorting{text-align:right}.comment-sorting a{color:#555;font-weight:normal;text-decoration:none}.comment-sorting a:hover{color:#999}.comment{padding:5px;margin-bottom:15px}.comment:hover{background:#fafafa}.comment-title{border-bottom:1px dotted #eee;margin-left:55px;margin-bottom:10px}.comment-date{color:#999;font-weight:200}.comment-actions{font-size:0.8em;margin-left:55px;margin-top:8px}.comment-actions li{display:inline}.comment-actions a{color:#999;text-decoration:none}.comment-actions a:focus,.comment-actions a:hover{color:#333;text-decoration:underline}.comment-content{margin-left:55px}.subtasks-table td{vertical-align:middle}.task-links-table td{vertical-align:middle}.task-links-task-count{color:#999}.task-link-closed{text-decoration:line-through}.markdown-editor-container{max-width:400px}div.CodeMirror,div.CodeMirror-scroll{max-height:250px;min-height:200px}.markdown-editor-small div.CodeMirror,.markdown-editor-small div.CodeMirror-scroll{min-height:100px;max-height:180px}.form-column div.CodeMirror{margin-bottom:10px}.markdown{line-height:1.4em}.markdown h1{margin-top:5px;margin-bottom:10px;font-weight:bold}.markdown h2{font-weight:bold}.markdown p{margin-bottom:10px}.markdown ol,.markdown ul{margin-left:25px;margin-top:10px;margin-bottom:10px}.markdown pre{background:#fbfbfb;padding:10px;border-radius:5px;border:1px solid #ddd;overflow:auto;color:#555}.markdown blockquote{font-style:italic;border-left:3px solid #ddd;padding-left:10px;margin-bottom:10px;margin-left:20px}.markdown img{display:block;max-width:80%;margin-top:10px}.documentation{margin:0 auto;padding:20px;max-width:850px;background:#fefefe;border:1px solid #ccc;border-radius:5px;color:#555}.documentation img{border:1px solid #333}.documentation h1{text-decoration:none;margin-bottom:30px}.documentation h2{text-decoration:none;border-bottom:1px solid #ccc;margin-bottom:25px}.documentation li{line-height:30px}.listing{border-radius:4px;padding:8px 35px 8px 14px;margin-bottom:20px;border:1px solid #ddd;color:#333;background-color:#fcfcfc;overflow:auto}.listing li{list-style-type:square;margin-left:20px;margin-bottom:3px}.listing ul{margin-top:15px;margin-bottom:15px}.activity-event{margin-bottom:15px;padding:10px}.activity-event:hover{background:#fafafa}.activity-date{margin-left:10px;font-weight:normal;color:#999}.activity-content{margin-left:55px}.activity-title{font-weight:bold;color:#000;border-bottom:1px dotted #efefef}.activity-description{color:#555;margin-top:10px}.activity-description li{list-style-type:circle}.activity-description ul{margin-top:10px;margin-left:20px}div.ganttview-hzheader-month,div.ganttview-hzheader-day,div.ganttview-vtheader,div.ganttview-vtheader-item-name,div.ganttview-vtheader-series,div.ganttview-grid,div.ganttview-grid-row-cell{float:left}div.ganttview-hzheader-month,div.ganttview-hzheader-day{text-align:center}div.ganttview-grid-row-cell.last,div.ganttview-hzheader-day.last,div.ganttview-hzheader-month.last{border-right:none}div.ganttview{border:1px solid #999}div.ganttview-hzheader-month{width:60px;height:20px;border-right:1px solid #d0d0d0;line-height:20px;overflow:hidden}div.ganttview-hzheader-day{width:20px;height:20px;border-right:1px solid #f0f0f0;border-top:1px solid #d0d0d0;line-height:20px;color:#555}div.ganttview-vtheader{margin-top:41px;width:400px;overflow:hidden;background-color:#fff}div.ganttview-vtheader-item{color:#555}div.ganttview-vtheader-series-name{width:400px;height:31px;line-height:31px;padding-left:3px;border-top:1px solid #d0d0d0;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}div.ganttview-vtheader-series-name a{color:#555;text-decoration:none}div.ganttview-vtheader-series-name a:hover{color:#333;text-decoration:underline}div.ganttview-vtheader-series-name a i{color:#000}div.ganttview-vtheader-series-name a:hover i{color:#555}div.ganttview-slide-container{overflow:auto;border-left:1px solid #999}div.ganttview-grid-row-cell{width:20px;height:31px;border-right:1px solid #f0f0f0;border-top:1px solid #f0f0f0}div.ganttview-grid-row-cell.ganttview-weekend{background-color:#fafafa}div.ganttview-blocks{margin-top:40px}div.ganttview-block-container{height:28px;padding-top:4px}div.ganttview-block{position:relative;height:25px;background-color:#E5ECF9;border:1px solid #c0c0c0;border-radius:3px}.ganttview-block-movable{cursor:move}div.ganttview-block-not-defined{border-color:#000;background-color:#000}div.ganttview-block-text{position:absolute;height:12px;font-size:0.7em;color:#999;padding:2px 3px}div.ganttview-block div.ui-resizable-handle.ui-resizable-s{bottom:-0}.user-mention-link{font-weight:bold;color:#000;text-decoration:none}.user-mention-link:hover{color:#555} +h1,li,ul,ol,table,tr,td,th,p,blockquote,body{margin:0;padding:0;font-size:100%}body{margin-left:10px;margin-right:10px;padding-bottom:10px;color:#333;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;text-rendering:optimizeLegibility}small{font-size:0.8em}hr{border:0;height:0;border-top:1px solid rgba(0,0,0,0.1);border-bottom:1px solid rgba(255,255,255,0.3)}.pull-right{text-align:right}ul.no-bullet li{list-style-type:none;margin-left:0}.chosen-select{min-height:27px}#app-loading-icon{position:fixed;right:3px;bottom:3px}.assign-me{vertical-align:bottom}a{color:#36c;border:none}a:focus{outline:0;color:#DF5353;text-decoration:none}a:hover{color:#333;text-decoration:none}h1,h2,h3{font-weight:normal;color:#333}h1{font-size:1.5em}h2{font-size:1.4em;margin-bottom:10px}h3{margin-top:10px;font-size:1.2em}table{width:100%;border-collapse:collapse;border-spacing:0;margin-bottom:20px}th{border:1px solid #eee;padding:0.5em 3px}td{border:1px solid #eee;padding:0.5em 3px;vertical-align:top}th{background:#fbfbfb;text-align:left}td li{margin-left:20px}.table-small{font-size:0.8em}th a{text-decoration:none;color:#333}th a:focus,th a:hover{text-decoration:underline}.table-fixed{table-layout:fixed;white-space:nowrap}.table-fixed th{overflow:hidden}.table-fixed td{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.table-stripped tr:nth-child(odd){background:#fefefe}.column-3{width:3%}.column-5{width:5%}.column-8{width:7.5%}.column-10{width:10%}.column-12{width:12%}.column-15{width:15%}.column-18{width:18%}.column-20{width:20%}.column-25{width:25%}.column-30{width:30%}.column-35{width:35%}.column-40{width:40%}.column-50{width:50%}.column-60{width:60%}.column-70,.column-80{width:70%}.draggable-row-handle{cursor:move;color:#dedede}.draggable-row-handle:hover{color:#333}tr.draggable-item-selected{background:#fff;border:2px solid #666;box-shadow:4px 2px 10px -4px rgba(0,0,0,0.55)}tr.draggable-item-selected td{border-top:none;border-bottom:none}tr.draggable-item-selected td:first-child{border-left:none}tr.draggable-item-selected td:last-child{border-right:none}.table-stripped tr.draggable-item-hover,tr.draggable-item-hover{background:#FEFFF2}form{margin-bottom:20px}label{cursor:pointer;display:block;margin-top:10px}input[type="number"],input[type="date"],input[type="email"],input[type="password"],input[type="text"]:not(.input-addon-field){color:#999;border:1px solid #ccc;width:300px;max-width:95%;font-size:1em;height:25px;padding-bottom:0;font-family:sans-serif;margin-top:10px;-webkit-appearance:none;-moz-appearance:none}input[type="number"]:focus,input[type="date"]:focus,input[type="email"]:focus,input[type="password"]:focus,input[type="text"]:focus{color:#000;border-color:rgba(82,168,236,0.8);outline:0;box-shadow:0 0 8px rgba(82,168,236,0.6)}input[type="number"]{width:70px}input[type="text"]:not(.input-addon-field).form-numeric{width:70px}input[type="text"]:not(.input-addon-field).form-datetime,input[type="text"]:not(.input-addon-field).form-date{width:150px}input[type="text"]:not(.input-addon-field).form-input-large{width:400px}input[type="text"]:not(.input-addon-field).form-input-small{width:150px}textarea:focus{color:#000;border-color:rgba(82,168,236,0.8);outline:0;box-shadow:0 0 8px rgba(82,168,236,0.6)}textarea{border:1px solid #ccc;width:400px;max-width:99%;height:200px;font-family:sans-serif}select{max-width:95%}select:focus{outline:0}.tag-autocomplete{width:400px}span.select2-container{margin-top:2px}::-webkit-input-placeholder,::-ms-input-placeholder,::-moz-placeholder{color:#999;opacity:0.2;padding-top:2px}.form-actions{padding-top:20px;clear:both}input.form-error,textarea.form-error{border:2px solid #b94a48}input.form-error:focus,textarea.form-error:focus{box-shadow:none;border:2px solid #b94a48}.form-required{color:red;padding-left:5px;font-weight:bold}.form-errors{color:#b94a48;list-style-type:none}ul.form-errors li{margin-left:0}.form-help{font-size:0.8em;color:brown;margin-bottom:15px}.form-inline{padding:0;margin:0;border:none}.form-inline label{display:inline}.form-inline input,.form-inline select{margin:0 15px 0 0}.form-inline .form-required{display:none}.form-inline-group{display:inline}.form-columns{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row}.form-column{margin-right:25px}.form-login{width:350px;margin:8% auto 0}.form-login li{margin-left:25px;line-height:25px}.form-login h2{margin-bottom:30px;font-weight:bold}.reset-password{margin-top:20px}.reset-password a{color:#999}.input-addon{display:flex}.input-addon-field{flex:1;font-size:1em;color:#999;margin:0;-webkit-appearance:none;-moz-appearance:none}.input-addon-item{background-color:rgba(147,128,108,0.1);color:#666;font:inherit;font-weight:normal}@media (max-width: 480px){.input-addon-item .dropdown .fa-caret-down{display:none}}.input-addon-field,.input-addon-item{border:1px solid rgba(147,128,108,0.25);padding:4px 0.75em}.input-addon-field:not(:first-child),.input-addon-item:not(:first-child){border-left:0}.input-addon-field:first-child,.input-addon-item:first-child{border-radius:5px 0 0 5px}.input-addon-field:last-child,.input-addon-item:last-child{border-radius:0 5px 5px 0}.alert{padding:8px 35px 8px 14px;margin-top:5px;margin-bottom:5px;color:#c09853;background-color:#fcf8e3;border:1px solid #fbeed5;border-radius:4px}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-normal{color:#333;background-color:#f0f0f0;border-color:#ddd}.alert ul{margin-top:10px;margin-bottom:10px}.alert li{margin-left:25px}.alert-fade-out{text-align:center;position:fixed;bottom:0;left:20%;width:60%;padding-top:5px;padding-bottom:5px;margin-bottom:0;border-width:1px 0 0;border-radius:4px 4px 0 0;z-index:9999}a.btn{text-decoration:none}.btn{-webkit-appearance:none;-moz-appearance:none;font-size:1.2em;font-weight:normal;cursor:pointer;display:inline-block;border-radius:2px;padding:3px 10px;margin:0;border:1px solid #ddd;background:#f5f5f5;color:#333}.btn:hover,.btn:focus{border-color:#bbb;background:#fafafa;color:#000}.btn-red{border-color:#b0281a;background:#d14836;color:#fff}.btn-red:hover,.btn-red:focus{border-color:#b0281a;background:#c53727;color:#fff}.btn-blue{border-color:#3079ed;background:#4d90fe;color:#fff}.btn-blue:hover,.btn-blue:focus{border-color:#3079ed;background:#357ae8;color:#fff}.btn:disabled{color:#ccc;border-color:#ccc;background:#f7f7f7}.buttons-header{font-size:0.8em;margin-top:5px;margin-bottom:15px}.tooltip-arrow:after{background:#fff;border:1px solid #aaaaaa;box-shadow:0 0 5px #aaa}div.ui-tooltip{min-width:200px;max-width:600px}.tooltip-arrow{width:20px;height:10px;overflow:hidden;position:absolute}.tooltip-arrow.top{top:-10px}.tooltip-arrow.bottom{bottom:-10px}.tooltip-arrow.align-left{left:10px}.tooltip-arrow.align-right{right:10px}.tooltip-arrow:after{content:"";position:absolute;width:14px;height:14px;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg)}.tooltip-arrow.bottom:after{top:-10px}.tooltip-arrow.top:after{bottom:-10px}.tooltip-arrow.align-left:after{left:0}.tooltip-arrow.align-right:after{right:0}.tooltip-large{width:600px}.ui-tooltip-content .markdown p{margin-bottom:0}.ui-tooltip li{list-style-type:none}.tooltip .fa-info-circle{color:#999}.dropdown{display:inline;position:relative}.dropdown ul{display:none}ul.dropdown-submenu-open{display:block;position:absolute;z-index:1000;min-width:285px;list-style:none;margin:3px 0 0 1px;padding:6px 0;background-color:#fff;border:1px solid #b2b2b2;border-radius:3px;box-shadow:0 1px 3px rgba(0,0,0,0.15)}.dropdown-submenu-open li{display:block;margin:0;padding:8px 10px;font-size:0.9em;border-bottom:1px solid #f8f8f8;cursor:pointer}.dropdown-submenu-open li.no-hover{cursor:default}.dropdown-submenu-open li:last-child{border:none}.dropdown-submenu-open li:not(.no-hover):hover{background:#4078C0;color:#fff}.dropdown-submenu-open li:hover a{color:#fff}.dropdown-submenu-open a{text-decoration:none;color:#333}.dropdown-submenu-open a:focus{text-decoration:underline}.dropdown-menu-link-text,.dropdown-menu-link-icon{color:#333;text-decoration:none}.dropdown-menu-link-text:hover{text-decoration:underline}.accordion-title{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAADCAYAAABS3WWCAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NEQ5RDgxQzc2RjQ5MTFFMjhEMUNENzFGRUMwRjhBRTciIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NEQ5RDgxQzg2RjQ5MTFFMjhEMUNENzFGRUMwRjhBRTciPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo0RDlEODFDNTZGNDkxMUUyOEQxQ0Q3MUZFQzBGOEFFNyIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo0RDlEODFDNjZGNDkxMUUyOEQxQ0Q3MUZFQzBGOEFFNyIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PvXFWFAAAAAYSURBVHjaYvj//z8D0/Pnz/8zgFgAAQYAS5UJscReGMIAAAAASUVORK5CYII=) repeat-x scroll 0 10px}.accordion-title h3{display:inline;padding-right:5px;background:#fff}.accordion-content{margin-top:15px;margin-bottom:25px}.accordion-toggle{color:#333;text-decoration:none}.accordion-toggle:focus{color:#333}.accordion-toggle:hover{color:#999}.accordion-toggle:before{content:"\f0d7"}.accordion-collapsed{margin-bottom:25px}.accordion-collapsed .accordion-toggle:before{content:"\f0da"}.accordion-collapsed .accordion-content{display:none}#main .confirm{max-width:700px}#popover-container{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.8);overflow:auto;z-index:100}#popover-content{position:absolute;width:70%;left:15%;top:1%;padding:15px;background:#fff;overflow:auto;max-height:90%}.popover-form{margin-bottom:0}.pagination{text-align:center}.pagination-next{margin-left:5px}.pagination-previous{margin-right:5px}header{box-sizing:border-box;display:flex;flex-wrap:wrap;margin-top:5px;margin-bottom:5px;border-bottom:1px solid #dedede}header>*{box-sizing:border-box}header>*{width:1%}header .menus-container{width:10%}@media (min-width: 768px) and (max-width: 1150px){header .menus-container{width:15%}}@media (max-width: 768px){header .menus-container{width:65%;order:2}}header .board-selector-container{width:15%}@media (min-width: 768px) and (max-width: 1150px){header .board-selector-container{width:20%}}@media (max-width: 768px){header .board-selector-container{width:35%;order:1;margin-bottom:5px}}header .title-container{width:75%}@media (min-width: 768px) and (max-width: 1150px){header .title-container{width:65%}}@media (max-width: 768px){header .title-container{width:100%;order:3}}header h1{font-size:1.5em}header h1 .tooltip{opacity:0.3;font-size:0.7em}.web-notification-icon{color:#36c}.web-notification-icon:focus,.web-notification-icon:hover{color:#000}.logo a{opacity:0.5;color:#d40000;text-decoration:none}.logo span{color:#333}.logo a:hover{opacity:0.8;color:#333}.logo a:focus span,.logo a:hover span{color:#d40000}.page-header{margin-bottom:20px}.page-header .dropdown{padding-right:10px}.page-header h2{margin:0;padding:0;font-weight:bold;border-bottom:1px dotted #ccc}.page-header h2 a{color:#333;text-decoration:none}.page-header h2 a:focus,.page-header h2 a:hover{color:#999}.page-header ul{text-align:left;margin-top:5px;display:inline-block}.page-header li{display:inline;padding-right:15px}.page-header li.active a{color:#333;text-decoration:none;font-weight:bold}.page-header li.active a:hover,.page-header li.active a:focus{text-decoration:underline}.menu-inline{margin-bottom:5px}.menu-inline li{display:inline;padding-right:15px}.menu-inline li .active a{font-weight:bold;color:#000;text-decoration:none}.sidebar-container{margin-top:10px;height:100%;width:100%;display:-ms-flexbox;display:-webkit-box;display:-moz-box;display:-ms-box;display:box;-ms-flex-direction:row;-webkit-box-orient:horizontal;-moz-box-orient:horizontal;-ms-box-orient:horizontal;box-orient:horizontal}.sidebar-content{padding-left:10px;-ms-flex:1;-webkit-box-flex:1;-moz-box-flex:1;-ms-box-flex:1;box-flex:1}.sidebar{padding-right:10px;border-right:1px dotted #eee;max-width:240px;min-width:190px;width:18%;-ms-flex:0 100px;-webkit-box-flex:0;-moz-box-flex:0;-ms-box-flex:0;box-flex:0}.sidebar h2{margin-top:0}.sidebar>ul a{text-decoration:none;color:#999;font-weight:300}.sidebar>ul a:hover{color:#333}.sidebar>ul li{list-style-type:none;line-height:35px;border-bottom:1px dotted #efefef;padding-left:13px}.sidebar>ul li:hover{border-left:5px solid #555;padding-left:8px}.sidebar>ul li.active{border-left:5px solid #333;padding-left:8px}.sidebar>ul li.active a{color:#333;font-weight:bold}.sidebar-icons>ul li{padding-left:0}.sidebar-icons>ul li:hover,.sidebar-icons>ul li.active{padding-left:0;border-left:none}.sidebar>ul li.active a:focus,.sidebar>ul li.active a:hover{color:#555}.sidebar>ul li:last-child{margin-bottom:15px}.avatar img{vertical-align:bottom}.avatar-left{float:left;margin-right:10px}.avatar-inline{display:inline-block;margin-right:3px}.avatar-48 img,.avatar-48 div{border-radius:30px}.avatar-48 .avatar-letter{line-height:48px;width:48px;font-size:25px}.avatar-20 img,.avatar-20 div{border-radius:10px}.avatar-20 .avatar-letter{line-height:20px;width:20px;font-size:11px}.avatar-letter{color:#fff;text-align:center}#file-dropzone,#screenshot-zone{position:relative;border:2px dashed #ccc;width:99%;height:250px;overflow:auto}#file-dropzone-inner,#screenshot-inner{position:absolute;left:0;bottom:48%;width:100%;text-align:center;color:#aaa}#screenshot-zone.screenshot-pasted{border:2px solid #333}#file-list{margin:20px}#file-list li{list-style-type:none;padding-top:8px;padding-bottom:8px;border-bottom:1px dotted #ddd;width:95%}#file-list li.file-error{font-weight:bold;color:#b94a48}.color-picker{width:180px}.color-picker-option{height:25px}.color-picker-square{display:inline-block;width:18px;height:18px;margin-right:5px;border:1px solid #000}.color-picker-label{display:inline-block;vertical-align:bottom;padding-bottom:3px}.file-thumbnails{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;flex-wrap:wrap;-webkit-justify-content:flex-start;justify-content:flex-start}.file-thumbnail{width:250px;border:1px solid #efefef;border-radius:5px;margin-bottom:20px;box-shadow:4px 2px 10px -6px rgba(0,0,0,0.55);margin-right:15px}.file-thumbnail img{border-top-left-radius:5px;border-top-right-radius:5px}.file-thumbnail img:hover{opacity:0.5}.file-thumbnail-content{padding-left:8px;padding-right:8px}.file-thumbnail-title{font-weight:700;font-size:0.9em;color:#555}.file-thumbnail-description{font-size:0.8em;color:#999;margin-top:8px;margin-bottom:5px}.file-viewer{position:relative}.file-viewer img{max-width:95%;max-height:85%;margin-top:10px}.filter-box{max-width:800px}.project-header{margin-top:8px;margin-bottom:20px}.action-menu{color:#333;text-decoration:none}.action-menu:hover,.action-menu:focus{text-decoration:underline}.project-creation-options{max-width:500px;border-left:3px dotted #efefef;margin-top:20px;padding-left:15px;padding-bottom:5px;padding-top:5px}.project-overview-columns{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;align-items:center;-webkit-justify-content:center;justify-content:center;margin-bottom:20px;font-size:1.4em}.project-overview-column{text-align:center;margin-right:3%;padding:3px 15px 3px 15px;border:1px dashed #ddd}.project-overview-column small{color:#999}.project-overview-column strong{color:#555}.project-header{box-sizing:border-box;display:flex;flex-wrap:wrap}.project-header>*{box-sizing:border-box}.project-header>*{width:1%}.project-header .dropdown-component{width:5%}@media (min-width: 768px) and (max-width: 1150px){.project-header .dropdown-component{width:8%}}@media (max-width: 768px){.project-header .dropdown-component{width:100%}}.project-header .views-switcher-component{width:38%}@media (max-width: 1300px){.project-header .views-switcher-component{width:45%}}@media (min-width: 768px) and (max-width: 1150px){.project-header .views-switcher-component{width:92%}}@media (max-width: 768px){.project-header .views-switcher-component{width:100%}}.project-header .filter-box-component{margin:0;width:55%}@media (max-width: 1300px){.project-header .filter-box-component{width:50%}}@media (min-width: 768px) and (max-width: 1150px){.project-header .filter-box-component{width:100%;margin-top:10px}.project-header .filter-box-component .filter-box{max-width:100%}}@media (max-width: 768px){.project-header .filter-box-component{width:100%;margin-top:10px}.project-header .filter-box-component .filter-box{max-width:100%}}.project-header .filter-box-component form{margin:0}.views{display:inline-block;margin-right:10px;font-size:0.9em}@media (max-width: 560px){.views{width:100%}}@media (max-width: 768px){.views{margin-top:10px;font-size:1em}}.views li{white-space:nowrap;background:#fafafa;border:1px solid #ddd;border-right:none;padding:4px 8px;display:inline}@media (max-width: 560px){.views li{display:block;margin-top:5px;border-radius:5px;border:1px solid #ddd}}.views li.active a{font-weight:bold;color:#000;text-decoration:none}.views li:first-child{border-top-left-radius:5px;border-bottom-left-radius:5px}.views li:last-child{border-right:1px solid #ddd;border-top-right-radius:5px;border-bottom-right-radius:5px}.views a{color:#555;text-decoration:none}.views a:hover{color:#333;text-decoration:underline}.dashboard-project-stats small{margin-right:10px;color:#999}.dashboard-table-link{font-weight:bold;color:#000;text-decoration:none}.dashboard-table-link:focus,.dashboard-table-link:hover{color:#999}.public-board{margin-top:5px}.public-task{max-width:800px;margin:5px auto 0}#board-container{overflow-x:auto}#board{table-layout:fixed;margin-bottom:0}#board th.board-column-header{width:240px}#board td{vertical-align:top}.board-container-compact{overflow-x:initial}@media all and (-ms-high-contrast: active), (-ms-high-contrast: none){.board-container-compact #board{table-layout:auto}}#board th.board-column-header.board-column-compact{width:initial}.board-column-collapsed{display:none}td.board-column-task-collapsed{font-weight:bold;background-color:#fbfbfb}#board th.board-column-header-collapsed{width:28px;min-width:28px;text-align:center;overflow:hidden}.board-rotation-wrapper{position:relative;padding:8px 4px;min-height:150px;overflow:hidden}.board-rotation{white-space:nowrap;-webkit-backface-visibility:hidden;-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg);-webkit-transform-origin:0 100%;-moz-transform-origin:0 100%;-ms-transform-origin:0 100%;transform-origin:0 100%}.board-column-title .dropdown-menu{text-decoration:none}.board-add-icon{float:left;padding:0 5px}.board-add-icon a{text-decoration:none;color:#36c;font-size:1.6em;line-height:70%}.board-add-icon a:focus,.board-add-icon a:hover{text-decoration:none;color:red}.board-column-header-task-count{color:#999;font-weight:normal}a.board-swimlane-toggle{text-decoration:none}a.board-swimlane-toggle:hover,a.board-swimlane-toggle:focus{color:#000;text-decoration:none;border:none}.board-task-list{min-height:60px}.board-task-list-limit{background-color:#DF5353}.draggable-item{cursor:pointer;user-select:none;-webkit-user-select:none;-moz-user-select:none}.draggable-placeholder{border:2px dashed #000;background:#fafafa;height:70px;margin-bottom:10px}div.draggable-item-selected{border:1px solid #000}.task-board-sort-handle{float:left;padding-right:5px}.task-board{position:relative;margin-bottom:4px;border:1px solid #000;padding:2px;word-wrap:break-word;font-size:0.9em}div.task-board-recent{border-width:2px}div.task-board-status-closed{user-select:none;border:1px dotted #555}.task-board a{color:#000;text-decoration:none}.task-board .dropdown-menu{font-weight:bold}.task-board .task-score{font-weight:bold}.task-board-collapsed{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.task-board-title{margin-top:5px;margin-bottom:8px}.task-board-title a:hover{text-decoration:underline}.task-board-saving-state{opacity:0.3}.task-board-saving-icon{position:absolute;margin:auto;width:100%;text-align:center;color:#000}.task-board-category-container{text-align:right;margin-top:8px;margin-bottom:8px}.task-board-category{font-weight:500;color:#000;border:1px solid #555;padding:1px 2px 1px 2px;border-radius:4px}.task-board-category:hover{opacity:0.6}.task-board-avatars{text-align:right;float:right}.task-board-change-assignee{cursor:pointer}.task-board-change-assignee:hover{opacity:0.6}.task-board-icons{font-size:0.8em;text-align:right;margin-top:4px;margin-bottom:2px}.task-board-icons a{opacity:0.5}.task-board-icons span{opacity:0.5;margin-left:2px}.task-board-icons a:hover,.task-board-icons span:hover{opacity:1.0}.flag-milestone{color:green}.task-board-age{display:inline-block}span.task-board-age-total{border:#666 1px solid;padding:1px 3px 1px 3px;border-top-left-radius:3px;border-bottom-left-radius:3px}span.task-board-age-column{border:#666 1px solid;border-left:none;margin-left:-5px;padding:1px 3px 1px 3px;border-top-right-radius:3px;border-bottom-right-radius:3px}.task-board-date{font-weight:bold;color:#000}span.task-board-date-today{opacity:1.0}span.task-board-date-overdue{opacity:1.0}.task-tags li{display:inline;margin:0;margin-right:4px;padding:2px;color:#555;border:1px solid #666;border-radius:2px}.task-summary-container .task-tags{margin-top:10px}#task-summary{margin-bottom:15px}#task-summary h2{color:#555;font-size:1.6em;margin-top:0;padding-top:0}.task-summary-container{border:2px solid #000;border-radius:8px;padding:15px}.task-summary-columns{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-justify-content:space-between;justify-content:space-between}.task-summary-column{color:#333}.task-summary-column span{color:#555}.task-summary-column li{line-height:23px}.task-show-title{border:2px solid #000;border-radius:8px;margin-bottom:20px}.task-show-title h2{color:#555;margin:0;padding:8px}.task-table .dropdown-menu{color:#000;text-decoration:none;font-weight:bold}.task-table .dropdown-menu:focus,.task-table .dropdown-menu:hover{text-decoration:underline}td.task-table a{color:#000;text-decoration:none}td.task-table a:hover{text-decoration:underline}.comment-sorting{text-align:right}.comment-sorting a{color:#555;font-weight:normal;text-decoration:none}.comment-sorting a:hover{color:#999}.comment{padding:5px;margin-bottom:15px}.comment:hover{background:#fafafa}.comment-title{border-bottom:1px dotted #eee;margin-left:55px;margin-bottom:10px}.comment-date{color:#999;font-weight:200}.comment-actions{font-size:0.8em;margin-left:55px;margin-top:8px}.comment-actions li{display:inline}.comment-actions a{color:#999;text-decoration:none}.comment-actions a:focus,.comment-actions a:hover{color:#333;text-decoration:underline}.comment-content{margin-left:55px}.subtasks-table td{vertical-align:middle}.task-links-table td{vertical-align:middle}.task-links-task-count{color:#999}.task-link-closed{text-decoration:line-through}.markdown-editor-container{max-width:400px}div.CodeMirror,div.CodeMirror-scroll{max-height:250px;min-height:200px}.markdown-editor-small div.CodeMirror,.markdown-editor-small div.CodeMirror-scroll{min-height:100px;max-height:180px}.form-column div.CodeMirror{margin-bottom:10px}.markdown{line-height:1.4em}.markdown h1{margin-top:5px;margin-bottom:10px;font-weight:bold}.markdown h2{font-weight:bold}.markdown p{margin-bottom:10px}.markdown ol,.markdown ul{margin-left:25px;margin-top:10px;margin-bottom:10px}.markdown pre{background:#fbfbfb;padding:10px;border-radius:5px;border:1px solid #ddd;overflow:auto;color:#555}.markdown blockquote{font-style:italic;border-left:3px solid #ddd;padding-left:10px;margin-bottom:10px;margin-left:20px}.markdown img{display:block;max-width:80%;margin-top:10px}.documentation{margin:0 auto;padding:20px;max-width:850px;background:#fefefe;border:1px solid #ccc;border-radius:5px;color:#555}.documentation img{border:1px solid #333}.documentation h1{text-decoration:none;margin-bottom:30px}.documentation h2{text-decoration:none;border-bottom:1px solid #ccc;margin-bottom:25px}.documentation li{line-height:30px}.listing{border-radius:4px;padding:8px 35px 8px 14px;margin-bottom:20px;border:1px solid #ddd;color:#333;background-color:#fcfcfc;overflow:auto}.listing li{list-style-type:square;margin-left:20px;margin-bottom:3px}.listing ul{margin-top:15px;margin-bottom:15px}.activity-event{margin-bottom:15px;padding:10px}.activity-event:hover{background:#fafafa}.activity-date{margin-left:10px;font-weight:normal;color:#999}.activity-content{margin-left:55px}.activity-title{font-weight:bold;color:#000;border-bottom:1px dotted #efefef}.activity-description{color:#555;margin-top:10px}.activity-description li{list-style-type:circle}.activity-description ul{margin-top:10px;margin-left:20px}div.ganttview-hzheader-month,div.ganttview-hzheader-day,div.ganttview-vtheader,div.ganttview-vtheader-item-name,div.ganttview-vtheader-series,div.ganttview-grid,div.ganttview-grid-row-cell{float:left}div.ganttview-hzheader-month,div.ganttview-hzheader-day{text-align:center}div.ganttview-grid-row-cell.last,div.ganttview-hzheader-day.last,div.ganttview-hzheader-month.last{border-right:none}div.ganttview{border:1px solid #999}div.ganttview-hzheader-month{width:60px;height:20px;border-right:1px solid #d0d0d0;line-height:20px;overflow:hidden}div.ganttview-hzheader-day{width:20px;height:20px;border-right:1px solid #f0f0f0;border-top:1px solid #d0d0d0;line-height:20px;color:#555}div.ganttview-vtheader{margin-top:41px;width:400px;overflow:hidden;background-color:#fff}div.ganttview-vtheader-item{color:#555}div.ganttview-vtheader-series-name{width:400px;height:31px;line-height:31px;padding-left:3px;border-top:1px solid #d0d0d0;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}div.ganttview-vtheader-series-name a{color:#555;text-decoration:none}div.ganttview-vtheader-series-name a:hover{color:#333;text-decoration:underline}div.ganttview-vtheader-series-name a i{color:#000}div.ganttview-vtheader-series-name a:hover i{color:#555}div.ganttview-slide-container{overflow:auto;border-left:1px solid #999}div.ganttview-grid-row-cell{width:20px;height:31px;border-right:1px solid #f0f0f0;border-top:1px solid #f0f0f0}div.ganttview-grid-row-cell.ganttview-weekend{background-color:#fafafa}div.ganttview-blocks{margin-top:40px}div.ganttview-block-container{height:28px;padding-top:4px}div.ganttview-block{position:relative;height:25px;background-color:#E5ECF9;border:1px solid #c0c0c0;border-radius:3px}.ganttview-block-movable{cursor:move}div.ganttview-block-not-defined{border-color:#000;background-color:#000}div.ganttview-block-text{position:absolute;height:12px;font-size:0.7em;color:#999;padding:2px 3px}div.ganttview-block div.ui-resizable-handle.ui-resizable-s{bottom:-0}.user-mention-link{font-weight:bold;color:#000;text-decoration:none}.user-mention-link:hover{color:#555} diff --git a/assets/sass/_form.sass b/assets/sass/_form.sass index e89fdc24..e46e14d4 100644 --- a/assets/sass/_form.sass +++ b/assets/sass/_form.sass @@ -26,16 +26,25 @@ input outline: 0 box-shadow: 0 0 8px rgba(82, 168, 236, 0.6) +input[type="number"] + width: 70px + +input[type="text"]:not(.input-addon-field) + &.form-numeric + width: 70px + &.form-datetime, &.form-date + width: 150px + &.form-input-large + width: 400px + &.form-input-small + width: 150px + textarea:focus color: color('dark') border-color: rgba(82, 168, 236, 0.8) outline: 0 box-shadow: 0 0 8px rgba(82, 168, 236, 0.6) -input - &.form-numeric, &[type="number"] - width: 70px - textarea border: 1px solid #ccc width: 400px @@ -101,14 +110,6 @@ ul.form-errors li .form-inline-group display: inline -input - &.form-datetime, &.form-date - width: 150px - &.form-input-large - width: 400px - &.form-input-small - width: 150px - .form-columns display: -webkit-flex display: flex diff --git a/doc/plugin-hooks.markdown b/doc/plugin-hooks.markdown index 5e01e93a..9a4bdab2 100644 --- a/doc/plugin-hooks.markdown +++ b/doc/plugin-hooks.markdown @@ -138,6 +138,8 @@ List of reference hooks: | `formatter:board:query` | Alter database query before rendering board | | `pagination:dashboard:task:query` | Alter database query for tasks pagination on the dashboard | | `pagination:dashboard:subtask:query` | Alter database query for subtasks pagination on the dashboard | +| `model:task:creation:prepare` | Alter form values before to save a task | +| `model:task:modification:prepare` | Alter form values before to edit a task | Template Hooks @@ -186,6 +188,7 @@ List of template hooks: | `template:config:email` | Email settings page | | `template:config:integrations` | Integration page in global settings | | `template:dashboard:sidebar` | Sidebar on dashboard page | +| `template:dashboard:show` | Main page of the dashboard | | `template:export:sidebar` | Sidebar on export pages | | `template:import:sidebar` | Sidebar on import pages | | `template:header:dropdown` | Page header dropdown menu (user avatar icon) | -- cgit v1.2.3 From 2ebe8b32728c341ec16e1197fe2e12d32ddd5de5 Mon Sep 17 00:00:00 2001 From: Frederic Guillot Date: Sat, 13 Aug 2016 18:08:46 -0400 Subject: Add the possibility to attach template hooks with local variables --- ChangeLog | 1 + app/Helper/HookHelper.php | 25 +++++++++++++++------- doc/plugin-hooks.markdown | 8 +++++++ tests/units/Helper/HookHelperTest.php | 40 +++++++++++++++++++++++++++-------- 4 files changed, 57 insertions(+), 17 deletions(-) (limited to 'app') diff --git a/ChangeLog b/ChangeLog index 25ce7eea..d013ad9a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,7 @@ Version 1.0.33 (unreleased) Improvements: +* Add the possibility to attach template hooks with local variables * Add "reference" hooks * Show project name in task forms * Convert vanilla CSS to SASS diff --git a/app/Helper/HookHelper.php b/app/Helper/HookHelper.php index cb4dc1ef..418c55a0 100644 --- a/app/Helper/HookHelper.php +++ b/app/Helper/HookHelper.php @@ -24,8 +24,8 @@ class HookHelper extends Base { $buffer = ''; - foreach ($this->hook->getListeners($hook) as $file) { - $buffer .= $this->helper->asset->$type($file); + foreach ($this->hook->getListeners($hook) as $params) { + $buffer .= $this->helper->asset->$type($params['template']); } return $buffer; @@ -43,8 +43,12 @@ class HookHelper extends Base { $buffer = ''; - foreach ($this->hook->getListeners($hook) as $template) { - $buffer .= $this->template->render($template, $variables); + foreach ($this->hook->getListeners($hook) as $params) { + if (! empty($params['variables'])) { + $variables = array_merge($variables, $params['variables']); + } + + $buffer .= $this->template->render($params['template'], $variables); } return $buffer; @@ -54,13 +58,18 @@ class HookHelper extends Base * Attach a template to a hook * * @access public - * @param string $hook - * @param string $template + * @param string $hook + * @param string $template + * @param array $variables * @return $this */ - public function attach($hook, $template) + public function attach($hook, $template, array $variables = array()) { - $this->hook->on($hook, $template); + $this->hook->on($hook, array( + 'template' => $template, + 'variables' => $variables, + )); + return $this; } } diff --git a/doc/plugin-hooks.markdown b/doc/plugin-hooks.markdown index 9a4bdab2..a700e34b 100644 --- a/doc/plugin-hooks.markdown +++ b/doc/plugin-hooks.markdown @@ -153,6 +153,14 @@ Example to add new content in the dashboard sidebar: $this->template->hook->attach('template:dashboard:sidebar', 'myplugin:dashboard/sidebar'); ``` +Example to attach a template with local variables: + +```php +$this->template->hook->attach('template:dashboard:sidebar', 'myplugin:dashboard/sidebar', array( + 'variable' => 'foobar', +)); +``` + This call is usually defined in the `initialize()` method. The first argument is name of the hook and the second argument is the template name. diff --git a/tests/units/Helper/HookHelperTest.php b/tests/units/Helper/HookHelperTest.php index 6e03acd1..66d13381 100644 --- a/tests/units/Helper/HookHelperTest.php +++ b/tests/units/Helper/HookHelperTest.php @@ -6,6 +6,28 @@ use Kanboard\Helper\HookHelper; class HookHelperTest extends Base { + public function testAttachLocalVariables() + { + $this->container['template'] = $this + ->getMockBuilder('\Kanboard\Core\Template') + ->setConstructorArgs(array($this->container['helper'])) + ->setMethods(array('render')) + ->getMock(); + + $this->container['template'] + ->expects($this->once()) + ->method('render') + ->with( + $this->equalTo('tpl1'), + $this->equalTo(array('k0' => 'v0', 'k1' => 'v1')) + ) + ->will($this->returnValue('tpl1_content')); + + $hookHelper = new HookHelper($this->container); + $hookHelper->attach('test', 'tpl1', array('k1' => 'v1')); + $this->assertEquals('tpl1_content', $hookHelper->render('test', array('k0' => 'v0'))); + } + public function testMultipleHooks() { $this->container['template'] = $this @@ -32,10 +54,10 @@ class HookHelperTest extends Base ) ->will($this->returnValue('tpl2_content')); - $h = new HookHelper($this->container); - $h->attach('test', 'tpl1'); - $h->attach('test', 'tpl2'); - $this->assertEquals('tpl1_contenttpl2_content', $h->render('test')); + $hookHelper = new HookHelper($this->container); + $hookHelper->attach('test', 'tpl1'); + $hookHelper->attach('test', 'tpl2'); + $this->assertEquals('tpl1_contenttpl2_content', $hookHelper->render('test')); } public function testAssetHooks() @@ -64,11 +86,11 @@ class HookHelperTest extends Base ) ->will($this->returnValue('')); - $h = new HookHelper($this->container); - $h->attach('test1', 'skin.css'); - $h->attach('test2', 'skin.js'); + $hookHelper = new HookHelper($this->container); + $hookHelper->attach('test1', 'skin.css'); + $hookHelper->attach('test2', 'skin.js'); - $this->assertContains('', $h->asset('css', 'test1')); - $this->assertContains('', $h->asset('js', 'test2')); + $this->assertContains('', $hookHelper->asset('css', 'test1')); + $this->assertContains('', $hookHelper->asset('js', 'test2')); } } -- cgit v1.2.3 From 010199e8f846f6c0b4f23336338bfda17ec04901 Mon Sep 17 00:00:00 2001 From: Frederic Guillot Date: Sat, 13 Aug 2016 18:41:01 -0400 Subject: Add the possibility to attach template hooks with a callback --- ChangeLog | 2 +- app/Helper/HookHelper.php | 27 +++++++++++++++++++ doc/plugin-hooks.markdown | 8 ++++++ tests/units/Helper/HookHelperTest.php | 51 +++++++++++++++++++++++++++++++++++ 4 files changed, 87 insertions(+), 1 deletion(-) (limited to 'app') diff --git a/ChangeLog b/ChangeLog index d013ad9a..25a92168 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,7 +3,7 @@ Version 1.0.33 (unreleased) Improvements: -* Add the possibility to attach template hooks with local variables +* Add the possibility to attach template hooks with local variables and callback * Add "reference" hooks * Show project name in task forms * Convert vanilla CSS to SASS diff --git a/app/Helper/HookHelper.php b/app/Helper/HookHelper.php index 418c55a0..e43cfdfd 100644 --- a/app/Helper/HookHelper.php +++ b/app/Helper/HookHelper.php @@ -46,6 +46,12 @@ class HookHelper extends Base foreach ($this->hook->getListeners($hook) as $params) { if (! empty($params['variables'])) { $variables = array_merge($variables, $params['variables']); + } elseif (! empty($params['callable'])) { + $result = call_user_func_array($params['callable'], $variables); + + if (is_array($result)) { + $variables = array_merge($variables, $result); + } } $buffer .= $this->template->render($params['template'], $variables); @@ -72,4 +78,25 @@ class HookHelper extends Base return $this; } + + /** + * Attach a template to a hook with a callable + * + * Arguments passed to the callback are the one passed to the hook + * + * @access public + * @param string $hook + * @param string $template + * @param callable $callable + * @return $this + */ + public function attachCallable($hook, $template, callable $callable) + { + $this->hook->on($hook, array( + 'template' => $template, + 'callable' => $callable, + )); + + return $this; + } } diff --git a/doc/plugin-hooks.markdown b/doc/plugin-hooks.markdown index a700e34b..97816d5f 100644 --- a/doc/plugin-hooks.markdown +++ b/doc/plugin-hooks.markdown @@ -161,6 +161,14 @@ $this->template->hook->attach('template:dashboard:sidebar', 'myplugin:dashboard/ )); ``` +Example to attach a template with a callable: + +```php +$this->template->hook->attach('template:dashboard:sidebar', 'myplugin:dashboard/sidebar', function($hook_param1, $hook_param2) { + return array('new_template_variable' => 'foobar'); // Inject a new variable into the plugin template +}); +``` + This call is usually defined in the `initialize()` method. The first argument is name of the hook and the second argument is the template name. diff --git a/tests/units/Helper/HookHelperTest.php b/tests/units/Helper/HookHelperTest.php index 66d13381..a67eaed9 100644 --- a/tests/units/Helper/HookHelperTest.php +++ b/tests/units/Helper/HookHelperTest.php @@ -6,6 +6,57 @@ use Kanboard\Helper\HookHelper; class HookHelperTest extends Base { + public function testAttachCallable() + { + $this->container['template'] = $this + ->getMockBuilder('\Kanboard\Core\Template') + ->setConstructorArgs(array($this->container['helper'])) + ->setMethods(array('render')) + ->getMock(); + + $this->container['template'] + ->expects($this->once()) + ->method('render') + ->with( + $this->equalTo('tpl1'), + $this->equalTo(array('k0' => 'v0', 'k1' => 'v1')) + ) + ->will($this->returnValue('tpl1_content')); + + $hookHelper = new HookHelper($this->container); + $hookHelper->attachCallable('test', 'tpl1', function() { + return array( + 'k1' => 'v1', + ); + }); + + $this->assertEquals('tpl1_content', $hookHelper->render('test', array('k0' => 'v0'))); + } + + public function testAttachCallableWithNoResult() + { + $this->container['template'] = $this + ->getMockBuilder('\Kanboard\Core\Template') + ->setConstructorArgs(array($this->container['helper'])) + ->setMethods(array('render')) + ->getMock(); + + $this->container['template'] + ->expects($this->once()) + ->method('render') + ->with( + $this->equalTo('tpl1'), + $this->equalTo(array('k0' => 'v0')) + ) + ->will($this->returnValue('tpl1_content')); + + $hookHelper = new HookHelper($this->container); + $hookHelper->attachCallable('test', 'tpl1', function() { + }); + + $this->assertEquals('tpl1_content', $hookHelper->render('test', array('k0' => 'v0'))); + } + public function testAttachLocalVariables() { $this->container['template'] = $this -- cgit v1.2.3 From 4520026e91ca0e601f48ff6f3a16f42354257f91 Mon Sep 17 00:00:00 2001 From: Frederic Guillot Date: Sat, 13 Aug 2016 19:19:55 -0400 Subject: Replace SQL query by a PicoDB query --- app/Model/TaskFinderModel.php | 78 ++++++++++--------------------- tests/units/Model/TaskFinderModelTest.php | 61 ++++++++++++++++++++++++ 2 files changed, 85 insertions(+), 54 deletions(-) (limited to 'app') diff --git a/app/Model/TaskFinderModel.php b/app/Model/TaskFinderModel.php index 924f339b..3c32e140 100644 --- a/app/Model/TaskFinderModel.php +++ b/app/Model/TaskFinderModel.php @@ -2,7 +2,6 @@ namespace Kanboard\Model; -use PDO; use Kanboard\Core\Base; /** @@ -298,59 +297,30 @@ class TaskFinderModel extends Base */ public function getDetails($task_id) { - $sql = ' - SELECT - tasks.id, - tasks.reference, - tasks.title, - tasks.description, - tasks.date_creation, - tasks.date_completed, - tasks.date_modification, - tasks.date_due, - tasks.date_started, - tasks.time_estimated, - tasks.time_spent, - tasks.color_id, - tasks.project_id, - tasks.column_id, - tasks.owner_id, - tasks.creator_id, - tasks.position, - tasks.is_active, - tasks.score, - tasks.category_id, - tasks.priority, - tasks.swimlane_id, - tasks.date_moved, - tasks.recurrence_status, - tasks.recurrence_trigger, - tasks.recurrence_factor, - tasks.recurrence_timeframe, - tasks.recurrence_basedate, - tasks.recurrence_parent, - tasks.recurrence_child, - project_has_categories.name AS category_name, - swimlanes.name AS swimlane_name, - projects.name AS project_name, - projects.default_swimlane, - columns.title AS column_title, - users.username AS assignee_username, - users.name AS assignee_name, - creators.username AS creator_username, - creators.name AS creator_name - FROM tasks - LEFT JOIN users ON users.id = tasks.owner_id - LEFT JOIN users AS creators ON creators.id = tasks.creator_id - LEFT JOIN project_has_categories ON project_has_categories.id = tasks.category_id - LEFT JOIN projects ON projects.id = tasks.project_id - LEFT JOIN columns ON columns.id = tasks.column_id - LEFT JOIN swimlanes ON swimlanes.id = tasks.swimlane_id - WHERE tasks.id = ? - '; - - $rq = $this->db->execute($sql, array($task_id)); - return $rq->fetch(PDO::FETCH_ASSOC); + return $this->db->table(TaskModel::TABLE) + ->columns( + TaskModel::TABLE.'.*', + CategoryModel::TABLE.'.name AS category_name', + SwimlaneModel::TABLE.'.name AS swimlane_name', + ProjectModel::TABLE.'.name AS project_name', + ProjectModel::TABLE.'.default_swimlane', + ColumnModel::TABLE.'.title AS column_title', + UserModel::TABLE.'.username AS assignee_username', + UserModel::TABLE.'.name AS assignee_name', + 'uc.username AS creator_username', + 'uc.name AS creator_name', + CategoryModel::TABLE.'.description AS category_description', + ColumnModel::TABLE.'.position AS column_position', + ProjectModel::TABLE.'.default_swimlane' + ) + ->join(UserModel::TABLE, 'id', 'owner_id', TaskModel::TABLE) + ->left(UserModel::TABLE, 'uc', 'id', TaskModel::TABLE, 'creator_id') + ->join(CategoryModel::TABLE, 'id', 'category_id', TaskModel::TABLE) + ->join(ColumnModel::TABLE, 'id', 'column_id', TaskModel::TABLE) + ->join(SwimlaneModel::TABLE, 'id', 'swimlane_id', TaskModel::TABLE) + ->join(ProjectModel::TABLE, 'id', 'project_id', TaskModel::TABLE) + ->eq(TaskModel::TABLE.'.id', $task_id) + ->findOne(); } /** diff --git a/tests/units/Model/TaskFinderModelTest.php b/tests/units/Model/TaskFinderModelTest.php index b2e2bd84..a9f018ff 100644 --- a/tests/units/Model/TaskFinderModelTest.php +++ b/tests/units/Model/TaskFinderModelTest.php @@ -6,9 +6,70 @@ use Kanboard\Model\ColumnModel; use Kanboard\Model\TaskCreationModel; use Kanboard\Model\TaskFinderModel; use Kanboard\Model\ProjectModel; +use Kanboard\Model\TaskModel; class TaskFinderModelTest extends Base { + public function testGetDetails() + { + $taskCreationModel = new TaskCreationModel($this->container); + $taskFinderModel = new TaskFinderModel($this->container); + $projectModel = new ProjectModel($this->container); + $categoryModel = new \Kanboard\Model\CategoryModel($this->container); + + $this->assertEquals(1, $projectModel->create(array('name' => 'Project #1'))); + $this->assertEquals(1, $categoryModel->create(array('project_id' => 1, 'name' => 'C1'))); + $this->assertEquals(1, $taskCreationModel->create(array( + 'project_id' => 1, + 'title' => 'Task #1', + 'reference' => 'test', + 'description' => 'desc', + 'owner_id' => 1, + 'category_id' => 1, + ))); + + $task = $taskFinderModel->getDetails(1); + $this->assertEquals(1, $task['id']); + $this->assertEquals('test', $task['reference']); + $this->assertEquals('Task #1', $task['title']); + $this->assertEquals('desc', $task['description']); + $this->assertEquals(time(), $task['date_creation'], 'Delta', 1); + $this->assertEquals(time(), $task['date_modification'], 'Delta', 1); + $this->assertEquals(time(), $task['date_moved'], 'Delta', 1); + $this->assertEquals(0, $task['date_completed']); + $this->assertEquals(0, $task['date_due']); + $this->assertEquals(0, $task['date_started']); + $this->assertEquals(0, $task['time_estimated']); + $this->assertEquals(0, $task['time_spent']); + $this->assertEquals('yellow', $task['color_id']); + $this->assertEquals(1, $task['project_id']); + $this->assertEquals(1, $task['column_id']); + $this->assertEquals(1, $task['owner_id']); + $this->assertEquals(0, $task['creator_id']); + $this->assertEquals(1, $task['position']); + $this->assertEquals(TaskModel::STATUS_OPEN, $task['is_active']); + $this->assertEquals(0, $task['score']); + $this->assertEquals(1, $task['category_id']); + $this->assertEquals(0, $task['priority']); + $this->assertEquals(0, $task['swimlane_id']); + $this->assertEquals(TaskModel::RECURRING_STATUS_NONE, $task['recurrence_status']); + $this->assertEquals(TaskModel::RECURRING_TRIGGER_FIRST_COLUMN, $task['recurrence_trigger']); + $this->assertEquals(0, $task['recurrence_factor']); + $this->assertEquals(TaskModel::RECURRING_TIMEFRAME_DAYS, $task['recurrence_timeframe']); + $this->assertEquals(TaskModel::RECURRING_BASEDATE_DUEDATE, $task['recurrence_basedate']); + $this->assertEquals(0, $task['recurrence_parent']); + $this->assertEquals(0, $task['recurrence_child']); + $this->assertEquals('C1', $task['category_name']); + $this->assertNull($task['swimlane_name']); + $this->assertEquals('Default swimlane', $task['default_swimlane']); + $this->assertEquals('Project #1', $task['project_name']); + $this->assertEquals('Backlog', $task['column_title']); + $this->assertEquals('admin', $task['assignee_username']); + $this->assertEquals('', $task['assignee_name']); + $this->assertEquals('', $task['creator_username']); + $this->assertEquals('', $task['creator_name']); + } + public function testGetTasksForDashboardWithHiddenColumn() { $taskCreationModel = new TaskCreationModel($this->container); -- cgit v1.2.3 From a631b76175e1bbb0a2d752cd395ef1295fa435b5 Mon Sep 17 00:00:00 2001 From: Frederic Guillot Date: Sat, 13 Aug 2016 19:34:21 -0400 Subject: Remove fixed table on dashboard and improve input placeholders --- app/Template/dashboard/projects.php | 2 +- app/Template/dashboard/subtasks.php | 2 +- app/Template/dashboard/tasks.php | 4 ++-- assets/css/app.min.css | 2 +- assets/sass/_form.sass | 8 +++----- assets/sass/_mixins.sass | 10 ++++++++++ assets/sass/_variables.sass | 2 +- 7 files changed, 19 insertions(+), 11 deletions(-) (limited to 'app') diff --git a/app/Template/dashboard/projects.php b/app/Template/dashboard/projects.php index 975ace44..77fb0bed 100644 --- a/app/Template/dashboard/projects.php +++ b/app/Template/dashboard/projects.php @@ -4,7 +4,7 @@ isEmpty()): ?>

- +
diff --git a/app/Template/dashboard/subtasks.php b/app/Template/dashboard/subtasks.php index ca550e4c..0a9f305b 100644 --- a/app/Template/dashboard/subtasks.php +++ b/app/Template/dashboard/subtasks.php @@ -4,7 +4,7 @@ isEmpty()): ?>

-
order('Id', \Kanboard\Model\ProjectModel::TABLE.'.id') ?> order('', \Kanboard\Model\ProjectModel::TABLE.'.is_private') ?>
+
diff --git a/app/Template/dashboard/tasks.php b/app/Template/dashboard/tasks.php index d9cb4f9e..d0e731d6 100644 --- a/app/Template/dashboard/tasks.php +++ b/app/Template/dashboard/tasks.php @@ -4,12 +4,12 @@ isEmpty()): ?>

-
order('Id', \Kanboard\Model\TaskModel::TABLE.'.id') ?> order(t('Project'), 'project_name') ?>
+
- + diff --git a/assets/css/app.min.css b/assets/css/app.min.css index 5570afec..db42e67c 100644 --- a/assets/css/app.min.css +++ b/assets/css/app.min.css @@ -1 +1 @@ -h1,li,ul,ol,table,tr,td,th,p,blockquote,body{margin:0;padding:0;font-size:100%}body{margin-left:10px;margin-right:10px;padding-bottom:10px;color:#333;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;text-rendering:optimizeLegibility}small{font-size:0.8em}hr{border:0;height:0;border-top:1px solid rgba(0,0,0,0.1);border-bottom:1px solid rgba(255,255,255,0.3)}.pull-right{text-align:right}ul.no-bullet li{list-style-type:none;margin-left:0}.chosen-select{min-height:27px}#app-loading-icon{position:fixed;right:3px;bottom:3px}.assign-me{vertical-align:bottom}a{color:#36c;border:none}a:focus{outline:0;color:#DF5353;text-decoration:none}a:hover{color:#333;text-decoration:none}h1,h2,h3{font-weight:normal;color:#333}h1{font-size:1.5em}h2{font-size:1.4em;margin-bottom:10px}h3{margin-top:10px;font-size:1.2em}table{width:100%;border-collapse:collapse;border-spacing:0;margin-bottom:20px}th{border:1px solid #eee;padding:0.5em 3px}td{border:1px solid #eee;padding:0.5em 3px;vertical-align:top}th{background:#fbfbfb;text-align:left}td li{margin-left:20px}.table-small{font-size:0.8em}th a{text-decoration:none;color:#333}th a:focus,th a:hover{text-decoration:underline}.table-fixed{table-layout:fixed;white-space:nowrap}.table-fixed th{overflow:hidden}.table-fixed td{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.table-stripped tr:nth-child(odd){background:#fefefe}.column-3{width:3%}.column-5{width:5%}.column-8{width:7.5%}.column-10{width:10%}.column-12{width:12%}.column-15{width:15%}.column-18{width:18%}.column-20{width:20%}.column-25{width:25%}.column-30{width:30%}.column-35{width:35%}.column-40{width:40%}.column-50{width:50%}.column-60{width:60%}.column-70,.column-80{width:70%}.draggable-row-handle{cursor:move;color:#dedede}.draggable-row-handle:hover{color:#333}tr.draggable-item-selected{background:#fff;border:2px solid #666;box-shadow:4px 2px 10px -4px rgba(0,0,0,0.55)}tr.draggable-item-selected td{border-top:none;border-bottom:none}tr.draggable-item-selected td:first-child{border-left:none}tr.draggable-item-selected td:last-child{border-right:none}.table-stripped tr.draggable-item-hover,tr.draggable-item-hover{background:#FEFFF2}form{margin-bottom:20px}label{cursor:pointer;display:block;margin-top:10px}input[type="number"],input[type="date"],input[type="email"],input[type="password"],input[type="text"]:not(.input-addon-field){color:#999;border:1px solid #ccc;width:300px;max-width:95%;font-size:1em;height:25px;padding-bottom:0;font-family:sans-serif;margin-top:10px;-webkit-appearance:none;-moz-appearance:none}input[type="number"]:focus,input[type="date"]:focus,input[type="email"]:focus,input[type="password"]:focus,input[type="text"]:focus{color:#000;border-color:rgba(82,168,236,0.8);outline:0;box-shadow:0 0 8px rgba(82,168,236,0.6)}input[type="number"]{width:70px}input[type="text"]:not(.input-addon-field).form-numeric{width:70px}input[type="text"]:not(.input-addon-field).form-datetime,input[type="text"]:not(.input-addon-field).form-date{width:150px}input[type="text"]:not(.input-addon-field).form-input-large{width:400px}input[type="text"]:not(.input-addon-field).form-input-small{width:150px}textarea:focus{color:#000;border-color:rgba(82,168,236,0.8);outline:0;box-shadow:0 0 8px rgba(82,168,236,0.6)}textarea{border:1px solid #ccc;width:400px;max-width:99%;height:200px;font-family:sans-serif}select{max-width:95%}select:focus{outline:0}.tag-autocomplete{width:400px}span.select2-container{margin-top:2px}::-webkit-input-placeholder,::-ms-input-placeholder,::-moz-placeholder{color:#999;opacity:0.2;padding-top:2px}.form-actions{padding-top:20px;clear:both}input.form-error,textarea.form-error{border:2px solid #b94a48}input.form-error:focus,textarea.form-error:focus{box-shadow:none;border:2px solid #b94a48}.form-required{color:red;padding-left:5px;font-weight:bold}.form-errors{color:#b94a48;list-style-type:none}ul.form-errors li{margin-left:0}.form-help{font-size:0.8em;color:brown;margin-bottom:15px}.form-inline{padding:0;margin:0;border:none}.form-inline label{display:inline}.form-inline input,.form-inline select{margin:0 15px 0 0}.form-inline .form-required{display:none}.form-inline-group{display:inline}.form-columns{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row}.form-column{margin-right:25px}.form-login{width:350px;margin:8% auto 0}.form-login li{margin-left:25px;line-height:25px}.form-login h2{margin-bottom:30px;font-weight:bold}.reset-password{margin-top:20px}.reset-password a{color:#999}.input-addon{display:flex}.input-addon-field{flex:1;font-size:1em;color:#999;margin:0;-webkit-appearance:none;-moz-appearance:none}.input-addon-item{background-color:rgba(147,128,108,0.1);color:#666;font:inherit;font-weight:normal}@media (max-width: 480px){.input-addon-item .dropdown .fa-caret-down{display:none}}.input-addon-field,.input-addon-item{border:1px solid rgba(147,128,108,0.25);padding:4px 0.75em}.input-addon-field:not(:first-child),.input-addon-item:not(:first-child){border-left:0}.input-addon-field:first-child,.input-addon-item:first-child{border-radius:5px 0 0 5px}.input-addon-field:last-child,.input-addon-item:last-child{border-radius:0 5px 5px 0}.alert{padding:8px 35px 8px 14px;margin-top:5px;margin-bottom:5px;color:#c09853;background-color:#fcf8e3;border:1px solid #fbeed5;border-radius:4px}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-normal{color:#333;background-color:#f0f0f0;border-color:#ddd}.alert ul{margin-top:10px;margin-bottom:10px}.alert li{margin-left:25px}.alert-fade-out{text-align:center;position:fixed;bottom:0;left:20%;width:60%;padding-top:5px;padding-bottom:5px;margin-bottom:0;border-width:1px 0 0;border-radius:4px 4px 0 0;z-index:9999}a.btn{text-decoration:none}.btn{-webkit-appearance:none;-moz-appearance:none;font-size:1.2em;font-weight:normal;cursor:pointer;display:inline-block;border-radius:2px;padding:3px 10px;margin:0;border:1px solid #ddd;background:#f5f5f5;color:#333}.btn:hover,.btn:focus{border-color:#bbb;background:#fafafa;color:#000}.btn-red{border-color:#b0281a;background:#d14836;color:#fff}.btn-red:hover,.btn-red:focus{border-color:#b0281a;background:#c53727;color:#fff}.btn-blue{border-color:#3079ed;background:#4d90fe;color:#fff}.btn-blue:hover,.btn-blue:focus{border-color:#3079ed;background:#357ae8;color:#fff}.btn:disabled{color:#ccc;border-color:#ccc;background:#f7f7f7}.buttons-header{font-size:0.8em;margin-top:5px;margin-bottom:15px}.tooltip-arrow:after{background:#fff;border:1px solid #aaaaaa;box-shadow:0 0 5px #aaa}div.ui-tooltip{min-width:200px;max-width:600px}.tooltip-arrow{width:20px;height:10px;overflow:hidden;position:absolute}.tooltip-arrow.top{top:-10px}.tooltip-arrow.bottom{bottom:-10px}.tooltip-arrow.align-left{left:10px}.tooltip-arrow.align-right{right:10px}.tooltip-arrow:after{content:"";position:absolute;width:14px;height:14px;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg)}.tooltip-arrow.bottom:after{top:-10px}.tooltip-arrow.top:after{bottom:-10px}.tooltip-arrow.align-left:after{left:0}.tooltip-arrow.align-right:after{right:0}.tooltip-large{width:600px}.ui-tooltip-content .markdown p{margin-bottom:0}.ui-tooltip li{list-style-type:none}.tooltip .fa-info-circle{color:#999}.dropdown{display:inline;position:relative}.dropdown ul{display:none}ul.dropdown-submenu-open{display:block;position:absolute;z-index:1000;min-width:285px;list-style:none;margin:3px 0 0 1px;padding:6px 0;background-color:#fff;border:1px solid #b2b2b2;border-radius:3px;box-shadow:0 1px 3px rgba(0,0,0,0.15)}.dropdown-submenu-open li{display:block;margin:0;padding:8px 10px;font-size:0.9em;border-bottom:1px solid #f8f8f8;cursor:pointer}.dropdown-submenu-open li.no-hover{cursor:default}.dropdown-submenu-open li:last-child{border:none}.dropdown-submenu-open li:not(.no-hover):hover{background:#4078C0;color:#fff}.dropdown-submenu-open li:hover a{color:#fff}.dropdown-submenu-open a{text-decoration:none;color:#333}.dropdown-submenu-open a:focus{text-decoration:underline}.dropdown-menu-link-text,.dropdown-menu-link-icon{color:#333;text-decoration:none}.dropdown-menu-link-text:hover{text-decoration:underline}.accordion-title{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAADCAYAAABS3WWCAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NEQ5RDgxQzc2RjQ5MTFFMjhEMUNENzFGRUMwRjhBRTciIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NEQ5RDgxQzg2RjQ5MTFFMjhEMUNENzFGRUMwRjhBRTciPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo0RDlEODFDNTZGNDkxMUUyOEQxQ0Q3MUZFQzBGOEFFNyIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo0RDlEODFDNjZGNDkxMUUyOEQxQ0Q3MUZFQzBGOEFFNyIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PvXFWFAAAAAYSURBVHjaYvj//z8D0/Pnz/8zgFgAAQYAS5UJscReGMIAAAAASUVORK5CYII=) repeat-x scroll 0 10px}.accordion-title h3{display:inline;padding-right:5px;background:#fff}.accordion-content{margin-top:15px;margin-bottom:25px}.accordion-toggle{color:#333;text-decoration:none}.accordion-toggle:focus{color:#333}.accordion-toggle:hover{color:#999}.accordion-toggle:before{content:"\f0d7"}.accordion-collapsed{margin-bottom:25px}.accordion-collapsed .accordion-toggle:before{content:"\f0da"}.accordion-collapsed .accordion-content{display:none}#main .confirm{max-width:700px}#popover-container{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.8);overflow:auto;z-index:100}#popover-content{position:absolute;width:70%;left:15%;top:1%;padding:15px;background:#fff;overflow:auto;max-height:90%}.popover-form{margin-bottom:0}.pagination{text-align:center}.pagination-next{margin-left:5px}.pagination-previous{margin-right:5px}header{box-sizing:border-box;display:flex;flex-wrap:wrap;margin-top:5px;margin-bottom:5px;border-bottom:1px solid #dedede}header>*{box-sizing:border-box}header>*{width:1%}header .menus-container{width:10%}@media (min-width: 768px) and (max-width: 1150px){header .menus-container{width:15%}}@media (max-width: 768px){header .menus-container{width:65%;order:2}}header .board-selector-container{width:15%}@media (min-width: 768px) and (max-width: 1150px){header .board-selector-container{width:20%}}@media (max-width: 768px){header .board-selector-container{width:35%;order:1;margin-bottom:5px}}header .title-container{width:75%}@media (min-width: 768px) and (max-width: 1150px){header .title-container{width:65%}}@media (max-width: 768px){header .title-container{width:100%;order:3}}header h1{font-size:1.5em}header h1 .tooltip{opacity:0.3;font-size:0.7em}.web-notification-icon{color:#36c}.web-notification-icon:focus,.web-notification-icon:hover{color:#000}.logo a{opacity:0.5;color:#d40000;text-decoration:none}.logo span{color:#333}.logo a:hover{opacity:0.8;color:#333}.logo a:focus span,.logo a:hover span{color:#d40000}.page-header{margin-bottom:20px}.page-header .dropdown{padding-right:10px}.page-header h2{margin:0;padding:0;font-weight:bold;border-bottom:1px dotted #ccc}.page-header h2 a{color:#333;text-decoration:none}.page-header h2 a:focus,.page-header h2 a:hover{color:#999}.page-header ul{text-align:left;margin-top:5px;display:inline-block}.page-header li{display:inline;padding-right:15px}.page-header li.active a{color:#333;text-decoration:none;font-weight:bold}.page-header li.active a:hover,.page-header li.active a:focus{text-decoration:underline}.menu-inline{margin-bottom:5px}.menu-inline li{display:inline;padding-right:15px}.menu-inline li .active a{font-weight:bold;color:#000;text-decoration:none}.sidebar-container{margin-top:10px;height:100%;width:100%;display:-ms-flexbox;display:-webkit-box;display:-moz-box;display:-ms-box;display:box;-ms-flex-direction:row;-webkit-box-orient:horizontal;-moz-box-orient:horizontal;-ms-box-orient:horizontal;box-orient:horizontal}.sidebar-content{padding-left:10px;-ms-flex:1;-webkit-box-flex:1;-moz-box-flex:1;-ms-box-flex:1;box-flex:1}.sidebar{padding-right:10px;border-right:1px dotted #eee;max-width:240px;min-width:190px;width:18%;-ms-flex:0 100px;-webkit-box-flex:0;-moz-box-flex:0;-ms-box-flex:0;box-flex:0}.sidebar h2{margin-top:0}.sidebar>ul a{text-decoration:none;color:#999;font-weight:300}.sidebar>ul a:hover{color:#333}.sidebar>ul li{list-style-type:none;line-height:35px;border-bottom:1px dotted #efefef;padding-left:13px}.sidebar>ul li:hover{border-left:5px solid #555;padding-left:8px}.sidebar>ul li.active{border-left:5px solid #333;padding-left:8px}.sidebar>ul li.active a{color:#333;font-weight:bold}.sidebar-icons>ul li{padding-left:0}.sidebar-icons>ul li:hover,.sidebar-icons>ul li.active{padding-left:0;border-left:none}.sidebar>ul li.active a:focus,.sidebar>ul li.active a:hover{color:#555}.sidebar>ul li:last-child{margin-bottom:15px}.avatar img{vertical-align:bottom}.avatar-left{float:left;margin-right:10px}.avatar-inline{display:inline-block;margin-right:3px}.avatar-48 img,.avatar-48 div{border-radius:30px}.avatar-48 .avatar-letter{line-height:48px;width:48px;font-size:25px}.avatar-20 img,.avatar-20 div{border-radius:10px}.avatar-20 .avatar-letter{line-height:20px;width:20px;font-size:11px}.avatar-letter{color:#fff;text-align:center}#file-dropzone,#screenshot-zone{position:relative;border:2px dashed #ccc;width:99%;height:250px;overflow:auto}#file-dropzone-inner,#screenshot-inner{position:absolute;left:0;bottom:48%;width:100%;text-align:center;color:#aaa}#screenshot-zone.screenshot-pasted{border:2px solid #333}#file-list{margin:20px}#file-list li{list-style-type:none;padding-top:8px;padding-bottom:8px;border-bottom:1px dotted #ddd;width:95%}#file-list li.file-error{font-weight:bold;color:#b94a48}.color-picker{width:180px}.color-picker-option{height:25px}.color-picker-square{display:inline-block;width:18px;height:18px;margin-right:5px;border:1px solid #000}.color-picker-label{display:inline-block;vertical-align:bottom;padding-bottom:3px}.file-thumbnails{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;flex-wrap:wrap;-webkit-justify-content:flex-start;justify-content:flex-start}.file-thumbnail{width:250px;border:1px solid #efefef;border-radius:5px;margin-bottom:20px;box-shadow:4px 2px 10px -6px rgba(0,0,0,0.55);margin-right:15px}.file-thumbnail img{border-top-left-radius:5px;border-top-right-radius:5px}.file-thumbnail img:hover{opacity:0.5}.file-thumbnail-content{padding-left:8px;padding-right:8px}.file-thumbnail-title{font-weight:700;font-size:0.9em;color:#555}.file-thumbnail-description{font-size:0.8em;color:#999;margin-top:8px;margin-bottom:5px}.file-viewer{position:relative}.file-viewer img{max-width:95%;max-height:85%;margin-top:10px}.filter-box{max-width:800px}.project-header{margin-top:8px;margin-bottom:20px}.action-menu{color:#333;text-decoration:none}.action-menu:hover,.action-menu:focus{text-decoration:underline}.project-creation-options{max-width:500px;border-left:3px dotted #efefef;margin-top:20px;padding-left:15px;padding-bottom:5px;padding-top:5px}.project-overview-columns{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;align-items:center;-webkit-justify-content:center;justify-content:center;margin-bottom:20px;font-size:1.4em}.project-overview-column{text-align:center;margin-right:3%;padding:3px 15px 3px 15px;border:1px dashed #ddd}.project-overview-column small{color:#999}.project-overview-column strong{color:#555}.project-header{box-sizing:border-box;display:flex;flex-wrap:wrap}.project-header>*{box-sizing:border-box}.project-header>*{width:1%}.project-header .dropdown-component{width:5%}@media (min-width: 768px) and (max-width: 1150px){.project-header .dropdown-component{width:8%}}@media (max-width: 768px){.project-header .dropdown-component{width:100%}}.project-header .views-switcher-component{width:38%}@media (max-width: 1300px){.project-header .views-switcher-component{width:45%}}@media (min-width: 768px) and (max-width: 1150px){.project-header .views-switcher-component{width:92%}}@media (max-width: 768px){.project-header .views-switcher-component{width:100%}}.project-header .filter-box-component{margin:0;width:55%}@media (max-width: 1300px){.project-header .filter-box-component{width:50%}}@media (min-width: 768px) and (max-width: 1150px){.project-header .filter-box-component{width:100%;margin-top:10px}.project-header .filter-box-component .filter-box{max-width:100%}}@media (max-width: 768px){.project-header .filter-box-component{width:100%;margin-top:10px}.project-header .filter-box-component .filter-box{max-width:100%}}.project-header .filter-box-component form{margin:0}.views{display:inline-block;margin-right:10px;font-size:0.9em}@media (max-width: 560px){.views{width:100%}}@media (max-width: 768px){.views{margin-top:10px;font-size:1em}}.views li{white-space:nowrap;background:#fafafa;border:1px solid #ddd;border-right:none;padding:4px 8px;display:inline}@media (max-width: 560px){.views li{display:block;margin-top:5px;border-radius:5px;border:1px solid #ddd}}.views li.active a{font-weight:bold;color:#000;text-decoration:none}.views li:first-child{border-top-left-radius:5px;border-bottom-left-radius:5px}.views li:last-child{border-right:1px solid #ddd;border-top-right-radius:5px;border-bottom-right-radius:5px}.views a{color:#555;text-decoration:none}.views a:hover{color:#333;text-decoration:underline}.dashboard-project-stats small{margin-right:10px;color:#999}.dashboard-table-link{font-weight:bold;color:#000;text-decoration:none}.dashboard-table-link:focus,.dashboard-table-link:hover{color:#999}.public-board{margin-top:5px}.public-task{max-width:800px;margin:5px auto 0}#board-container{overflow-x:auto}#board{table-layout:fixed;margin-bottom:0}#board th.board-column-header{width:240px}#board td{vertical-align:top}.board-container-compact{overflow-x:initial}@media all and (-ms-high-contrast: active), (-ms-high-contrast: none){.board-container-compact #board{table-layout:auto}}#board th.board-column-header.board-column-compact{width:initial}.board-column-collapsed{display:none}td.board-column-task-collapsed{font-weight:bold;background-color:#fbfbfb}#board th.board-column-header-collapsed{width:28px;min-width:28px;text-align:center;overflow:hidden}.board-rotation-wrapper{position:relative;padding:8px 4px;min-height:150px;overflow:hidden}.board-rotation{white-space:nowrap;-webkit-backface-visibility:hidden;-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg);-webkit-transform-origin:0 100%;-moz-transform-origin:0 100%;-ms-transform-origin:0 100%;transform-origin:0 100%}.board-column-title .dropdown-menu{text-decoration:none}.board-add-icon{float:left;padding:0 5px}.board-add-icon a{text-decoration:none;color:#36c;font-size:1.6em;line-height:70%}.board-add-icon a:focus,.board-add-icon a:hover{text-decoration:none;color:red}.board-column-header-task-count{color:#999;font-weight:normal}a.board-swimlane-toggle{text-decoration:none}a.board-swimlane-toggle:hover,a.board-swimlane-toggle:focus{color:#000;text-decoration:none;border:none}.board-task-list{min-height:60px}.board-task-list-limit{background-color:#DF5353}.draggable-item{cursor:pointer;user-select:none;-webkit-user-select:none;-moz-user-select:none}.draggable-placeholder{border:2px dashed #000;background:#fafafa;height:70px;margin-bottom:10px}div.draggable-item-selected{border:1px solid #000}.task-board-sort-handle{float:left;padding-right:5px}.task-board{position:relative;margin-bottom:4px;border:1px solid #000;padding:2px;word-wrap:break-word;font-size:0.9em}div.task-board-recent{border-width:2px}div.task-board-status-closed{user-select:none;border:1px dotted #555}.task-board a{color:#000;text-decoration:none}.task-board .dropdown-menu{font-weight:bold}.task-board .task-score{font-weight:bold}.task-board-collapsed{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.task-board-title{margin-top:5px;margin-bottom:8px}.task-board-title a:hover{text-decoration:underline}.task-board-saving-state{opacity:0.3}.task-board-saving-icon{position:absolute;margin:auto;width:100%;text-align:center;color:#000}.task-board-category-container{text-align:right;margin-top:8px;margin-bottom:8px}.task-board-category{font-weight:500;color:#000;border:1px solid #555;padding:1px 2px 1px 2px;border-radius:4px}.task-board-category:hover{opacity:0.6}.task-board-avatars{text-align:right;float:right}.task-board-change-assignee{cursor:pointer}.task-board-change-assignee:hover{opacity:0.6}.task-board-icons{font-size:0.8em;text-align:right;margin-top:4px;margin-bottom:2px}.task-board-icons a{opacity:0.5}.task-board-icons span{opacity:0.5;margin-left:2px}.task-board-icons a:hover,.task-board-icons span:hover{opacity:1.0}.flag-milestone{color:green}.task-board-age{display:inline-block}span.task-board-age-total{border:#666 1px solid;padding:1px 3px 1px 3px;border-top-left-radius:3px;border-bottom-left-radius:3px}span.task-board-age-column{border:#666 1px solid;border-left:none;margin-left:-5px;padding:1px 3px 1px 3px;border-top-right-radius:3px;border-bottom-right-radius:3px}.task-board-date{font-weight:bold;color:#000}span.task-board-date-today{opacity:1.0}span.task-board-date-overdue{opacity:1.0}.task-tags li{display:inline;margin:0;margin-right:4px;padding:2px;color:#555;border:1px solid #666;border-radius:2px}.task-summary-container .task-tags{margin-top:10px}#task-summary{margin-bottom:15px}#task-summary h2{color:#555;font-size:1.6em;margin-top:0;padding-top:0}.task-summary-container{border:2px solid #000;border-radius:8px;padding:15px}.task-summary-columns{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-justify-content:space-between;justify-content:space-between}.task-summary-column{color:#333}.task-summary-column span{color:#555}.task-summary-column li{line-height:23px}.task-show-title{border:2px solid #000;border-radius:8px;margin-bottom:20px}.task-show-title h2{color:#555;margin:0;padding:8px}.task-table .dropdown-menu{color:#000;text-decoration:none;font-weight:bold}.task-table .dropdown-menu:focus,.task-table .dropdown-menu:hover{text-decoration:underline}td.task-table a{color:#000;text-decoration:none}td.task-table a:hover{text-decoration:underline}.comment-sorting{text-align:right}.comment-sorting a{color:#555;font-weight:normal;text-decoration:none}.comment-sorting a:hover{color:#999}.comment{padding:5px;margin-bottom:15px}.comment:hover{background:#fafafa}.comment-title{border-bottom:1px dotted #eee;margin-left:55px;margin-bottom:10px}.comment-date{color:#999;font-weight:200}.comment-actions{font-size:0.8em;margin-left:55px;margin-top:8px}.comment-actions li{display:inline}.comment-actions a{color:#999;text-decoration:none}.comment-actions a:focus,.comment-actions a:hover{color:#333;text-decoration:underline}.comment-content{margin-left:55px}.subtasks-table td{vertical-align:middle}.task-links-table td{vertical-align:middle}.task-links-task-count{color:#999}.task-link-closed{text-decoration:line-through}.markdown-editor-container{max-width:400px}div.CodeMirror,div.CodeMirror-scroll{max-height:250px;min-height:200px}.markdown-editor-small div.CodeMirror,.markdown-editor-small div.CodeMirror-scroll{min-height:100px;max-height:180px}.form-column div.CodeMirror{margin-bottom:10px}.markdown{line-height:1.4em}.markdown h1{margin-top:5px;margin-bottom:10px;font-weight:bold}.markdown h2{font-weight:bold}.markdown p{margin-bottom:10px}.markdown ol,.markdown ul{margin-left:25px;margin-top:10px;margin-bottom:10px}.markdown pre{background:#fbfbfb;padding:10px;border-radius:5px;border:1px solid #ddd;overflow:auto;color:#555}.markdown blockquote{font-style:italic;border-left:3px solid #ddd;padding-left:10px;margin-bottom:10px;margin-left:20px}.markdown img{display:block;max-width:80%;margin-top:10px}.documentation{margin:0 auto;padding:20px;max-width:850px;background:#fefefe;border:1px solid #ccc;border-radius:5px;color:#555}.documentation img{border:1px solid #333}.documentation h1{text-decoration:none;margin-bottom:30px}.documentation h2{text-decoration:none;border-bottom:1px solid #ccc;margin-bottom:25px}.documentation li{line-height:30px}.listing{border-radius:4px;padding:8px 35px 8px 14px;margin-bottom:20px;border:1px solid #ddd;color:#333;background-color:#fcfcfc;overflow:auto}.listing li{list-style-type:square;margin-left:20px;margin-bottom:3px}.listing ul{margin-top:15px;margin-bottom:15px}.activity-event{margin-bottom:15px;padding:10px}.activity-event:hover{background:#fafafa}.activity-date{margin-left:10px;font-weight:normal;color:#999}.activity-content{margin-left:55px}.activity-title{font-weight:bold;color:#000;border-bottom:1px dotted #efefef}.activity-description{color:#555;margin-top:10px}.activity-description li{list-style-type:circle}.activity-description ul{margin-top:10px;margin-left:20px}div.ganttview-hzheader-month,div.ganttview-hzheader-day,div.ganttview-vtheader,div.ganttview-vtheader-item-name,div.ganttview-vtheader-series,div.ganttview-grid,div.ganttview-grid-row-cell{float:left}div.ganttview-hzheader-month,div.ganttview-hzheader-day{text-align:center}div.ganttview-grid-row-cell.last,div.ganttview-hzheader-day.last,div.ganttview-hzheader-month.last{border-right:none}div.ganttview{border:1px solid #999}div.ganttview-hzheader-month{width:60px;height:20px;border-right:1px solid #d0d0d0;line-height:20px;overflow:hidden}div.ganttview-hzheader-day{width:20px;height:20px;border-right:1px solid #f0f0f0;border-top:1px solid #d0d0d0;line-height:20px;color:#555}div.ganttview-vtheader{margin-top:41px;width:400px;overflow:hidden;background-color:#fff}div.ganttview-vtheader-item{color:#555}div.ganttview-vtheader-series-name{width:400px;height:31px;line-height:31px;padding-left:3px;border-top:1px solid #d0d0d0;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}div.ganttview-vtheader-series-name a{color:#555;text-decoration:none}div.ganttview-vtheader-series-name a:hover{color:#333;text-decoration:underline}div.ganttview-vtheader-series-name a i{color:#000}div.ganttview-vtheader-series-name a:hover i{color:#555}div.ganttview-slide-container{overflow:auto;border-left:1px solid #999}div.ganttview-grid-row-cell{width:20px;height:31px;border-right:1px solid #f0f0f0;border-top:1px solid #f0f0f0}div.ganttview-grid-row-cell.ganttview-weekend{background-color:#fafafa}div.ganttview-blocks{margin-top:40px}div.ganttview-block-container{height:28px;padding-top:4px}div.ganttview-block{position:relative;height:25px;background-color:#E5ECF9;border:1px solid #c0c0c0;border-radius:3px}.ganttview-block-movable{cursor:move}div.ganttview-block-not-defined{border-color:#000;background-color:#000}div.ganttview-block-text{position:absolute;height:12px;font-size:0.7em;color:#999;padding:2px 3px}div.ganttview-block div.ui-resizable-handle.ui-resizable-s{bottom:-0}.user-mention-link{font-weight:bold;color:#000;text-decoration:none}.user-mention-link:hover{color:#555} +h1,li,ul,ol,table,tr,td,th,p,blockquote,body{margin:0;padding:0;font-size:100%}body{margin-left:10px;margin-right:10px;padding-bottom:10px;color:#333;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;text-rendering:optimizeLegibility}small{font-size:0.8em}hr{border:0;height:0;border-top:1px solid rgba(0,0,0,0.1);border-bottom:1px solid rgba(255,255,255,0.3)}.pull-right{text-align:right}ul.no-bullet li{list-style-type:none;margin-left:0}.chosen-select{min-height:27px}#app-loading-icon{position:fixed;right:3px;bottom:3px}.assign-me{vertical-align:bottom}a{color:#36c;border:none}a:focus{outline:0;color:#DF5353;text-decoration:none}a:hover{color:#333;text-decoration:none}h1,h2,h3{font-weight:normal;color:#333}h1{font-size:1.5em}h2{font-size:1.4em;margin-bottom:10px}h3{margin-top:10px;font-size:1.2em}table{width:100%;border-collapse:collapse;border-spacing:0;margin-bottom:20px}th{border:1px solid #eee;padding:0.5em 3px}td{border:1px solid #eee;padding:0.5em 3px;vertical-align:top}th{background:#fbfbfb;text-align:left}td li{margin-left:20px}.table-small{font-size:0.8em}th a{text-decoration:none;color:#333}th a:focus,th a:hover{text-decoration:underline}.table-fixed{table-layout:fixed;white-space:nowrap}.table-fixed th{overflow:hidden}.table-fixed td{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.table-stripped tr:nth-child(odd){background:#fefefe}.column-3{width:3%}.column-5{width:5%}.column-8{width:7.5%}.column-10{width:10%}.column-12{width:12%}.column-15{width:15%}.column-18{width:18%}.column-20{width:20%}.column-25{width:25%}.column-30{width:30%}.column-35{width:35%}.column-40{width:40%}.column-50{width:50%}.column-60{width:60%}.column-70,.column-80{width:70%}.draggable-row-handle{cursor:move;color:#dedede}.draggable-row-handle:hover{color:#333}tr.draggable-item-selected{background:#fff;border:2px solid #666;box-shadow:4px 2px 10px -4px rgba(0,0,0,0.55)}tr.draggable-item-selected td{border-top:none;border-bottom:none}tr.draggable-item-selected td:first-child{border-left:none}tr.draggable-item-selected td:last-child{border-right:none}.table-stripped tr.draggable-item-hover,tr.draggable-item-hover{background:#FEFFF2}form{margin-bottom:20px}label{cursor:pointer;display:block;margin-top:10px}input[type="number"],input[type="date"],input[type="email"],input[type="password"],input[type="text"]:not(.input-addon-field){color:#999;border:1px solid #ccc;width:300px;max-width:95%;font-size:1em;height:25px;padding-bottom:0;font-family:sans-serif;margin-top:10px;-webkit-appearance:none;-moz-appearance:none}input[type="number"]::-webkit-input-placeholder,input[type="date"]::-webkit-input-placeholder,input[type="email"]::-webkit-input-placeholder,input[type="password"]::-webkit-input-placeholder,input[type="text"]:not(.input-addon-field)::-webkit-input-placeholder{color:#dedede}input[type="number"]:-moz-placeholder,input[type="date"]:-moz-placeholder,input[type="email"]:-moz-placeholder,input[type="password"]:-moz-placeholder,input[type="text"]:not(.input-addon-field):-moz-placeholder{color:#dedede}input[type="number"]::-moz-placeholder,input[type="date"]::-moz-placeholder,input[type="email"]::-moz-placeholder,input[type="password"]::-moz-placeholder,input[type="text"]:not(.input-addon-field)::-moz-placeholder{color:#dedede}input[type="number"]:-ms-input-placeholder,input[type="date"]:-ms-input-placeholder,input[type="email"]:-ms-input-placeholder,input[type="password"]:-ms-input-placeholder,input[type="text"]:not(.input-addon-field):-ms-input-placeholder{color:#dedede}input[type="number"]:focus,input[type="date"]:focus,input[type="email"]:focus,input[type="password"]:focus,input[type="text"]:focus{color:#000;border-color:rgba(82,168,236,0.8);outline:0;box-shadow:0 0 8px rgba(82,168,236,0.6)}input[type="number"]{width:70px}input[type="text"]:not(.input-addon-field).form-numeric{width:70px}input[type="text"]:not(.input-addon-field).form-datetime,input[type="text"]:not(.input-addon-field).form-date{width:150px}input[type="text"]:not(.input-addon-field).form-input-large{width:400px}input[type="text"]:not(.input-addon-field).form-input-small{width:150px}textarea:focus{color:#000;border-color:rgba(82,168,236,0.8);outline:0;box-shadow:0 0 8px rgba(82,168,236,0.6)}textarea{border:1px solid #ccc;width:400px;max-width:99%;height:200px;font-family:sans-serif}select{max-width:95%}select:focus{outline:0}.tag-autocomplete{width:400px}span.select2-container{margin-top:2px}.form-actions{padding-top:20px;clear:both}input.form-error,textarea.form-error{border:2px solid #b94a48}input.form-error:focus,textarea.form-error:focus{box-shadow:none;border:2px solid #b94a48}.form-required{color:red;padding-left:5px;font-weight:bold}.form-errors{color:#b94a48;list-style-type:none}ul.form-errors li{margin-left:0}.form-help{font-size:0.8em;color:brown;margin-bottom:15px}.form-inline{padding:0;margin:0;border:none}.form-inline label{display:inline}.form-inline input,.form-inline select{margin:0 15px 0 0}.form-inline .form-required{display:none}.form-inline-group{display:inline}.form-columns{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row}.form-column{margin-right:25px}.form-login{width:350px;margin:8% auto 0}.form-login li{margin-left:25px;line-height:25px}.form-login h2{margin-bottom:30px;font-weight:bold}.reset-password{margin-top:20px}.reset-password a{color:#999}.input-addon{display:flex}.input-addon-field{flex:1;font-size:1em;color:#999;margin:0;-webkit-appearance:none;-moz-appearance:none}.input-addon-item{background-color:rgba(147,128,108,0.1);color:#666;font:inherit;font-weight:normal}@media (max-width: 480px){.input-addon-item .dropdown .fa-caret-down{display:none}}.input-addon-field,.input-addon-item{border:1px solid rgba(147,128,108,0.25);padding:4px 0.75em}.input-addon-field:not(:first-child),.input-addon-item:not(:first-child){border-left:0}.input-addon-field:first-child,.input-addon-item:first-child{border-radius:5px 0 0 5px}.input-addon-field:last-child,.input-addon-item:last-child{border-radius:0 5px 5px 0}.alert{padding:8px 35px 8px 14px;margin-top:5px;margin-bottom:5px;color:#c09853;background-color:#fcf8e3;border:1px solid #fbeed5;border-radius:4px}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-normal{color:#333;background-color:#f0f0f0;border-color:#ddd}.alert ul{margin-top:10px;margin-bottom:10px}.alert li{margin-left:25px}.alert-fade-out{text-align:center;position:fixed;bottom:0;left:20%;width:60%;padding-top:5px;padding-bottom:5px;margin-bottom:0;border-width:1px 0 0;border-radius:4px 4px 0 0;z-index:9999}a.btn{text-decoration:none}.btn{-webkit-appearance:none;-moz-appearance:none;font-size:1.2em;font-weight:normal;cursor:pointer;display:inline-block;border-radius:2px;padding:3px 10px;margin:0;border:1px solid #ddd;background:#f5f5f5;color:#333}.btn:hover,.btn:focus{border-color:#bbb;background:#fafafa;color:#000}.btn-red{border-color:#b0281a;background:#d14836;color:#fff}.btn-red:hover,.btn-red:focus{border-color:#b0281a;background:#c53727;color:#fff}.btn-blue{border-color:#3079ed;background:#4d90fe;color:#fff}.btn-blue:hover,.btn-blue:focus{border-color:#3079ed;background:#357ae8;color:#fff}.btn:disabled{color:#ccc;border-color:#ccc;background:#f7f7f7}.buttons-header{font-size:0.8em;margin-top:5px;margin-bottom:15px}.tooltip-arrow:after{background:#fff;border:1px solid #aaaaaa;box-shadow:0 0 5px #aaa}div.ui-tooltip{min-width:200px;max-width:600px}.tooltip-arrow{width:20px;height:10px;overflow:hidden;position:absolute}.tooltip-arrow.top{top:-10px}.tooltip-arrow.bottom{bottom:-10px}.tooltip-arrow.align-left{left:10px}.tooltip-arrow.align-right{right:10px}.tooltip-arrow:after{content:"";position:absolute;width:14px;height:14px;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg)}.tooltip-arrow.bottom:after{top:-10px}.tooltip-arrow.top:after{bottom:-10px}.tooltip-arrow.align-left:after{left:0}.tooltip-arrow.align-right:after{right:0}.tooltip-large{width:600px}.ui-tooltip-content .markdown p{margin-bottom:0}.ui-tooltip li{list-style-type:none}.tooltip .fa-info-circle{color:#999}.dropdown{display:inline;position:relative}.dropdown ul{display:none}ul.dropdown-submenu-open{display:block;position:absolute;z-index:1000;min-width:285px;list-style:none;margin:3px 0 0 1px;padding:6px 0;background-color:#fff;border:1px solid #b2b2b2;border-radius:3px;box-shadow:0 1px 3px rgba(0,0,0,0.15)}.dropdown-submenu-open li{display:block;margin:0;padding:8px 10px;font-size:0.9em;border-bottom:1px solid #f8f8f8;cursor:pointer}.dropdown-submenu-open li.no-hover{cursor:default}.dropdown-submenu-open li:last-child{border:none}.dropdown-submenu-open li:not(.no-hover):hover{background:#4078C0;color:#fff}.dropdown-submenu-open li:hover a{color:#fff}.dropdown-submenu-open a{text-decoration:none;color:#333}.dropdown-submenu-open a:focus{text-decoration:underline}.dropdown-menu-link-text,.dropdown-menu-link-icon{color:#333;text-decoration:none}.dropdown-menu-link-text:hover{text-decoration:underline}.accordion-title{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAADCAYAAABS3WWCAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NEQ5RDgxQzc2RjQ5MTFFMjhEMUNENzFGRUMwRjhBRTciIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NEQ5RDgxQzg2RjQ5MTFFMjhEMUNENzFGRUMwRjhBRTciPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo0RDlEODFDNTZGNDkxMUUyOEQxQ0Q3MUZFQzBGOEFFNyIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo0RDlEODFDNjZGNDkxMUUyOEQxQ0Q3MUZFQzBGOEFFNyIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PvXFWFAAAAAYSURBVHjaYvj//z8D0/Pnz/8zgFgAAQYAS5UJscReGMIAAAAASUVORK5CYII=) repeat-x scroll 0 10px}.accordion-title h3{display:inline;padding-right:5px;background:#fff}.accordion-content{margin-top:15px;margin-bottom:25px}.accordion-toggle{color:#333;text-decoration:none}.accordion-toggle:focus{color:#333}.accordion-toggle:hover{color:#999}.accordion-toggle:before{content:"\f0d7"}.accordion-collapsed{margin-bottom:25px}.accordion-collapsed .accordion-toggle:before{content:"\f0da"}.accordion-collapsed .accordion-content{display:none}#main .confirm{max-width:700px}#popover-container{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.8);overflow:auto;z-index:100}#popover-content{position:absolute;width:70%;left:15%;top:1%;padding:15px;background:#fff;overflow:auto;max-height:90%}.popover-form{margin-bottom:0}.pagination{text-align:center}.pagination-next{margin-left:5px}.pagination-previous{margin-right:5px}header{box-sizing:border-box;display:flex;flex-wrap:wrap;margin-top:5px;margin-bottom:5px;border-bottom:1px solid #dedede}header>*{box-sizing:border-box}header>*{width:1%}header .menus-container{width:10%}@media (min-width: 768px) and (max-width: 1150px){header .menus-container{width:15%}}@media (max-width: 768px){header .menus-container{width:65%;order:2}}header .board-selector-container{width:15%}@media (min-width: 768px) and (max-width: 1150px){header .board-selector-container{width:20%}}@media (max-width: 768px){header .board-selector-container{width:35%;order:1;margin-bottom:5px}}header .title-container{width:75%}@media (min-width: 768px) and (max-width: 1150px){header .title-container{width:65%}}@media (max-width: 768px){header .title-container{width:100%;order:3}}header h1{font-size:1.5em}header h1 .tooltip{opacity:0.3;font-size:0.7em}.web-notification-icon{color:#36c}.web-notification-icon:focus,.web-notification-icon:hover{color:#000}.logo a{opacity:0.5;color:#d40000;text-decoration:none}.logo span{color:#333}.logo a:hover{opacity:0.8;color:#333}.logo a:focus span,.logo a:hover span{color:#d40000}.page-header{margin-bottom:20px}.page-header .dropdown{padding-right:10px}.page-header h2{margin:0;padding:0;font-weight:bold;border-bottom:1px dotted #ccc}.page-header h2 a{color:#333;text-decoration:none}.page-header h2 a:focus,.page-header h2 a:hover{color:#999}.page-header ul{text-align:left;margin-top:5px;display:inline-block}.page-header li{display:inline;padding-right:15px}.page-header li.active a{color:#333;text-decoration:none;font-weight:bold}.page-header li.active a:hover,.page-header li.active a:focus{text-decoration:underline}.menu-inline{margin-bottom:5px}.menu-inline li{display:inline;padding-right:15px}.menu-inline li .active a{font-weight:bold;color:#000;text-decoration:none}.sidebar-container{margin-top:10px;height:100%;width:100%;display:-ms-flexbox;display:-webkit-box;display:-moz-box;display:-ms-box;display:box;-ms-flex-direction:row;-webkit-box-orient:horizontal;-moz-box-orient:horizontal;-ms-box-orient:horizontal;box-orient:horizontal}.sidebar-content{padding-left:10px;-ms-flex:1;-webkit-box-flex:1;-moz-box-flex:1;-ms-box-flex:1;box-flex:1}.sidebar{padding-right:10px;border-right:1px dotted #eee;max-width:240px;min-width:190px;width:18%;-ms-flex:0 100px;-webkit-box-flex:0;-moz-box-flex:0;-ms-box-flex:0;box-flex:0}.sidebar h2{margin-top:0}.sidebar>ul a{text-decoration:none;color:#999;font-weight:300}.sidebar>ul a:hover{color:#333}.sidebar>ul li{list-style-type:none;line-height:35px;border-bottom:1px dotted #efefef;padding-left:13px}.sidebar>ul li:hover{border-left:5px solid #555;padding-left:8px}.sidebar>ul li.active{border-left:5px solid #333;padding-left:8px}.sidebar>ul li.active a{color:#333;font-weight:bold}.sidebar-icons>ul li{padding-left:0}.sidebar-icons>ul li:hover,.sidebar-icons>ul li.active{padding-left:0;border-left:none}.sidebar>ul li.active a:focus,.sidebar>ul li.active a:hover{color:#555}.sidebar>ul li:last-child{margin-bottom:15px}.avatar img{vertical-align:bottom}.avatar-left{float:left;margin-right:10px}.avatar-inline{display:inline-block;margin-right:3px}.avatar-48 img,.avatar-48 div{border-radius:30px}.avatar-48 .avatar-letter{line-height:48px;width:48px;font-size:25px}.avatar-20 img,.avatar-20 div{border-radius:10px}.avatar-20 .avatar-letter{line-height:20px;width:20px;font-size:11px}.avatar-letter{color:#fff;text-align:center}#file-dropzone,#screenshot-zone{position:relative;border:2px dashed #ccc;width:99%;height:250px;overflow:auto}#file-dropzone-inner,#screenshot-inner{position:absolute;left:0;bottom:48%;width:100%;text-align:center;color:#aaa}#screenshot-zone.screenshot-pasted{border:2px solid #333}#file-list{margin:20px}#file-list li{list-style-type:none;padding-top:8px;padding-bottom:8px;border-bottom:1px dotted #ddd;width:95%}#file-list li.file-error{font-weight:bold;color:#b94a48}.color-picker{width:180px}.color-picker-option{height:25px}.color-picker-square{display:inline-block;width:18px;height:18px;margin-right:5px;border:1px solid #000}.color-picker-label{display:inline-block;vertical-align:bottom;padding-bottom:3px}.file-thumbnails{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;flex-wrap:wrap;-webkit-justify-content:flex-start;justify-content:flex-start}.file-thumbnail{width:250px;border:1px solid #efefef;border-radius:5px;margin-bottom:20px;box-shadow:4px 2px 10px -6px rgba(0,0,0,0.55);margin-right:15px}.file-thumbnail img{border-top-left-radius:5px;border-top-right-radius:5px}.file-thumbnail img:hover{opacity:0.5}.file-thumbnail-content{padding-left:8px;padding-right:8px}.file-thumbnail-title{font-weight:700;font-size:0.9em;color:#555}.file-thumbnail-description{font-size:0.8em;color:#999;margin-top:8px;margin-bottom:5px}.file-viewer{position:relative}.file-viewer img{max-width:95%;max-height:85%;margin-top:10px}.filter-box{max-width:800px}.project-header{margin-top:8px;margin-bottom:20px}.action-menu{color:#333;text-decoration:none}.action-menu:hover,.action-menu:focus{text-decoration:underline}.project-creation-options{max-width:500px;border-left:3px dotted #efefef;margin-top:20px;padding-left:15px;padding-bottom:5px;padding-top:5px}.project-overview-columns{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;align-items:center;-webkit-justify-content:center;justify-content:center;margin-bottom:20px;font-size:1.4em}.project-overview-column{text-align:center;margin-right:3%;padding:3px 15px 3px 15px;border:1px dashed #ddd}.project-overview-column small{color:#999}.project-overview-column strong{color:#555}.project-header{box-sizing:border-box;display:flex;flex-wrap:wrap}.project-header>*{box-sizing:border-box}.project-header>*{width:1%}.project-header .dropdown-component{width:5%}@media (min-width: 768px) and (max-width: 1150px){.project-header .dropdown-component{width:8%}}@media (max-width: 768px){.project-header .dropdown-component{width:100%}}.project-header .views-switcher-component{width:38%}@media (max-width: 1300px){.project-header .views-switcher-component{width:45%}}@media (min-width: 768px) and (max-width: 1150px){.project-header .views-switcher-component{width:92%}}@media (max-width: 768px){.project-header .views-switcher-component{width:100%}}.project-header .filter-box-component{margin:0;width:55%}@media (max-width: 1300px){.project-header .filter-box-component{width:50%}}@media (min-width: 768px) and (max-width: 1150px){.project-header .filter-box-component{width:100%;margin-top:10px}.project-header .filter-box-component .filter-box{max-width:100%}}@media (max-width: 768px){.project-header .filter-box-component{width:100%;margin-top:10px}.project-header .filter-box-component .filter-box{max-width:100%}}.project-header .filter-box-component form{margin:0}.views{display:inline-block;margin-right:10px;font-size:0.9em}@media (max-width: 560px){.views{width:100%}}@media (max-width: 768px){.views{margin-top:10px;font-size:1em}}.views li{white-space:nowrap;background:#fafafa;border:1px solid #ddd;border-right:none;padding:4px 8px;display:inline}@media (max-width: 560px){.views li{display:block;margin-top:5px;border-radius:5px;border:1px solid #ddd}}.views li.active a{font-weight:bold;color:#000;text-decoration:none}.views li:first-child{border-top-left-radius:5px;border-bottom-left-radius:5px}.views li:last-child{border-right:1px solid #ddd;border-top-right-radius:5px;border-bottom-right-radius:5px}.views a{color:#555;text-decoration:none}.views a:hover{color:#333;text-decoration:underline}.dashboard-project-stats small{margin-right:10px;color:#999}.dashboard-table-link{font-weight:bold;color:#000;text-decoration:none}.dashboard-table-link:focus,.dashboard-table-link:hover{color:#999}.public-board{margin-top:5px}.public-task{max-width:800px;margin:5px auto 0}#board-container{overflow-x:auto}#board{table-layout:fixed;margin-bottom:0}#board th.board-column-header{width:240px}#board td{vertical-align:top}.board-container-compact{overflow-x:initial}@media all and (-ms-high-contrast: active), (-ms-high-contrast: none){.board-container-compact #board{table-layout:auto}}#board th.board-column-header.board-column-compact{width:initial}.board-column-collapsed{display:none}td.board-column-task-collapsed{font-weight:bold;background-color:#fbfbfb}#board th.board-column-header-collapsed{width:28px;min-width:28px;text-align:center;overflow:hidden}.board-rotation-wrapper{position:relative;padding:8px 4px;min-height:150px;overflow:hidden}.board-rotation{white-space:nowrap;-webkit-backface-visibility:hidden;-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg);-webkit-transform-origin:0 100%;-moz-transform-origin:0 100%;-ms-transform-origin:0 100%;transform-origin:0 100%}.board-column-title .dropdown-menu{text-decoration:none}.board-add-icon{float:left;padding:0 5px}.board-add-icon a{text-decoration:none;color:#36c;font-size:1.6em;line-height:70%}.board-add-icon a:focus,.board-add-icon a:hover{text-decoration:none;color:red}.board-column-header-task-count{color:#999;font-weight:normal}a.board-swimlane-toggle{text-decoration:none}a.board-swimlane-toggle:hover,a.board-swimlane-toggle:focus{color:#000;text-decoration:none;border:none}.board-task-list{min-height:60px}.board-task-list-limit{background-color:#DF5353}.draggable-item{cursor:pointer;user-select:none;-webkit-user-select:none;-moz-user-select:none}.draggable-placeholder{border:2px dashed #000;background:#fafafa;height:70px;margin-bottom:10px}div.draggable-item-selected{border:1px solid #000}.task-board-sort-handle{float:left;padding-right:5px}.task-board{position:relative;margin-bottom:4px;border:1px solid #000;padding:2px;word-wrap:break-word;font-size:0.9em}div.task-board-recent{border-width:2px}div.task-board-status-closed{user-select:none;border:1px dotted #555}.task-board a{color:#000;text-decoration:none}.task-board .dropdown-menu{font-weight:bold}.task-board .task-score{font-weight:bold}.task-board-collapsed{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.task-board-title{margin-top:5px;margin-bottom:8px}.task-board-title a:hover{text-decoration:underline}.task-board-saving-state{opacity:0.3}.task-board-saving-icon{position:absolute;margin:auto;width:100%;text-align:center;color:#000}.task-board-category-container{text-align:right;margin-top:8px;margin-bottom:8px}.task-board-category{font-weight:500;color:#000;border:1px solid #555;padding:1px 2px 1px 2px;border-radius:4px}.task-board-category:hover{opacity:0.6}.task-board-avatars{text-align:right;float:right}.task-board-change-assignee{cursor:pointer}.task-board-change-assignee:hover{opacity:0.6}.task-board-icons{font-size:0.8em;text-align:right;margin-top:4px;margin-bottom:2px}.task-board-icons a{opacity:0.5}.task-board-icons span{opacity:0.5;margin-left:2px}.task-board-icons a:hover,.task-board-icons span:hover{opacity:1.0}.flag-milestone{color:green}.task-board-age{display:inline-block}span.task-board-age-total{border:#666 1px solid;padding:1px 3px 1px 3px;border-top-left-radius:3px;border-bottom-left-radius:3px}span.task-board-age-column{border:#666 1px solid;border-left:none;margin-left:-5px;padding:1px 3px 1px 3px;border-top-right-radius:3px;border-bottom-right-radius:3px}.task-board-date{font-weight:bold;color:#000}span.task-board-date-today{opacity:1.0}span.task-board-date-overdue{opacity:1.0}.task-tags li{display:inline;margin:0;margin-right:4px;padding:2px;color:#555;border:1px solid #666;border-radius:2px}.task-summary-container .task-tags{margin-top:10px}#task-summary{margin-bottom:15px}#task-summary h2{color:#555;font-size:1.6em;margin-top:0;padding-top:0}.task-summary-container{border:2px solid #000;border-radius:8px;padding:15px}.task-summary-columns{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-justify-content:space-between;justify-content:space-between}.task-summary-column{color:#333}.task-summary-column span{color:#555}.task-summary-column li{line-height:23px}.task-show-title{border:2px solid #000;border-radius:8px;margin-bottom:20px}.task-show-title h2{color:#555;margin:0;padding:8px}.task-table .dropdown-menu{color:#000;text-decoration:none;font-weight:bold}.task-table .dropdown-menu:focus,.task-table .dropdown-menu:hover{text-decoration:underline}td.task-table a{color:#000;text-decoration:none}td.task-table a:hover{text-decoration:underline}.comment-sorting{text-align:right}.comment-sorting a{color:#555;font-weight:normal;text-decoration:none}.comment-sorting a:hover{color:#999}.comment{padding:5px;margin-bottom:15px}.comment:hover{background:#fafafa}.comment-title{border-bottom:1px dotted #eee;margin-left:55px;margin-bottom:10px}.comment-date{color:#999;font-weight:200}.comment-actions{font-size:0.8em;margin-left:55px;margin-top:8px}.comment-actions li{display:inline}.comment-actions a{color:#999;text-decoration:none}.comment-actions a:focus,.comment-actions a:hover{color:#333;text-decoration:underline}.comment-content{margin-left:55px}.subtasks-table td{vertical-align:middle}.task-links-table td{vertical-align:middle}.task-links-task-count{color:#999}.task-link-closed{text-decoration:line-through}.markdown-editor-container{max-width:400px}div.CodeMirror,div.CodeMirror-scroll{max-height:250px;min-height:200px}.markdown-editor-small div.CodeMirror,.markdown-editor-small div.CodeMirror-scroll{min-height:100px;max-height:180px}.form-column div.CodeMirror{margin-bottom:10px}.markdown{line-height:1.4em}.markdown h1{margin-top:5px;margin-bottom:10px;font-weight:bold}.markdown h2{font-weight:bold}.markdown p{margin-bottom:10px}.markdown ol,.markdown ul{margin-left:25px;margin-top:10px;margin-bottom:10px}.markdown pre{background:#fbfbfb;padding:10px;border-radius:5px;border:1px solid #ddd;overflow:auto;color:#555}.markdown blockquote{font-style:italic;border-left:3px solid #ddd;padding-left:10px;margin-bottom:10px;margin-left:20px}.markdown img{display:block;max-width:80%;margin-top:10px}.documentation{margin:0 auto;padding:20px;max-width:850px;background:#fefefe;border:1px solid #ccc;border-radius:5px;color:#555}.documentation img{border:1px solid #333}.documentation h1{text-decoration:none;margin-bottom:30px}.documentation h2{text-decoration:none;border-bottom:1px solid #ccc;margin-bottom:25px}.documentation li{line-height:30px}.listing{border-radius:4px;padding:8px 35px 8px 14px;margin-bottom:20px;border:1px solid #ddd;color:#333;background-color:#fcfcfc;overflow:auto}.listing li{list-style-type:square;margin-left:20px;margin-bottom:3px}.listing ul{margin-top:15px;margin-bottom:15px}.activity-event{margin-bottom:15px;padding:10px}.activity-event:hover{background:#fafafa}.activity-date{margin-left:10px;font-weight:normal;color:#999}.activity-content{margin-left:55px}.activity-title{font-weight:bold;color:#000;border-bottom:1px dotted #efefef}.activity-description{color:#555;margin-top:10px}.activity-description li{list-style-type:circle}.activity-description ul{margin-top:10px;margin-left:20px}div.ganttview-hzheader-month,div.ganttview-hzheader-day,div.ganttview-vtheader,div.ganttview-vtheader-item-name,div.ganttview-vtheader-series,div.ganttview-grid,div.ganttview-grid-row-cell{float:left}div.ganttview-hzheader-month,div.ganttview-hzheader-day{text-align:center}div.ganttview-grid-row-cell.last,div.ganttview-hzheader-day.last,div.ganttview-hzheader-month.last{border-right:none}div.ganttview{border:1px solid #999}div.ganttview-hzheader-month{width:60px;height:20px;border-right:1px solid #d0d0d0;line-height:20px;overflow:hidden}div.ganttview-hzheader-day{width:20px;height:20px;border-right:1px solid #f0f0f0;border-top:1px solid #d0d0d0;line-height:20px;color:#555}div.ganttview-vtheader{margin-top:41px;width:400px;overflow:hidden;background-color:#fff}div.ganttview-vtheader-item{color:#555}div.ganttview-vtheader-series-name{width:400px;height:31px;line-height:31px;padding-left:3px;border-top:1px solid #d0d0d0;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}div.ganttview-vtheader-series-name a{color:#555;text-decoration:none}div.ganttview-vtheader-series-name a:hover{color:#333;text-decoration:underline}div.ganttview-vtheader-series-name a i{color:#000}div.ganttview-vtheader-series-name a:hover i{color:#555}div.ganttview-slide-container{overflow:auto;border-left:1px solid #999}div.ganttview-grid-row-cell{width:20px;height:31px;border-right:1px solid #f0f0f0;border-top:1px solid #f0f0f0}div.ganttview-grid-row-cell.ganttview-weekend{background-color:#fafafa}div.ganttview-blocks{margin-top:40px}div.ganttview-block-container{height:28px;padding-top:4px}div.ganttview-block{position:relative;height:25px;background-color:#E5ECF9;border:1px solid #c0c0c0;border-radius:3px}.ganttview-block-movable{cursor:move}div.ganttview-block-not-defined{border-color:#000;background-color:#000}div.ganttview-block-text{position:absolute;height:12px;font-size:0.7em;color:#999;padding:2px 3px}div.ganttview-block div.ui-resizable-handle.ui-resizable-s{bottom:-0}.user-mention-link{font-weight:bold;color:#000;text-decoration:none}.user-mention-link:hover{color:#555} diff --git a/assets/sass/_form.sass b/assets/sass/_form.sass index e46e14d4..d70d505c 100644 --- a/assets/sass/_form.sass +++ b/assets/sass/_form.sass @@ -1,4 +1,5 @@ @import variables +@import mixins form margin-bottom: 20px @@ -20,6 +21,8 @@ input font-family: sans-serif margin-top: 10px +appearance + @include placeholder + color: color('lighter') &[type="number"]:focus, &[type="date"]:focus, &[type="email"]:focus, &[type="password"]:focus, &[type="text"]:focus color: color('dark') border-color: rgba(82, 168, 236, 0.8) @@ -63,11 +66,6 @@ select span.select2-container margin-top: 2px -\::-webkit-input-placeholder, ::-ms-input-placeholder, ::-moz-placeholder - color: color('light') - opacity: 0.2 - padding-top: 2px - .form-actions padding-top: 20px clear: both diff --git a/assets/sass/_mixins.sass b/assets/sass/_mixins.sass index 66ed04f0..9b913a56 100644 --- a/assets/sass/_mixins.sass +++ b/assets/sass/_mixins.sass @@ -27,3 +27,13 @@ @mixin grid_width($width) width: $width * 100% + +@mixin placeholder + &::-webkit-input-placeholder + @content + &:-moz-placeholder + @content + &::-moz-placeholder + @content + &:-ms-input-placeholder + @content diff --git a/assets/sass/_variables.sass b/assets/sass/_variables.sass index 497904d6..bd41e291 100644 --- a/assets/sass/_variables.sass +++ b/assets/sass/_variables.sass @@ -2,7 +2,7 @@ $xs-device-width: 480px $sm-device-width: 768px $md-device-width: 1150px -$colors: ('primary': #333, 'light': #999, 'dark': #000, 'medium': #555, 'error': #b94a48) +$colors: ('primary': #333, 'light': #999, 'lighter': #dedede, 'dark': #000, 'medium': #555, 'error': #b94a48) $link-colors: ('primary': #3366CC, 'focus': #DF5353, 'hover': #333) $background-colors: ('primary': #fbfbfb, 'light': #fcfcfc) -- cgit v1.2.3 From 521379a350da1e67be88a81f0434ec8f5df37e5e Mon Sep 17 00:00:00 2001 From: Frederic Guillot Date: Sat, 13 Aug 2016 20:23:04 -0400 Subject: Display same task summary on all task view pages --- app/Controller/ActivityController.php | 1 + app/Controller/TaskViewController.php | 3 ++ app/Template/activity/task.php | 11 +++-- app/Template/task/analytics.php | 10 ++-- app/Template/task/show.php | 74 ++++++++++++++--------------- app/Template/task/time_tracking_details.php | 9 ++-- app/Template/task/transitions.php | 9 ++-- assets/css/app.min.css | 2 +- assets/sass/_task_summary.sass | 9 ---- 9 files changed, 68 insertions(+), 60 deletions(-) (limited to 'app') diff --git a/app/Controller/ActivityController.php b/app/Controller/ActivityController.php index 9f9841af..476e4aac 100644 --- a/app/Controller/ActivityController.php +++ b/app/Controller/ActivityController.php @@ -40,6 +40,7 @@ class ActivityController extends BaseController 'task' => $task, 'project' => $this->projectModel->getById($task['project_id']), 'events' => $this->helper->projectActivity->getTaskEvents($task['id']), + 'tags' => $this->taskTagModel->getList($task['id']), ))); } } diff --git a/app/Controller/TaskViewController.php b/app/Controller/TaskViewController.php index e40ebdc0..36597457 100644 --- a/app/Controller/TaskViewController.php +++ b/app/Controller/TaskViewController.php @@ -91,6 +91,7 @@ class TaskViewController extends BaseController 'lead_time' => $this->taskAnalyticModel->getLeadTime($task), 'cycle_time' => $this->taskAnalyticModel->getCycleTime($task), 'time_spent_columns' => $this->taskAnalyticModel->getTimeSpentByColumn($task), + 'tags' => $this->taskTagModel->getList($task['id']), ))); } @@ -115,6 +116,7 @@ class TaskViewController extends BaseController 'task' => $task, 'project' => $this->projectModel->getById($task['project_id']), 'subtask_paginator' => $subtask_paginator, + 'tags' => $this->taskTagModel->getList($task['id']), ))); } @@ -131,6 +133,7 @@ class TaskViewController extends BaseController 'task' => $task, 'project' => $this->projectModel->getById($task['project_id']), 'transitions' => $this->transitionModel->getAllByTask($task['id']), + 'tags' => $this->taskTagModel->getList($task['id']), ))); } } diff --git a/app/Template/activity/task.php b/app/Template/activity/task.php index 04c64c63..39953d1a 100644 --- a/app/Template/activity/task.php +++ b/app/Template/activity/task.php @@ -1,9 +1,12 @@ -
-

text->e($task['title']) ?>

-
+render('task/details', array( + 'task' => $task, + 'tags' => $tags, + 'project' => $project, + 'editable' => false, +)) ?> -render('event/events', array('events' => $events)) ?> \ No newline at end of file +render('event/events', array('events' => $events)) ?> diff --git a/app/Template/task/analytics.php b/app/Template/task/analytics.php index db2d0cef..ecfef242 100644 --- a/app/Template/task/analytics.php +++ b/app/Template/task/analytics.php @@ -1,6 +1,10 @@ -
-

text->e($task['title']) ?>

-
+render('task/details', array( + 'task' => $task, + 'tags' => $tags, + 'project' => $project, + 'editable' => false, +)) ?> + diff --git a/app/Template/task/show.php b/app/Template/task/show.php index b18c2bca..a5c2d5a7 100644 --- a/app/Template/task/show.php +++ b/app/Template/task/show.php @@ -8,58 +8,58 @@ )) ?> -hook->render('template:task:show:before-description', array('task' => $task, 'project' => $project)) ?> -render('task/description', array('task' => $task)) ?> + hook->render('template:task:show:before-description', array('task' => $task, 'project' => $project)) ?> + render('task/description', array('task' => $task)) ?> -hook->render('template:task:show:before-subtasks', array('task' => $task, 'project' => $project)) ?> -render('subtask/show', array( - 'task' => $task, - 'subtasks' => $subtasks, - 'project' => $project, - 'editable' => true, -)) ?> + hook->render('template:task:show:before-subtasks', array('task' => $task, 'project' => $project)) ?> + render('subtask/show', array( + 'task' => $task, + 'subtasks' => $subtasks, + 'project' => $project, + 'editable' => true, + )) ?> -hook->render('template:task:show:before-internal-links', array('task' => $task, 'project' => $project)) ?> -render('task_internal_link/show', array( - 'task' => $task, - 'links' => $internal_links, - 'project' => $project, - 'link_label_list' => $link_label_list, - 'editable' => true, - 'is_public' => false, -)) ?> + hook->render('template:task:show:before-internal-links', array('task' => $task, 'project' => $project)) ?> + render('task_internal_link/show', array( + 'task' => $task, + 'links' => $internal_links, + 'project' => $project, + 'link_label_list' => $link_label_list, + 'editable' => true, + 'is_public' => false, + )) ?> -hook->render('template:task:show:before-external-links', array('task' => $task, 'project' => $project)) ?> -render('task_external_link/show', array( - 'task' => $task, - 'links' => $external_links, - 'project' => $project, -)) ?> + hook->render('template:task:show:before-external-links', array('task' => $task, 'project' => $project)) ?> + render('task_external_link/show', array( + 'task' => $task, + 'links' => $external_links, + 'project' => $project, + )) ?> -hook->render('template:task:show:before-attachments', array('task' => $task, 'project' => $project)) ?> -render('task_file/show', array( - 'task' => $task, - 'files' => $files, - 'images' => $images -)) ?> + hook->render('template:task:show:before-attachments', array('task' => $task, 'project' => $project)) ?> + render('task_file/show', array( + 'task' => $task, + 'files' => $files, + 'images' => $images + )) ?> -hook->render('template:task:show:before-comments', array('task' => $task, 'project' => $project)) ?> -render('comments/show', array( - 'task' => $task, - 'comments' => $comments, - 'project' => $project, - 'editable' => $this->user->hasProjectAccess('CommentController', 'edit', $project['id']), -)) ?> + hook->render('template:task:show:before-comments', array('task' => $task, 'project' => $project)) ?> + render('comments/show', array( + 'task' => $task, + 'comments' => $comments, + 'project' => $project, + 'editable' => $this->user->hasProjectAccess('CommentController', 'edit', $project['id']), + )) ?> hook->render('template:task:show:bottom', array('task' => $task, 'project' => $project)) ?> diff --git a/app/Template/task/time_tracking_details.php b/app/Template/task/time_tracking_details.php index 1a179522..2b46ca6b 100644 --- a/app/Template/task/time_tracking_details.php +++ b/app/Template/task/time_tracking_details.php @@ -1,6 +1,9 @@ -
-

text->e($task['title']) ?>

-
+render('task/details', array( + 'task' => $task, + 'tags' => $tags, + 'project' => $project, + 'editable' => false, +)) ?> render('task/time_tracking_summary', array('task' => $task)) ?> diff --git a/app/Template/task/transitions.php b/app/Template/task/transitions.php index 9e04c4e1..6f5f02a6 100644 --- a/app/Template/task/transitions.php +++ b/app/Template/task/transitions.php @@ -1,6 +1,9 @@ -
-

text->e($task['title']) ?>

-
+render('task/details', array( + 'task' => $task, + 'tags' => $tags, + 'project' => $project, + 'editable' => false, +)) ?>
order('Id', \Kanboard\Model\TaskModel::TABLE.'.id') ?> order(t('Project'), 'project_name') ?> order(t('Task'), \Kanboard\Model\TaskModel::TABLE.'.title') ?>order(t('Priority'), \Kanboard\Model\TaskModel::TABLE.'.priority') ?>order(t('Priority'), \Kanboard\Model\TaskModel::TABLE.'.priority') ?> order(t('Due date'), \Kanboard\Model\TaskModel::TABLE.'.date_due') ?> order(t('Column'), 'column_title') ?>
+
diff --git a/app/Template/analytic/avg_time_columns.php b/app/Template/analytic/avg_time_columns.php index 5f6c6b35..91c269fc 100644 --- a/app/Template/analytic/avg_time_columns.php +++ b/app/Template/analytic/avg_time_columns.php @@ -9,7 +9,7 @@
-
+
diff --git a/app/Template/analytic/compare_hours.php b/app/Template/analytic/compare_hours.php index e4a0b60e..c0b9cfc3 100644 --- a/app/Template/analytic/compare_hours.php +++ b/app/Template/analytic/compare_hours.php @@ -23,7 +23,7 @@ isEmpty()): ?>

isEmpty()): ?> -
+
diff --git a/app/Template/analytic/tasks.php b/app/Template/analytic/tasks.php index 9e7b1fd7..4bc19784 100644 --- a/app/Template/analytic/tasks.php +++ b/app/Template/analytic/tasks.php @@ -9,7 +9,7 @@
-
order(t('Id'), 'tasks.id') ?> order(t('Title'), 'tasks.title') ?>
+
diff --git a/app/Template/analytic/users.php b/app/Template/analytic/users.php index 9d1d3a1e..91bec11b 100644 --- a/app/Template/analytic/users.php +++ b/app/Template/analytic/users.php @@ -9,7 +9,7 @@
-
+
diff --git a/app/Template/board/tooltip_external_links.php b/app/Template/board/tooltip_external_links.php index 65331864..a9f1fc7f 100644 --- a/app/Template/board/tooltip_external_links.php +++ b/app/Template/board/tooltip_external_links.php @@ -1,5 +1,5 @@
-
+
diff --git a/app/Template/board/tooltip_files.php b/app/Template/board/tooltip_files.php index 6f9e2640..4e704dac 100644 --- a/app/Template/board/tooltip_files.php +++ b/app/Template/board/tooltip_files.php @@ -1,5 +1,5 @@
-
+
diff --git a/app/Template/board/tooltip_subtasks.php b/app/Template/board/tooltip_subtasks.php index 0322d373..8d5bc059 100644 --- a/app/Template/board/tooltip_subtasks.php +++ b/app/Template/board/tooltip_subtasks.php @@ -1,5 +1,5 @@
- +
diff --git a/app/Template/board/tooltip_tasklinks.php b/app/Template/board/tooltip_tasklinks.php index d1156cbe..08432e71 100644 --- a/app/Template/board/tooltip_tasklinks.php +++ b/app/Template/board/tooltip_tasklinks.php @@ -1,5 +1,5 @@
-
+
$grouped_links): ?> diff --git a/app/Template/category/index.php b/app/Template/category/index.php index a103d89f..ac60d9a8 100644 --- a/app/Template/category/index.php +++ b/app/Template/category/index.php @@ -2,7 +2,7 @@ -
+
diff --git a/app/Template/column/index.php b/app/Template/column/index.php index 04760a16..66890ba5 100644 --- a/app/Template/column/index.php +++ b/app/Template/column/index.php @@ -12,7 +12,7 @@

diff --git a/app/Template/currency/index.php b/app/Template/currency/index.php index 9881cee5..db9b21af 100644 --- a/app/Template/currency/index.php +++ b/app/Template/currency/index.php @@ -4,7 +4,7 @@ -
+
diff --git a/app/Template/custom_filter/index.php b/app/Template/custom_filter/index.php index 08c8040c..dcab891b 100644 --- a/app/Template/custom_filter/index.php +++ b/app/Template/custom_filter/index.php @@ -3,7 +3,7 @@

-
+
diff --git a/app/Template/dashboard/notifications.php b/app/Template/dashboard/notifications.php index 3b70b49f..a189d74f 100644 --- a/app/Template/dashboard/notifications.php +++ b/app/Template/dashboard/notifications.php @@ -13,7 +13,7 @@ -
+
diff --git a/app/Template/dashboard/projects.php b/app/Template/dashboard/projects.php index 77fb0bed..f8806c01 100644 --- a/app/Template/dashboard/projects.php +++ b/app/Template/dashboard/projects.php @@ -4,7 +4,7 @@ isEmpty()): ?>

-
+
diff --git a/app/Template/dashboard/subtasks.php b/app/Template/dashboard/subtasks.php index 0a9f305b..b71deeb9 100644 --- a/app/Template/dashboard/subtasks.php +++ b/app/Template/dashboard/subtasks.php @@ -4,7 +4,7 @@ isEmpty()): ?>

-
order('Id', \Kanboard\Model\ProjectModel::TABLE.'.id') ?> order('', \Kanboard\Model\ProjectModel::TABLE.'.is_private') ?>
+
diff --git a/app/Template/dashboard/tasks.php b/app/Template/dashboard/tasks.php index d0e731d6..427b903d 100644 --- a/app/Template/dashboard/tasks.php +++ b/app/Template/dashboard/tasks.php @@ -4,7 +4,7 @@ isEmpty()): ?>

-
order('Id', \Kanboard\Model\TaskModel::TABLE.'.id') ?> order(t('Project'), 'project_name') ?>
+
diff --git a/app/Template/group/users.php b/app/Template/group/users.php index a4895ab7..73597b39 100644 --- a/app/Template/group/users.php +++ b/app/Template/group/users.php @@ -8,7 +8,7 @@ isEmpty()): ?>

-
order('Id', \Kanboard\Model\TaskModel::TABLE.'.id') ?> order(t('Project'), 'project_name') ?>
+
diff --git a/app/Template/link/index.php b/app/Template/link/index.php index 7e32069a..70ead4a6 100644 --- a/app/Template/link/index.php +++ b/app/Template/link/index.php @@ -2,7 +2,7 @@

-
order(t('Id'), 'id') ?> order(t('Username'), 'username') ?>
+
diff --git a/app/Template/project_list/show.php b/app/Template/project_list/show.php index 1fe75592..8e4c3e6a 100644 --- a/app/Template/project_list/show.php +++ b/app/Template/project_list/show.php @@ -12,7 +12,7 @@ isEmpty()): ?>

-
+
diff --git a/app/Template/project_overview/files.php b/app/Template/project_overview/files.php index fa870938..826e6325 100644 --- a/app/Template/project_overview/files.php +++ b/app/Template/project_overview/files.php @@ -1,5 +1,5 @@ -
order(t('Id'), 'id') ?> order(t('Status'), 'is_active') ?>
+
diff --git a/app/Template/project_permission/index.php b/app/Template/project_permission/index.php index d850ec50..c7b17782 100644 --- a/app/Template/project_permission/index.php +++ b/app/Template/project_permission/index.php @@ -9,7 +9,7 @@
-
+
@@ -69,7 +69,7 @@
-
+
diff --git a/app/Template/project_tag/index.php b/app/Template/project_tag/index.php index 8e8dd96c..f77e21ee 100644 --- a/app/Template/project_tag/index.php +++ b/app/Template/project_tag/index.php @@ -11,7 +11,7 @@

-
+
diff --git a/app/Template/project_user_overview/roles.php b/app/Template/project_user_overview/roles.php index 87c8df85..011714d4 100644 --- a/app/Template/project_user_overview/roles.php +++ b/app/Template/project_user_overview/roles.php @@ -1,7 +1,7 @@ isEmpty()): ?>

-
+
diff --git a/app/Template/project_user_overview/tasks.php b/app/Template/project_user_overview/tasks.php index af0a3d97..8d682170 100644 --- a/app/Template/project_user_overview/tasks.php +++ b/app/Template/project_user_overview/tasks.php @@ -1,7 +1,7 @@ isEmpty()): ?>

isEmpty()): ?> -
order(t('User'), 'users.username') ?> order(t('Project'), 'projects.name') ?>
+
diff --git a/app/Template/project_user_overview/tooltip_users.php b/app/Template/project_user_overview/tooltip_users.php index 7117a87f..99b00030 100644 --- a/app/Template/project_user_overview/tooltip_users.php +++ b/app/Template/project_user_overview/tooltip_users.php @@ -1,7 +1,7 @@

-
order(t('Id'), 'tasks.id') ?> order(t('Project'), 'projects.name') ?>
+
$role_name): ?> diff --git a/app/Template/project_view/show.php b/app/Template/project_view/show.php index 667a576c..afe60384 100644 --- a/app/Template/project_view/show.php +++ b/app/Template/project_view/show.php @@ -52,7 +52,7 @@ -
+
diff --git a/app/Template/search/results.php b/app/Template/search/results.php index 8376b9e8..8c439a8a 100644 --- a/app/Template/search/results.php +++ b/app/Template/search/results.php @@ -1,4 +1,4 @@ -
+
diff --git a/app/Template/subtask/table.php b/app/Template/subtask/table.php index 4c6484ef..5c60df44 100644 --- a/app/Template/subtask/table.php +++ b/app/Template/subtask/table.php @@ -1,6 +1,6 @@
order(t('Project'), 'tasks.project_id') ?> order(t('Id'), 'tasks.id') ?>
diff --git a/app/Template/swimlane/table.php b/app/Template/swimlane/table.php index be123b08..cefef9de 100644 --- a/app/Template/swimlane/table.php +++ b/app/Template/swimlane/table.php @@ -1,5 +1,5 @@
diff --git a/app/Template/tag/index.php b/app/Template/tag/index.php index 2a495eb3..8e0c9a06 100644 --- a/app/Template/tag/index.php +++ b/app/Template/tag/index.php @@ -11,7 +11,7 @@

-
+
diff --git a/app/Template/task/analytics.php b/app/Template/task/analytics.php index ecfef242..071f24a7 100644 --- a/app/Template/task/analytics.php +++ b/app/Template/task/analytics.php @@ -18,7 +18,7 @@

-
+
diff --git a/app/Template/task/time_tracking_details.php b/app/Template/task/time_tracking_details.php index 2b46ca6b..7cb419e0 100644 --- a/app/Template/task/time_tracking_details.php +++ b/app/Template/task/time_tracking_details.php @@ -11,7 +11,7 @@ isEmpty()): ?>

-
+
diff --git a/app/Template/task/transitions.php b/app/Template/task/transitions.php index 6f5f02a6..4a9f22ce 100644 --- a/app/Template/task/transitions.php +++ b/app/Template/task/transitions.php @@ -12,7 +12,7 @@

-
order(t('User'), 'username') ?> order(t('Subtask'), 'subtask_title') ?>
+
diff --git a/app/Template/task_external_link/table.php b/app/Template/task_external_link/table.php index 56ef0363..cdfe0028 100644 --- a/app/Template/task_external_link/table.php +++ b/app/Template/task_external_link/table.php @@ -1,5 +1,5 @@ -
+
diff --git a/app/Template/task_file/files.php b/app/Template/task_file/files.php index 7ca59b1c..94c26f73 100644 --- a/app/Template/task_file/files.php +++ b/app/Template/task_file/files.php @@ -1,5 +1,5 @@ -
+
diff --git a/app/Template/task_internal_link/table.php b/app/Template/task_internal_link/table.php index 424d4791..6584a33a 100644 --- a/app/Template/task_internal_link/table.php +++ b/app/Template/task_internal_link/table.php @@ -1,5 +1,5 @@ -
+ $grouped_links): ?> diff --git a/app/Template/task_list/show.php b/app/Template/task_list/show.php index bb95b6a3..0518e4c3 100644 --- a/app/Template/task_list/show.php +++ b/app/Template/task_list/show.php @@ -4,7 +4,7 @@ isEmpty()): ?>

isEmpty()): ?> - +
diff --git a/app/Template/user_list/show.php b/app/Template/user_list/show.php index b2bd9377..5e285c89 100644 --- a/app/Template/user_list/show.php +++ b/app/Template/user_list/show.php @@ -12,7 +12,7 @@ isEmpty()): ?>

-
order(t('Id'), 'tasks.id') ?> order(t('Swimlane'), 'tasks.swimlane_id') ?>
+
diff --git a/app/Template/user_view/last.php b/app/Template/user_view/last.php index 3de4d5e2..72f59bf6 100644 --- a/app/Template/user_view/last.php +++ b/app/Template/user_view/last.php @@ -5,7 +5,7 @@

-
order(t('Id'), 'id') ?> order(t('Username'), 'username') ?>
+
@@ -21,4 +21,4 @@
- \ No newline at end of file + diff --git a/app/Template/user_view/password_reset.php b/app/Template/user_view/password_reset.php index 1371ce11..de7047e0 100644 --- a/app/Template/user_view/password_reset.php +++ b/app/Template/user_view/password_reset.php @@ -5,7 +5,7 @@

- +
@@ -23,4 +23,4 @@
- \ No newline at end of file + diff --git a/app/Template/user_view/sessions.php b/app/Template/user_view/sessions.php index eda3ef7f..10497e4f 100644 --- a/app/Template/user_view/sessions.php +++ b/app/Template/user_view/sessions.php @@ -5,7 +5,7 @@

- +
diff --git a/app/Template/user_view/timesheet.php b/app/Template/user_view/timesheet.php index 3df57492..aeffd2f4 100644 --- a/app/Template/user_view/timesheet.php +++ b/app/Template/user_view/timesheet.php @@ -6,7 +6,7 @@ isEmpty()): ?>

-
+
diff --git a/assets/css/app.min.css b/assets/css/app.min.css index 0bdfc3c2..dc46461f 100644 --- a/assets/css/app.min.css +++ b/assets/css/app.min.css @@ -1 +1 @@ -h1,li,ul,ol,table,tr,td,th,p,blockquote,body{margin:0;padding:0;font-size:100%}body{margin-left:10px;margin-right:10px;padding-bottom:10px;color:#333;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;text-rendering:optimizeLegibility}small{font-size:0.8em}hr{border:0;height:0;border-top:1px solid rgba(0,0,0,0.1);border-bottom:1px solid rgba(255,255,255,0.3)}.pull-right{text-align:right}ul.no-bullet li{list-style-type:none;margin-left:0}.chosen-select{min-height:27px}#app-loading-icon{position:fixed;right:3px;bottom:3px}.assign-me{vertical-align:bottom}a{color:#36c;border:none}a:focus{outline:0;color:#DF5353;text-decoration:none}a:hover{color:#333;text-decoration:none}h1,h2,h3{font-weight:normal;color:#333}h1{font-size:1.5em}h2{font-size:1.4em;margin-bottom:10px}h3{margin-top:10px;font-size:1.2em}table{width:100%;border-collapse:collapse;border-spacing:0;margin-bottom:20px}th{border:1px solid #eee;padding:0.5em 3px}td{border:1px solid #eee;padding:0.5em 3px;vertical-align:top}th{background:#fbfbfb;text-align:left}td li{margin-left:20px}.table-small{font-size:0.8em}th a{text-decoration:none;color:#333}th a:focus,th a:hover{text-decoration:underline}.table-fixed{table-layout:fixed;white-space:nowrap}.table-fixed th{overflow:hidden}.table-fixed td{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.table-stripped tr:nth-child(odd){background:#fefefe}.column-3{width:3%}.column-5{width:5%}.column-8{width:7.5%}.column-10{width:10%}.column-12{width:12%}.column-15{width:15%}.column-18{width:18%}.column-20{width:20%}.column-25{width:25%}.column-30{width:30%}.column-35{width:35%}.column-40{width:40%}.column-50{width:50%}.column-60{width:60%}.column-70,.column-80{width:70%}.draggable-row-handle{cursor:move;color:#dedede}.draggable-row-handle:hover{color:#333}tr.draggable-item-selected{background:#fff;border:2px solid #666;box-shadow:4px 2px 10px -4px rgba(0,0,0,0.55)}tr.draggable-item-selected td{border-top:none;border-bottom:none}tr.draggable-item-selected td:first-child{border-left:none}tr.draggable-item-selected td:last-child{border-right:none}.table-stripped tr.draggable-item-hover,tr.draggable-item-hover{background:#FEFFF2}form{margin-bottom:20px}label{cursor:pointer;display:block;margin-top:10px}input[type="number"],input[type="date"],input[type="email"],input[type="password"],input[type="text"]:not(.input-addon-field){color:#999;border:1px solid #ccc;width:300px;max-width:95%;font-size:1em;height:25px;padding-bottom:0;font-family:sans-serif;margin-top:10px;-webkit-appearance:none;-moz-appearance:none}input[type="number"]::-webkit-input-placeholder,input[type="date"]::-webkit-input-placeholder,input[type="email"]::-webkit-input-placeholder,input[type="password"]::-webkit-input-placeholder,input[type="text"]:not(.input-addon-field)::-webkit-input-placeholder{color:#dedede}input[type="number"]:-moz-placeholder,input[type="date"]:-moz-placeholder,input[type="email"]:-moz-placeholder,input[type="password"]:-moz-placeholder,input[type="text"]:not(.input-addon-field):-moz-placeholder{color:#dedede}input[type="number"]::-moz-placeholder,input[type="date"]::-moz-placeholder,input[type="email"]::-moz-placeholder,input[type="password"]::-moz-placeholder,input[type="text"]:not(.input-addon-field)::-moz-placeholder{color:#dedede}input[type="number"]:-ms-input-placeholder,input[type="date"]:-ms-input-placeholder,input[type="email"]:-ms-input-placeholder,input[type="password"]:-ms-input-placeholder,input[type="text"]:not(.input-addon-field):-ms-input-placeholder{color:#dedede}input[type="number"]:focus,input[type="date"]:focus,input[type="email"]:focus,input[type="password"]:focus,input[type="text"]:focus{color:#000;border-color:rgba(82,168,236,0.8);outline:0;box-shadow:0 0 8px rgba(82,168,236,0.6)}input[type="number"]{width:70px}input[type="text"]:not(.input-addon-field).form-numeric{width:70px}input[type="text"]:not(.input-addon-field).form-datetime,input[type="text"]:not(.input-addon-field).form-date{width:150px}input[type="text"]:not(.input-addon-field).form-input-large{width:400px}input[type="text"]:not(.input-addon-field).form-input-small{width:150px}textarea:focus{color:#000;border-color:rgba(82,168,236,0.8);outline:0;box-shadow:0 0 8px rgba(82,168,236,0.6)}textarea{border:1px solid #ccc;width:400px;max-width:99%;height:200px;font-family:sans-serif}select{max-width:95%}select:focus{outline:0}.tag-autocomplete{width:400px}span.select2-container{margin-top:2px}.form-actions{padding-top:20px;clear:both}input.form-error,textarea.form-error{border:2px solid #b94a48}input.form-error:focus,textarea.form-error:focus{box-shadow:none;border:2px solid #b94a48}.form-required{color:red;padding-left:5px;font-weight:bold}.form-errors{color:#b94a48;list-style-type:none}ul.form-errors li{margin-left:0}.form-help{font-size:0.8em;color:brown;margin-bottom:15px}.form-inline{padding:0;margin:0;border:none}.form-inline label{display:inline}.form-inline input,.form-inline select{margin:0 15px 0 0}.form-inline .form-required{display:none}.form-inline-group{display:inline}.form-columns{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row}.form-column{margin-right:25px}.form-login{width:350px;margin:8% auto 0}.form-login li{margin-left:25px;line-height:25px}.form-login h2{margin-bottom:30px;font-weight:bold}.reset-password{margin-top:20px}.reset-password a{color:#999}.input-addon{display:flex}.input-addon-field{flex:1;font-size:1em;color:#999;margin:0;-webkit-appearance:none;-moz-appearance:none}.input-addon-item{background-color:rgba(147,128,108,0.1);color:#666;font:inherit;font-weight:normal}@media (max-width: 480px){.input-addon-item .dropdown .fa-caret-down{display:none}}.input-addon-field,.input-addon-item{border:1px solid rgba(147,128,108,0.25);padding:4px 0.75em}.input-addon-field:not(:first-child),.input-addon-item:not(:first-child){border-left:0}.input-addon-field:first-child,.input-addon-item:first-child{border-radius:5px 0 0 5px}.input-addon-field:last-child,.input-addon-item:last-child{border-radius:0 5px 5px 0}.alert{padding:8px 35px 8px 14px;margin-top:5px;margin-bottom:5px;color:#c09853;background-color:#fcf8e3;border:1px solid #fbeed5;border-radius:4px}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-normal{color:#333;background-color:#f0f0f0;border-color:#ddd}.alert ul{margin-top:10px;margin-bottom:10px}.alert li{margin-left:25px}.alert-fade-out{text-align:center;position:fixed;bottom:0;left:20%;width:60%;padding-top:5px;padding-bottom:5px;margin-bottom:0;border-width:1px 0 0;border-radius:4px 4px 0 0;z-index:9999}a.btn{text-decoration:none}.btn{-webkit-appearance:none;-moz-appearance:none;font-size:1.2em;font-weight:normal;cursor:pointer;display:inline-block;border-radius:2px;padding:3px 10px;margin:0;border:1px solid #ddd;background:#f5f5f5;color:#333}.btn:hover,.btn:focus{border-color:#bbb;background:#fafafa;color:#000}.btn-red{border-color:#b0281a;background:#d14836;color:#fff}.btn-red:hover,.btn-red:focus{border-color:#b0281a;background:#c53727;color:#fff}.btn-blue{border-color:#3079ed;background:#4d90fe;color:#fff}.btn-blue:hover,.btn-blue:focus{border-color:#3079ed;background:#357ae8;color:#fff}.btn:disabled{color:#ccc;border-color:#ccc;background:#f7f7f7}.buttons-header{font-size:0.8em;margin-top:5px;margin-bottom:15px}.tooltip-arrow:after{background:#fff;border:1px solid #aaaaaa;box-shadow:0 0 5px #aaa}div.ui-tooltip{min-width:200px;max-width:600px}.tooltip-arrow{width:20px;height:10px;overflow:hidden;position:absolute}.tooltip-arrow.top{top:-10px}.tooltip-arrow.bottom{bottom:-10px}.tooltip-arrow.align-left{left:10px}.tooltip-arrow.align-right{right:10px}.tooltip-arrow:after{content:"";position:absolute;width:14px;height:14px;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg)}.tooltip-arrow.bottom:after{top:-10px}.tooltip-arrow.top:after{bottom:-10px}.tooltip-arrow.align-left:after{left:0}.tooltip-arrow.align-right:after{right:0}.tooltip-large{width:600px}.ui-tooltip-content .markdown p{margin-bottom:0}.ui-tooltip li{list-style-type:none}.tooltip .fa-info-circle{color:#999}.dropdown{display:inline;position:relative}.dropdown ul{display:none}ul.dropdown-submenu-open{display:block;position:absolute;z-index:1000;min-width:285px;list-style:none;margin:3px 0 0 1px;padding:6px 0;background-color:#fff;border:1px solid #b2b2b2;border-radius:3px;box-shadow:0 1px 3px rgba(0,0,0,0.15)}.dropdown-submenu-open li{display:block;margin:0;padding:8px 10px;font-size:0.9em;border-bottom:1px solid #f8f8f8;cursor:pointer}.dropdown-submenu-open li.no-hover{cursor:default}.dropdown-submenu-open li:last-child{border:none}.dropdown-submenu-open li:not(.no-hover):hover{background:#4078C0;color:#fff}.dropdown-submenu-open li:hover a{color:#fff}.dropdown-submenu-open a{text-decoration:none;color:#333}.dropdown-submenu-open a:focus{text-decoration:underline}.dropdown-menu-link-text,.dropdown-menu-link-icon{color:#333;text-decoration:none}.dropdown-menu-link-text:hover{text-decoration:underline}.accordion-title{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAADCAYAAABS3WWCAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NEQ5RDgxQzc2RjQ5MTFFMjhEMUNENzFGRUMwRjhBRTciIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NEQ5RDgxQzg2RjQ5MTFFMjhEMUNENzFGRUMwRjhBRTciPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo0RDlEODFDNTZGNDkxMUUyOEQxQ0Q3MUZFQzBGOEFFNyIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo0RDlEODFDNjZGNDkxMUUyOEQxQ0Q3MUZFQzBGOEFFNyIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PvXFWFAAAAAYSURBVHjaYvj//z8D0/Pnz/8zgFgAAQYAS5UJscReGMIAAAAASUVORK5CYII=) repeat-x scroll 0 10px}.accordion-title h3{display:inline;padding-right:5px;background:#fff}.accordion-content{margin-top:15px;margin-bottom:25px}.accordion-toggle{color:#333;text-decoration:none}.accordion-toggle:focus{color:#333}.accordion-toggle:hover{color:#999}.accordion-toggle:before{content:"\f0d7"}.accordion-collapsed{margin-bottom:25px}.accordion-collapsed .accordion-toggle:before{content:"\f0da"}.accordion-collapsed .accordion-content{display:none}#main .confirm{max-width:700px}#popover-container{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.8);overflow:auto;z-index:100}#popover-content{position:absolute;width:70%;left:15%;top:1%;padding:15px;background:#fff;overflow:auto;max-height:90%}.popover-form{margin-bottom:0}.pagination{text-align:center}.pagination-next{margin-left:5px}.pagination-previous{margin-right:5px}header{box-sizing:border-box;display:flex;flex-wrap:wrap;margin-top:5px;margin-bottom:5px;border-bottom:1px solid #dedede}header>*{box-sizing:border-box}header>*{width:1%}header .menus-container{width:10%}@media (min-width: 768px) and (max-width: 1150px){header .menus-container{width:15%}}@media (max-width: 768px){header .menus-container{width:65%;order:2}}header .board-selector-container{width:15%}@media (min-width: 768px) and (max-width: 1150px){header .board-selector-container{width:20%}}@media (max-width: 768px){header .board-selector-container{width:35%;order:1;margin-bottom:5px}}header .title-container{width:75%}@media (min-width: 768px) and (max-width: 1150px){header .title-container{width:65%}}@media (max-width: 768px){header .title-container{width:100%;order:3}}header h1{font-size:1.5em}header h1 .tooltip{opacity:0.3;font-size:0.7em}.web-notification-icon{color:#36c}.web-notification-icon:focus,.web-notification-icon:hover{color:#000}.logo a{opacity:0.5;color:#d40000;text-decoration:none}.logo span{color:#333}.logo a:hover{opacity:0.8;color:#333}.logo a:focus span,.logo a:hover span{color:#d40000}.page-header{margin-bottom:20px}.page-header .dropdown{padding-right:10px}.page-header h2{margin:0;padding:0;font-weight:bold;border-bottom:1px dotted #ccc}.page-header h2 a{color:#333;text-decoration:none}.page-header h2 a:focus,.page-header h2 a:hover{color:#999}.page-header ul{text-align:left;margin-top:5px;display:inline-block}.page-header li{display:inline;padding-right:15px}@media (max-width: 480px){.page-header li{display:block;line-height:1.5em}}.page-header li.active a{color:#333;text-decoration:none;font-weight:bold}.page-header li.active a:hover,.page-header li.active a:focus{text-decoration:underline}.menu-inline{margin-bottom:5px}.menu-inline li{display:inline;padding-right:15px}.menu-inline li .active a{font-weight:bold;color:#000;text-decoration:none}.sidebar-container{box-sizing:border-box;display:flex;flex-wrap:wrap}.sidebar-container>*{box-sizing:border-box}.sidebar-container>*{width:1%}.sidebar-content{padding-left:10px;width:80%}@media (max-width: 480px){.sidebar-content{width:100%}}.sidebar{max-width:240px;min-width:190px;width:18%}@media (max-width: 480px){.sidebar{width:100%;max-width:99%;min-width:0}}.sidebar h2{margin-top:0}.sidebar>ul a{text-decoration:none;color:#999;font-weight:300}.sidebar>ul a:hover{color:#333}.sidebar>ul li{list-style-type:none;line-height:35px;border-bottom:1px dotted #efefef;padding-left:13px}.sidebar>ul li:hover{border-left:5px solid #555;padding-left:8px}.sidebar>ul li.active{border-left:5px solid #333;padding-left:8px}.sidebar>ul li.active a{color:#333;font-weight:bold}.sidebar-icons>ul li{padding-left:0}.sidebar-icons>ul li:hover,.sidebar-icons>ul li.active{padding-left:0;border-left:none}.sidebar>ul li.active a:focus,.sidebar>ul li.active a:hover{color:#555}.sidebar>ul li:last-child{margin-bottom:15px}.avatar img{vertical-align:bottom}.avatar-left{float:left;margin-right:10px}.avatar-inline{display:inline-block;margin-right:3px}.avatar-48 img,.avatar-48 div{border-radius:30px}.avatar-48 .avatar-letter{line-height:48px;width:48px;font-size:25px}.avatar-20 img,.avatar-20 div{border-radius:10px}.avatar-20 .avatar-letter{line-height:20px;width:20px;font-size:11px}.avatar-letter{color:#fff;text-align:center}#file-dropzone,#screenshot-zone{position:relative;border:2px dashed #ccc;width:99%;height:250px;overflow:auto}#file-dropzone-inner,#screenshot-inner{position:absolute;left:0;bottom:48%;width:100%;text-align:center;color:#aaa}#screenshot-zone.screenshot-pasted{border:2px solid #333}#file-list{margin:20px}#file-list li{list-style-type:none;padding-top:8px;padding-bottom:8px;border-bottom:1px dotted #ddd;width:95%}#file-list li.file-error{font-weight:bold;color:#b94a48}.color-picker{width:180px}.color-picker-option{height:25px}.color-picker-square{display:inline-block;width:18px;height:18px;margin-right:5px;border:1px solid #000}.color-picker-label{display:inline-block;vertical-align:bottom;padding-bottom:3px}.file-thumbnails{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;flex-wrap:wrap;-webkit-justify-content:flex-start;justify-content:flex-start}.file-thumbnail{width:250px;border:1px solid #efefef;border-radius:5px;margin-bottom:20px;box-shadow:4px 2px 10px -6px rgba(0,0,0,0.55);margin-right:15px}.file-thumbnail img{border-top-left-radius:5px;border-top-right-radius:5px}.file-thumbnail img:hover{opacity:0.5}.file-thumbnail-content{padding-left:8px;padding-right:8px}.file-thumbnail-title{font-weight:700;font-size:0.9em;color:#555}.file-thumbnail-description{font-size:0.8em;color:#999;margin-top:8px;margin-bottom:5px}.file-viewer{position:relative}.file-viewer img{max-width:95%;max-height:85%;margin-top:10px}.filter-box{max-width:800px}.project-header{margin-top:8px;margin-bottom:20px}.action-menu{color:#333;text-decoration:none}.action-menu:hover,.action-menu:focus{text-decoration:underline}.project-creation-options{max-width:500px;border-left:3px dotted #efefef;margin-top:20px;padding-left:15px;padding-bottom:5px;padding-top:5px}.project-overview-columns{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;align-items:center;-webkit-justify-content:center;justify-content:center;margin-bottom:20px;font-size:1.4em}.project-overview-column{text-align:center;margin-right:3%;padding:3px 15px 3px 15px;border:1px dashed #ddd}.project-overview-column small{color:#999}.project-overview-column strong{color:#555}.project-header{box-sizing:border-box;display:flex;flex-wrap:wrap}.project-header>*{box-sizing:border-box}.project-header>*{width:1%}.project-header .dropdown-component{width:5%}@media (min-width: 768px) and (max-width: 1150px){.project-header .dropdown-component{width:8%}}@media (max-width: 768px){.project-header .dropdown-component{width:100%}}.project-header .views-switcher-component{width:38%}@media (max-width: 1300px){.project-header .views-switcher-component{width:45%}}@media (min-width: 768px) and (max-width: 1150px){.project-header .views-switcher-component{width:92%}}@media (max-width: 768px){.project-header .views-switcher-component{width:100%}}.project-header .filter-box-component{margin:0;width:55%}@media (max-width: 1300px){.project-header .filter-box-component{width:50%}}@media (min-width: 768px) and (max-width: 1150px){.project-header .filter-box-component{width:100%;margin-top:10px}.project-header .filter-box-component .filter-box{max-width:100%}}@media (max-width: 768px){.project-header .filter-box-component{width:100%;margin-top:10px}.project-header .filter-box-component .filter-box{max-width:100%}}.project-header .filter-box-component form{margin:0}.views{display:inline-block;margin-right:10px;font-size:0.9em}@media (max-width: 560px){.views{width:100%}}@media (max-width: 768px){.views{margin-top:10px;font-size:1em}}.views li{white-space:nowrap;background:#fafafa;border:1px solid #ddd;border-right:none;padding:4px 8px;display:inline}@media (max-width: 560px){.views li{display:block;margin-top:5px;border-radius:5px;border:1px solid #ddd}}.views li.active a{font-weight:bold;color:#000;text-decoration:none}.views li:first-child{border-top-left-radius:5px;border-bottom-left-radius:5px}.views li:last-child{border-right:1px solid #ddd;border-top-right-radius:5px;border-bottom-right-radius:5px}.views a{color:#555;text-decoration:none}.views a:hover{color:#333;text-decoration:underline}.dashboard-project-stats small{margin-right:10px;color:#999}.dashboard-table-link{font-weight:bold;color:#000;text-decoration:none}.dashboard-table-link:focus,.dashboard-table-link:hover{color:#999}.public-board{margin-top:5px}.public-task{max-width:800px;margin:5px auto 0}#board-container{overflow-x:auto}#board{table-layout:fixed;margin-bottom:0}#board th.board-column-header{width:240px}#board td{vertical-align:top}.board-container-compact{overflow-x:initial}@media all and (-ms-high-contrast: active), (-ms-high-contrast: none){.board-container-compact #board{table-layout:auto}}#board th.board-column-header.board-column-compact{width:initial}.board-column-collapsed{display:none}td.board-column-task-collapsed{font-weight:bold;background-color:#fbfbfb}#board th.board-column-header-collapsed{width:28px;min-width:28px;text-align:center;overflow:hidden}.board-rotation-wrapper{position:relative;padding:8px 4px;min-height:150px;overflow:hidden}.board-rotation{white-space:nowrap;-webkit-backface-visibility:hidden;-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg);-webkit-transform-origin:0 100%;-moz-transform-origin:0 100%;-ms-transform-origin:0 100%;transform-origin:0 100%}.board-column-title .dropdown-menu{text-decoration:none}.board-add-icon{float:left;padding:0 5px}.board-add-icon a{text-decoration:none;color:#36c;font-size:1.6em;line-height:70%}.board-add-icon a:focus,.board-add-icon a:hover{text-decoration:none;color:red}.board-column-header-task-count{color:#999;font-weight:normal}a.board-swimlane-toggle{text-decoration:none}a.board-swimlane-toggle:hover,a.board-swimlane-toggle:focus{color:#000;text-decoration:none;border:none}.board-task-list{min-height:60px}.board-task-list-limit{background-color:#DF5353}.draggable-item{cursor:pointer;user-select:none;-webkit-user-select:none;-moz-user-select:none}.draggable-placeholder{border:2px dashed #000;background:#fafafa;height:70px;margin-bottom:10px}div.draggable-item-selected{border:1px solid #000}.task-board-sort-handle{float:left;padding-right:5px}.task-board{position:relative;margin-bottom:4px;border:1px solid #000;padding:2px;word-wrap:break-word;font-size:0.9em}div.task-board-recent{border-width:2px}div.task-board-status-closed{user-select:none;border:1px dotted #555}.task-board a{color:#000;text-decoration:none}.task-board .dropdown-menu{font-weight:bold}.task-board .task-score{font-weight:bold}.task-board-collapsed{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.task-board-title{margin-top:5px;margin-bottom:8px}.task-board-title a:hover{text-decoration:underline}.task-board-saving-state{opacity:0.3}.task-board-saving-icon{position:absolute;margin:auto;width:100%;text-align:center;color:#000}.task-board-category-container{text-align:right;margin-top:8px;margin-bottom:8px}.task-board-category{font-weight:500;color:#000;border:1px solid #555;padding:1px 2px 1px 2px;border-radius:4px}.task-board-category:hover{opacity:0.6}.task-board-avatars{text-align:right;float:right}.task-board-change-assignee{cursor:pointer}.task-board-change-assignee:hover{opacity:0.6}.task-board-icons{font-size:0.8em;text-align:right;margin-top:4px;margin-bottom:2px}.task-board-icons a{opacity:0.5}.task-board-icons span{opacity:0.5;margin-left:2px}.task-board-icons a:hover,.task-board-icons span:hover{opacity:1.0}.flag-milestone{color:green}.task-board-age{display:inline-block}span.task-board-age-total{border:#666 1px solid;padding:1px 3px 1px 3px;border-top-left-radius:3px;border-bottom-left-radius:3px}span.task-board-age-column{border:#666 1px solid;border-left:none;margin-left:-5px;padding:1px 3px 1px 3px;border-top-right-radius:3px;border-bottom-right-radius:3px}.task-board-date{font-weight:bold;color:#000}span.task-board-date-today{opacity:1.0}span.task-board-date-overdue{opacity:1.0}.task-tags li{display:inline;margin:0;margin-right:4px;padding:2px;color:#555;border:1px solid #666;border-radius:2px}.task-summary-container .task-tags{margin-top:10px}#task-summary{margin-bottom:15px}#task-summary h2{color:#555;font-size:1.6em;margin-top:0;padding-top:0}.task-summary-container{border:2px solid #000;border-radius:8px;padding:15px}.task-summary-columns{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-justify-content:space-between;justify-content:space-between}@media (max-width: 480px){.task-summary-columns{display:block}}.task-summary-column{color:#333}.task-summary-column span{color:#555}.task-summary-column li{line-height:23px}.task-table .dropdown-menu{color:#000;text-decoration:none;font-weight:bold}.task-table .dropdown-menu:focus,.task-table .dropdown-menu:hover{text-decoration:underline}td.task-table a{color:#000;text-decoration:none}td.task-table a:hover{text-decoration:underline}.comment-sorting{text-align:right}.comment-sorting a{color:#555;font-weight:normal;text-decoration:none}.comment-sorting a:hover{color:#999}.comment{padding:5px;margin-bottom:15px}.comment:hover{background:#fafafa}.comment-title{border-bottom:1px dotted #eee;margin-left:55px;margin-bottom:10px}.comment-date{color:#999;font-weight:200}.comment-actions{font-size:0.8em;margin-left:55px;margin-top:8px}.comment-actions li{display:inline}.comment-actions a{color:#999;text-decoration:none}.comment-actions a:focus,.comment-actions a:hover{color:#333;text-decoration:underline}.comment-content{margin-left:55px}.subtasks-table td{vertical-align:middle}.task-links-table td{vertical-align:middle}.task-links-task-count{color:#999}.task-link-closed{text-decoration:line-through}.markdown-editor-container{max-width:400px}div.CodeMirror,div.CodeMirror-scroll{max-height:250px;min-height:200px}.markdown-editor-small div.CodeMirror,.markdown-editor-small div.CodeMirror-scroll{min-height:100px;max-height:180px}.form-column div.CodeMirror{margin-bottom:10px}.markdown{line-height:1.4em}.markdown h1{margin-top:5px;margin-bottom:10px;font-weight:bold}.markdown h2{font-weight:bold}.markdown p{margin-bottom:10px}.markdown ol,.markdown ul{margin-left:25px;margin-top:10px;margin-bottom:10px}.markdown pre{background:#fbfbfb;padding:10px;border-radius:5px;border:1px solid #ddd;overflow:auto;color:#555}.markdown blockquote{font-style:italic;border-left:3px solid #ddd;padding-left:10px;margin-bottom:10px;margin-left:20px}.markdown img{display:block;max-width:80%;margin-top:10px}.documentation{margin:0 auto;padding:20px;max-width:850px;background:#fefefe;border:1px solid #ccc;border-radius:5px;color:#555}.documentation img{border:1px solid #333}.documentation h1{text-decoration:none;margin-bottom:30px}.documentation h2{text-decoration:none;border-bottom:1px solid #ccc;margin-bottom:25px}.documentation li{line-height:30px}.listing{border-radius:4px;padding:8px 35px 8px 14px;margin-bottom:20px;border:1px solid #ddd;color:#333;background-color:#fcfcfc;overflow:auto}.listing li{list-style-type:square;margin-left:20px;margin-bottom:3px}.listing ul{margin-top:15px;margin-bottom:15px}.activity-event{margin-bottom:15px;padding:10px}.activity-event:hover{background:#fafafa}.activity-date{margin-left:10px;font-weight:normal;color:#999}.activity-content{margin-left:55px}.activity-title{font-weight:bold;color:#000;border-bottom:1px dotted #efefef}.activity-description{color:#555;margin-top:10px}.activity-description li{list-style-type:circle}.activity-description ul{margin-top:10px;margin-left:20px}div.ganttview-hzheader-month,div.ganttview-hzheader-day,div.ganttview-vtheader,div.ganttview-vtheader-item-name,div.ganttview-vtheader-series,div.ganttview-grid,div.ganttview-grid-row-cell{float:left}div.ganttview-hzheader-month,div.ganttview-hzheader-day{text-align:center}div.ganttview-grid-row-cell.last,div.ganttview-hzheader-day.last,div.ganttview-hzheader-month.last{border-right:none}div.ganttview{border:1px solid #999}div.ganttview-hzheader-month{width:60px;height:20px;border-right:1px solid #d0d0d0;line-height:20px;overflow:hidden}div.ganttview-hzheader-day{width:20px;height:20px;border-right:1px solid #f0f0f0;border-top:1px solid #d0d0d0;line-height:20px;color:#555}div.ganttview-vtheader{margin-top:41px;width:400px;overflow:hidden;background-color:#fff}div.ganttview-vtheader-item{color:#555}div.ganttview-vtheader-series-name{width:400px;height:31px;line-height:31px;padding-left:3px;border-top:1px solid #d0d0d0;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}div.ganttview-vtheader-series-name a{color:#555;text-decoration:none}div.ganttview-vtheader-series-name a:hover{color:#333;text-decoration:underline}div.ganttview-vtheader-series-name a i{color:#000}div.ganttview-vtheader-series-name a:hover i{color:#555}div.ganttview-slide-container{overflow:auto;border-left:1px solid #999}div.ganttview-grid-row-cell{width:20px;height:31px;border-right:1px solid #f0f0f0;border-top:1px solid #f0f0f0}div.ganttview-grid-row-cell.ganttview-weekend{background-color:#fafafa}div.ganttview-blocks{margin-top:40px}div.ganttview-block-container{height:28px;padding-top:4px}div.ganttview-block{position:relative;height:25px;background-color:#E5ECF9;border:1px solid #c0c0c0;border-radius:3px}.ganttview-block-movable{cursor:move}div.ganttview-block-not-defined{border-color:#000;background-color:#000}div.ganttview-block-text{position:absolute;height:12px;font-size:0.7em;color:#999;padding:2px 3px}div.ganttview-block div.ui-resizable-handle.ui-resizable-s{bottom:-0}.user-mention-link{font-weight:bold;color:#000;text-decoration:none}.user-mention-link:hover{color:#555} +h1,li,ul,ol,table,tr,td,th,p,blockquote,body{margin:0;padding:0;font-size:100%}body{margin-left:10px;margin-right:10px;padding-bottom:10px;color:#333;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;text-rendering:optimizeLegibility}small{font-size:0.8em}hr{border:0;height:0;border-top:1px solid rgba(0,0,0,0.1);border-bottom:1px solid rgba(255,255,255,0.3)}.pull-right{text-align:right}ul.no-bullet li{list-style-type:none;margin-left:0}.chosen-select{min-height:27px}#app-loading-icon{position:fixed;right:3px;bottom:3px}.assign-me{vertical-align:bottom}a{color:#36c;border:none}a:focus{outline:0;color:#DF5353;text-decoration:none}a:hover{color:#333;text-decoration:none}h1,h2,h3{font-weight:normal;color:#333}h1{font-size:1.5em}h2{font-size:1.4em;margin-bottom:10px}h3{margin-top:10px;font-size:1.2em}table{width:100%;border-collapse:collapse;border-spacing:0;margin-bottom:20px}table.table-fixed{table-layout:fixed;white-space:nowrap}table.table-fixed th{overflow:hidden}table.table-fixed td{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}table.table-small{font-size:0.8em}table.table-striped tr:nth-child(odd){background:#fefefe}@media (max-width: 768px){table.table-scrolling{overflow-x:auto;display:inline-block;vertical-align:top;max-width:100%;white-space:nowrap}}table th{text-align:left;padding:0.5em 3px;border:1px solid #eee;background:#fbfbfb}table th a{text-decoration:none;color:#333}table th a:focus,table th a:hover{text-decoration:underline}table td{border:1px solid #eee;padding:0.5em 3px;vertical-align:top}table td li{margin-left:20px}.column-1{width:1%}.column-2{width:2%}.column-3{width:3%}.column-4{width:4%}.column-5{width:5%}.column-6{width:6%}.column-7{width:7%}.column-8{width:8%}.column-9{width:9%}.column-10{width:10%}.column-11{width:11%}.column-12{width:12%}.column-13{width:13%}.column-14{width:14%}.column-15{width:15%}.column-16{width:16%}.column-17{width:17%}.column-18{width:18%}.column-19{width:19%}.column-20{width:20%}.column-21{width:21%}.column-22{width:22%}.column-23{width:23%}.column-24{width:24%}.column-25{width:25%}.column-26{width:26%}.column-27{width:27%}.column-28{width:28%}.column-29{width:29%}.column-30{width:30%}.column-31{width:31%}.column-32{width:32%}.column-33{width:33%}.column-34{width:34%}.column-35{width:35%}.column-36{width:36%}.column-37{width:37%}.column-38{width:38%}.column-39{width:39%}.column-40{width:40%}.column-41{width:41%}.column-42{width:42%}.column-43{width:43%}.column-44{width:44%}.column-45{width:45%}.column-46{width:46%}.column-47{width:47%}.column-48{width:48%}.column-49{width:49%}.column-50{width:50%}.column-51{width:51%}.column-52{width:52%}.column-53{width:53%}.column-54{width:54%}.column-55{width:55%}.column-56{width:56%}.column-57{width:57%}.column-58{width:58%}.column-59{width:59%}.column-60{width:60%}.column-61{width:61%}.column-62{width:62%}.column-63{width:63%}.column-64{width:64%}.column-65{width:65%}.column-66{width:66%}.column-67{width:67%}.column-68{width:68%}.column-69{width:69%}.column-70{width:70%}.column-71{width:71%}.column-72{width:72%}.column-73{width:73%}.column-74{width:74%}.column-75{width:75%}.column-76{width:76%}.column-77{width:77%}.column-78{width:78%}.column-79{width:79%}.column-80{width:80%}.column-81{width:81%}.column-82{width:82%}.column-83{width:83%}.column-84{width:84%}.column-85{width:85%}.column-86{width:86%}.column-87{width:87%}.column-88{width:88%}.column-89{width:89%}.column-90{width:90%}.column-91{width:91%}.column-92{width:92%}.column-93{width:93%}.column-94{width:94%}.column-95{width:95%}.column-96{width:96%}.column-97{width:97%}.column-98{width:98%}.column-99{width:99%}.column-100{width:100%}.draggable-row-handle{cursor:move;color:#dedede}.draggable-row-handle:hover{color:#333}tr.draggable-item-selected{background:#fff;border:2px solid #666;box-shadow:4px 2px 10px -4px rgba(0,0,0,0.55)}tr.draggable-item-selected td{border-top:none;border-bottom:none}tr.draggable-item-selected td:first-child{border-left:none}tr.draggable-item-selected td:last-child{border-right:none}.table-stripped tr.draggable-item-hover,.table-stripped tr.draggable-item-hover{background:#FEFFF2}form{margin-bottom:20px}label{cursor:pointer;display:block;margin-top:10px}input[type="number"],input[type="date"],input[type="email"],input[type="password"],input[type="text"]:not(.input-addon-field){color:#999;border:1px solid #ccc;width:300px;max-width:95%;font-size:1em;height:25px;padding-bottom:0;font-family:sans-serif;margin-top:10px;-webkit-appearance:none;-moz-appearance:none}input[type="number"]::-webkit-input-placeholder,input[type="date"]::-webkit-input-placeholder,input[type="email"]::-webkit-input-placeholder,input[type="password"]::-webkit-input-placeholder,input[type="text"]:not(.input-addon-field)::-webkit-input-placeholder{color:#dedede}input[type="number"]:-moz-placeholder,input[type="date"]:-moz-placeholder,input[type="email"]:-moz-placeholder,input[type="password"]:-moz-placeholder,input[type="text"]:not(.input-addon-field):-moz-placeholder{color:#dedede}input[type="number"]::-moz-placeholder,input[type="date"]::-moz-placeholder,input[type="email"]::-moz-placeholder,input[type="password"]::-moz-placeholder,input[type="text"]:not(.input-addon-field)::-moz-placeholder{color:#dedede}input[type="number"]:-ms-input-placeholder,input[type="date"]:-ms-input-placeholder,input[type="email"]:-ms-input-placeholder,input[type="password"]:-ms-input-placeholder,input[type="text"]:not(.input-addon-field):-ms-input-placeholder{color:#dedede}input[type="number"]:focus,input[type="date"]:focus,input[type="email"]:focus,input[type="password"]:focus,input[type="text"]:focus{color:#000;border-color:rgba(82,168,236,0.8);outline:0;box-shadow:0 0 8px rgba(82,168,236,0.6)}input[type="number"]{width:70px}input[type="text"]:not(.input-addon-field).form-numeric{width:70px}input[type="text"]:not(.input-addon-field).form-datetime,input[type="text"]:not(.input-addon-field).form-date{width:150px}input[type="text"]:not(.input-addon-field).form-input-large{width:400px}input[type="text"]:not(.input-addon-field).form-input-small{width:150px}textarea:focus{color:#000;border-color:rgba(82,168,236,0.8);outline:0;box-shadow:0 0 8px rgba(82,168,236,0.6)}textarea{border:1px solid #ccc;width:400px;max-width:99%;height:200px;font-family:sans-serif}select{max-width:95%}select:focus{outline:0}.tag-autocomplete{width:400px}span.select2-container{margin-top:2px}.form-actions{padding-top:20px;clear:both}input.form-error,textarea.form-error{border:2px solid #b94a48}input.form-error:focus,textarea.form-error:focus{box-shadow:none;border:2px solid #b94a48}.form-required{color:red;padding-left:5px;font-weight:bold}.form-errors{color:#b94a48;list-style-type:none}ul.form-errors li{margin-left:0}.form-help{font-size:0.8em;color:brown;margin-bottom:15px}.form-inline{padding:0;margin:0;border:none}.form-inline label{display:inline}.form-inline input,.form-inline select{margin:0 15px 0 0}.form-inline .form-required{display:none}.form-inline-group{display:inline}.form-columns{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row}.form-column{margin-right:25px}.form-login{width:350px;margin:8% auto 0}.form-login li{margin-left:25px;line-height:25px}.form-login h2{margin-bottom:30px;font-weight:bold}.reset-password{margin-top:20px}.reset-password a{color:#999}.input-addon{display:flex}.input-addon-field{flex:1;font-size:1em;color:#999;margin:0;-webkit-appearance:none;-moz-appearance:none}.input-addon-item{background-color:rgba(147,128,108,0.1);color:#666;font:inherit;font-weight:normal}@media (max-width: 480px){.input-addon-item .dropdown .fa-caret-down{display:none}}.input-addon-field,.input-addon-item{border:1px solid rgba(147,128,108,0.25);padding:4px 0.75em}.input-addon-field:not(:first-child),.input-addon-item:not(:first-child){border-left:0}.input-addon-field:first-child,.input-addon-item:first-child{border-radius:5px 0 0 5px}.input-addon-field:last-child,.input-addon-item:last-child{border-radius:0 5px 5px 0}.alert{padding:8px 35px 8px 14px;margin-top:5px;margin-bottom:5px;color:#c09853;background-color:#fcf8e3;border:1px solid #fbeed5;border-radius:4px}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-normal{color:#333;background-color:#f0f0f0;border-color:#ddd}.alert ul{margin-top:10px;margin-bottom:10px}.alert li{margin-left:25px}.alert-fade-out{text-align:center;position:fixed;bottom:0;left:20%;width:60%;padding-top:5px;padding-bottom:5px;margin-bottom:0;border-width:1px 0 0;border-radius:4px 4px 0 0;z-index:9999}a.btn{text-decoration:none}.btn{-webkit-appearance:none;-moz-appearance:none;font-size:1.2em;font-weight:normal;cursor:pointer;display:inline-block;border-radius:2px;padding:3px 10px;margin:0;border:1px solid #ddd;background:#f5f5f5;color:#333}.btn:hover,.btn:focus{border-color:#bbb;background:#fafafa;color:#000}.btn-red{border-color:#b0281a;background:#d14836;color:#fff}.btn-red:hover,.btn-red:focus{border-color:#b0281a;background:#c53727;color:#fff}.btn-blue{border-color:#3079ed;background:#4d90fe;color:#fff}.btn-blue:hover,.btn-blue:focus{border-color:#3079ed;background:#357ae8;color:#fff}.btn:disabled{color:#ccc;border-color:#ccc;background:#f7f7f7}.buttons-header{font-size:0.8em;margin-top:5px;margin-bottom:15px}.tooltip-arrow:after{background:#fff;border:1px solid #aaaaaa;box-shadow:0 0 5px #aaa}div.ui-tooltip{min-width:200px;max-width:600px}.tooltip-arrow{width:20px;height:10px;overflow:hidden;position:absolute}.tooltip-arrow.top{top:-10px}.tooltip-arrow.bottom{bottom:-10px}.tooltip-arrow.align-left{left:10px}.tooltip-arrow.align-right{right:10px}.tooltip-arrow:after{content:"";position:absolute;width:14px;height:14px;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg)}.tooltip-arrow.bottom:after{top:-10px}.tooltip-arrow.top:after{bottom:-10px}.tooltip-arrow.align-left:after{left:0}.tooltip-arrow.align-right:after{right:0}.tooltip-large{width:600px}.ui-tooltip-content .markdown p{margin-bottom:0}.ui-tooltip li{list-style-type:none}.tooltip .fa-info-circle{color:#999}.dropdown{display:inline;position:relative}.dropdown ul{display:none}ul.dropdown-submenu-open{display:block;position:absolute;z-index:1000;min-width:285px;list-style:none;margin:3px 0 0 1px;padding:6px 0;background-color:#fff;border:1px solid #b2b2b2;border-radius:3px;box-shadow:0 1px 3px rgba(0,0,0,0.15)}.dropdown-submenu-open li{display:block;margin:0;padding:8px 10px;font-size:0.9em;border-bottom:1px solid #f8f8f8;cursor:pointer}.dropdown-submenu-open li.no-hover{cursor:default}.dropdown-submenu-open li:last-child{border:none}.dropdown-submenu-open li:not(.no-hover):hover{background:#4078C0;color:#fff}.dropdown-submenu-open li:hover a{color:#fff}.dropdown-submenu-open a{text-decoration:none;color:#333}.dropdown-submenu-open a:focus{text-decoration:underline}.dropdown-menu-link-text,.dropdown-menu-link-icon{color:#333;text-decoration:none}.dropdown-menu-link-text:hover{text-decoration:underline}.accordion-title{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAADCAYAAABS3WWCAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NEQ5RDgxQzc2RjQ5MTFFMjhEMUNENzFGRUMwRjhBRTciIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NEQ5RDgxQzg2RjQ5MTFFMjhEMUNENzFGRUMwRjhBRTciPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo0RDlEODFDNTZGNDkxMUUyOEQxQ0Q3MUZFQzBGOEFFNyIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo0RDlEODFDNjZGNDkxMUUyOEQxQ0Q3MUZFQzBGOEFFNyIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PvXFWFAAAAAYSURBVHjaYvj//z8D0/Pnz/8zgFgAAQYAS5UJscReGMIAAAAASUVORK5CYII=) repeat-x scroll 0 10px}.accordion-title h3{display:inline;padding-right:5px;background:#fff}.accordion-content{margin-top:15px;margin-bottom:25px}.accordion-toggle{color:#333;text-decoration:none}.accordion-toggle:focus{color:#333}.accordion-toggle:hover{color:#999}.accordion-toggle:before{content:"\f0d7"}.accordion-collapsed{margin-bottom:25px}.accordion-collapsed .accordion-toggle:before{content:"\f0da"}.accordion-collapsed .accordion-content{display:none}#main .confirm{max-width:700px}#popover-container{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.8);overflow:auto;z-index:100}#popover-content{position:absolute;width:70%;left:15%;top:1%;padding:15px;background:#fff;overflow:auto;max-height:90%}.popover-form{margin-bottom:0}.pagination{text-align:center}.pagination-next{margin-left:5px}.pagination-previous{margin-right:5px}header{box-sizing:border-box;display:flex;flex-wrap:wrap;margin-top:5px;margin-bottom:5px;border-bottom:1px solid #dedede}header>*{box-sizing:border-box}header>*{width:1%}header .menus-container{width:10%}@media (min-width: 768px) and (max-width: 1150px){header .menus-container{width:15%}}@media (max-width: 768px){header .menus-container{width:65%;order:2}}header .board-selector-container{width:15%}@media (min-width: 768px) and (max-width: 1150px){header .board-selector-container{width:20%}}@media (max-width: 768px){header .board-selector-container{width:35%;order:1;margin-bottom:5px}}header .title-container{width:75%}@media (min-width: 768px) and (max-width: 1150px){header .title-container{width:65%}}@media (max-width: 768px){header .title-container{width:100%;order:3}}header h1{font-size:1.5em}header h1 .tooltip{opacity:0.3;font-size:0.7em}.web-notification-icon{color:#36c}.web-notification-icon:focus,.web-notification-icon:hover{color:#000}.logo a{opacity:0.5;color:#d40000;text-decoration:none}.logo span{color:#333}.logo a:hover{opacity:0.8;color:#333}.logo a:focus span,.logo a:hover span{color:#d40000}.page-header{margin-bottom:20px}.page-header .dropdown{padding-right:10px}.page-header h2{margin:0;padding:0;font-weight:bold;border-bottom:1px dotted #ccc}.page-header h2 a{color:#333;text-decoration:none}.page-header h2 a:focus,.page-header h2 a:hover{color:#999}.page-header ul{text-align:left;margin-top:5px;display:inline-block}.page-header li{display:inline;padding-right:15px}@media (max-width: 480px){.page-header li{display:block;line-height:1.5em}}.page-header li.active a{color:#333;text-decoration:none;font-weight:bold}.page-header li.active a:hover,.page-header li.active a:focus{text-decoration:underline}.menu-inline{margin-bottom:5px}.menu-inline li{display:inline;padding-right:15px}.menu-inline li .active a{font-weight:bold;color:#000;text-decoration:none}.sidebar-container{box-sizing:border-box;display:flex;flex-wrap:wrap}.sidebar-container>*{box-sizing:border-box}.sidebar-container>*{width:1%}.sidebar-content{padding-left:10px;width:82%}@media (max-width: 480px){.sidebar-content{width:100%}}.sidebar{max-width:240px;min-width:190px;width:18%}@media (max-width: 480px){.sidebar{width:100%;max-width:99%;min-width:0}}.sidebar h2{margin-top:0}.sidebar>ul a{text-decoration:none;color:#999;font-weight:300}.sidebar>ul a:hover{color:#333}.sidebar>ul li{list-style-type:none;line-height:35px;border-bottom:1px dotted #efefef;padding-left:13px}.sidebar>ul li:hover{border-left:5px solid #555;padding-left:8px}.sidebar>ul li.active{border-left:5px solid #333;padding-left:8px}.sidebar>ul li.active a{color:#333;font-weight:bold}.sidebar-icons>ul li{padding-left:0}.sidebar-icons>ul li:hover,.sidebar-icons>ul li.active{padding-left:0;border-left:none}.sidebar>ul li.active a:focus,.sidebar>ul li.active a:hover{color:#555}.sidebar>ul li:last-child{margin-bottom:15px}.avatar img{vertical-align:bottom}.avatar-left{float:left;margin-right:10px}.avatar-inline{display:inline-block;margin-right:3px}.avatar-48 img,.avatar-48 div{border-radius:30px}.avatar-48 .avatar-letter{line-height:48px;width:48px;font-size:25px}.avatar-20 img,.avatar-20 div{border-radius:10px}.avatar-20 .avatar-letter{line-height:20px;width:20px;font-size:11px}.avatar-letter{color:#fff;text-align:center}#file-dropzone,#screenshot-zone{position:relative;border:2px dashed #ccc;width:99%;height:250px;overflow:auto}#file-dropzone-inner,#screenshot-inner{position:absolute;left:0;bottom:48%;width:100%;text-align:center;color:#aaa}#screenshot-zone.screenshot-pasted{border:2px solid #333}#file-list{margin:20px}#file-list li{list-style-type:none;padding-top:8px;padding-bottom:8px;border-bottom:1px dotted #ddd;width:95%}#file-list li.file-error{font-weight:bold;color:#b94a48}.color-picker{width:180px}.color-picker-option{height:25px}.color-picker-square{display:inline-block;width:18px;height:18px;margin-right:5px;border:1px solid #000}.color-picker-label{display:inline-block;vertical-align:bottom;padding-bottom:3px}.file-thumbnails{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;flex-wrap:wrap;-webkit-justify-content:flex-start;justify-content:flex-start}.file-thumbnail{width:250px;border:1px solid #efefef;border-radius:5px;margin-bottom:20px;box-shadow:4px 2px 10px -6px rgba(0,0,0,0.55);margin-right:15px}.file-thumbnail img{border-top-left-radius:5px;border-top-right-radius:5px}.file-thumbnail img:hover{opacity:0.5}.file-thumbnail-content{padding-left:8px;padding-right:8px}.file-thumbnail-title{font-weight:700;font-size:0.9em;color:#555}.file-thumbnail-description{font-size:0.8em;color:#999;margin-top:8px;margin-bottom:5px}.file-viewer{position:relative}.file-viewer img{max-width:95%;max-height:85%;margin-top:10px}.filter-box{max-width:800px}.project-header{margin-top:8px;margin-bottom:20px}.action-menu{color:#333;text-decoration:none}.action-menu:hover,.action-menu:focus{text-decoration:underline}.project-creation-options{max-width:500px;border-left:3px dotted #efefef;margin-top:20px;padding-left:15px;padding-bottom:5px;padding-top:5px}.project-overview-columns{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;align-items:center;-webkit-justify-content:center;justify-content:center;margin-bottom:20px;font-size:1.4em}.project-overview-column{text-align:center;margin-right:3%;padding:3px 15px 3px 15px;border:1px dashed #ddd}.project-overview-column small{color:#999}.project-overview-column strong{color:#555}.project-header{box-sizing:border-box;display:flex;flex-wrap:wrap}.project-header>*{box-sizing:border-box}.project-header>*{width:1%}.project-header .dropdown-component{width:5%}@media (min-width: 768px) and (max-width: 1150px){.project-header .dropdown-component{width:8%}}@media (max-width: 768px){.project-header .dropdown-component{width:100%}}.project-header .views-switcher-component{width:38%}@media (max-width: 1300px){.project-header .views-switcher-component{width:45%}}@media (min-width: 768px) and (max-width: 1150px){.project-header .views-switcher-component{width:92%}}@media (max-width: 768px){.project-header .views-switcher-component{width:100%}}.project-header .filter-box-component{margin:0;width:55%}@media (max-width: 1300px){.project-header .filter-box-component{width:50%}}@media (min-width: 768px) and (max-width: 1150px){.project-header .filter-box-component{width:100%;margin-top:10px}.project-header .filter-box-component .filter-box{max-width:100%}}@media (max-width: 768px){.project-header .filter-box-component{width:100%;margin-top:10px}.project-header .filter-box-component .filter-box{max-width:100%}}.project-header .filter-box-component form{margin:0}.views{display:inline-block;margin-right:10px;font-size:0.9em}@media (max-width: 560px){.views{width:100%}}@media (max-width: 768px){.views{margin-top:10px;font-size:1em}}.views li{white-space:nowrap;background:#fafafa;border:1px solid #ddd;border-right:none;padding:4px 8px;display:inline}@media (max-width: 560px){.views li{display:block;margin-top:5px;border-radius:5px;border:1px solid #ddd}}.views li.active a{font-weight:bold;color:#000;text-decoration:none}.views li:first-child{border-top-left-radius:5px;border-bottom-left-radius:5px}.views li:last-child{border-right:1px solid #ddd;border-top-right-radius:5px;border-bottom-right-radius:5px}.views a{color:#555;text-decoration:none}.views a:hover{color:#333;text-decoration:underline}.dashboard-project-stats small{margin-right:10px;color:#999}.dashboard-table-link{font-weight:bold;color:#000;text-decoration:none}.dashboard-table-link:focus,.dashboard-table-link:hover{color:#999}.public-board{margin-top:5px}.public-task{max-width:800px;margin:5px auto 0}#board-container{overflow-x:auto}#board{table-layout:fixed;margin-bottom:0}#board th.board-column-header{width:240px}#board td{vertical-align:top}.board-container-compact{overflow-x:initial}@media all and (-ms-high-contrast: active), (-ms-high-contrast: none){.board-container-compact #board{table-layout:auto}}#board th.board-column-header.board-column-compact{width:initial}.board-column-collapsed{display:none}td.board-column-task-collapsed{font-weight:bold;background-color:#fbfbfb}#board th.board-column-header-collapsed{width:28px;min-width:28px;text-align:center;overflow:hidden}.board-rotation-wrapper{position:relative;padding:8px 4px;min-height:150px;overflow:hidden}.board-rotation{white-space:nowrap;-webkit-backface-visibility:hidden;-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg);-webkit-transform-origin:0 100%;-moz-transform-origin:0 100%;-ms-transform-origin:0 100%;transform-origin:0 100%}.board-column-title .dropdown-menu{text-decoration:none}.board-add-icon{float:left;padding:0 5px}.board-add-icon a{text-decoration:none;color:#36c;font-size:1.6em;line-height:70%}.board-add-icon a:focus,.board-add-icon a:hover{text-decoration:none;color:red}.board-column-header-task-count{color:#999;font-weight:normal}a.board-swimlane-toggle{text-decoration:none}a.board-swimlane-toggle:hover,a.board-swimlane-toggle:focus{color:#000;text-decoration:none;border:none}.board-task-list{min-height:60px}.board-task-list-limit{background-color:#DF5353}.draggable-item{cursor:pointer;user-select:none;-webkit-user-select:none;-moz-user-select:none}.draggable-placeholder{border:2px dashed #000;background:#fafafa;height:70px;margin-bottom:10px}div.draggable-item-selected{border:1px solid #000}.task-board-sort-handle{float:left;padding-right:5px}.task-board{position:relative;margin-bottom:4px;border:1px solid #000;padding:2px;word-wrap:break-word;font-size:0.9em}div.task-board-recent{border-width:2px}div.task-board-status-closed{user-select:none;border:1px dotted #555}.task-board a{color:#000;text-decoration:none}.task-board .dropdown-menu{font-weight:bold}.task-board .task-score{font-weight:bold}.task-board-collapsed{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.task-board-title{margin-top:5px;margin-bottom:8px}.task-board-title a:hover{text-decoration:underline}.task-board-saving-state{opacity:0.3}.task-board-saving-icon{position:absolute;margin:auto;width:100%;text-align:center;color:#000}.task-board-category-container{text-align:right;margin-top:8px;margin-bottom:8px}.task-board-category{font-weight:500;color:#000;border:1px solid #555;padding:1px 2px 1px 2px;border-radius:4px}.task-board-category:hover{opacity:0.6}.task-board-avatars{text-align:right;float:right}.task-board-change-assignee{cursor:pointer}.task-board-change-assignee:hover{opacity:0.6}.task-board-icons{font-size:0.8em;text-align:right;margin-top:4px;margin-bottom:2px}.task-board-icons a{opacity:0.5}.task-board-icons span{opacity:0.5;margin-left:2px}.task-board-icons a:hover,.task-board-icons span:hover{opacity:1.0}.flag-milestone{color:green}.task-board-age{display:inline-block}span.task-board-age-total{border:#666 1px solid;padding:1px 3px 1px 3px;border-top-left-radius:3px;border-bottom-left-radius:3px}span.task-board-age-column{border:#666 1px solid;border-left:none;margin-left:-5px;padding:1px 3px 1px 3px;border-top-right-radius:3px;border-bottom-right-radius:3px}.task-board-date{font-weight:bold;color:#000}span.task-board-date-today{opacity:1.0}span.task-board-date-overdue{opacity:1.0}.task-tags li{display:inline;margin:0;margin-right:4px;padding:2px;color:#555;border:1px solid #666;border-radius:2px}.task-summary-container .task-tags{margin-top:10px}#task-summary{margin-bottom:15px}#task-summary h2{color:#555;font-size:1.6em;margin-top:0;padding-top:0}.task-summary-container{border:2px solid #000;border-radius:8px;padding:15px}.task-summary-columns{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-justify-content:space-between;justify-content:space-between}@media (max-width: 480px){.task-summary-columns{display:block}}.task-summary-column{color:#333}.task-summary-column span{color:#555}.task-summary-column li{line-height:23px}.task-table .dropdown-menu{color:#000;text-decoration:none;font-weight:bold}.task-table .dropdown-menu:focus,.task-table .dropdown-menu:hover{text-decoration:underline}td.task-table a{color:#000;text-decoration:none}td.task-table a:hover{text-decoration:underline}.comment-sorting{text-align:right}.comment-sorting a{color:#555;font-weight:normal;text-decoration:none}.comment-sorting a:hover{color:#999}.comment{padding:5px;margin-bottom:15px}.comment:hover{background:#fafafa}.comment-title{border-bottom:1px dotted #eee;margin-left:55px;margin-bottom:10px}.comment-date{color:#999;font-weight:200}.comment-actions{font-size:0.8em;margin-left:55px;margin-top:8px}.comment-actions li{display:inline}.comment-actions a{color:#999;text-decoration:none}.comment-actions a:focus,.comment-actions a:hover{color:#333;text-decoration:underline}.comment-content{margin-left:55px}.subtasks-table td{vertical-align:middle}.task-links-table td{vertical-align:middle}.task-links-task-count{color:#999}.task-link-closed{text-decoration:line-through}.markdown-editor-container{max-width:400px}div.CodeMirror,div.CodeMirror-scroll{max-height:250px;min-height:200px}.markdown-editor-small div.CodeMirror,.markdown-editor-small div.CodeMirror-scroll{min-height:100px;max-height:180px}.form-column div.CodeMirror{margin-bottom:10px}.markdown{line-height:1.4em}.markdown h1{margin-top:5px;margin-bottom:10px;font-weight:bold}.markdown h2{font-weight:bold}.markdown p{margin-bottom:10px}.markdown ol,.markdown ul{margin-left:25px;margin-top:10px;margin-bottom:10px}.markdown pre{background:#fbfbfb;padding:10px;border-radius:5px;border:1px solid #ddd;overflow:auto;color:#555}.markdown blockquote{font-style:italic;border-left:3px solid #ddd;padding-left:10px;margin-bottom:10px;margin-left:20px}.markdown img{display:block;max-width:80%;margin-top:10px}.documentation{margin:0 auto;padding:20px;max-width:850px;background:#fefefe;border:1px solid #ccc;border-radius:5px;color:#555}.documentation img{border:1px solid #333}.documentation h1{text-decoration:none;margin-bottom:30px}.documentation h2{text-decoration:none;border-bottom:1px solid #ccc;margin-bottom:25px}.documentation li{line-height:30px}.listing{border-radius:4px;padding:8px 35px 8px 14px;margin-bottom:20px;border:1px solid #ddd;color:#333;background-color:#fcfcfc;overflow:auto}.listing li{list-style-type:square;margin-left:20px;margin-bottom:3px}.listing ul{margin-top:15px;margin-bottom:15px}.activity-event{margin-bottom:15px;padding:10px}.activity-event:hover{background:#fafafa}.activity-date{margin-left:10px;font-weight:normal;color:#999}.activity-content{margin-left:55px}.activity-title{font-weight:bold;color:#000;border-bottom:1px dotted #efefef}.activity-description{color:#555;margin-top:10px}.activity-description li{list-style-type:circle}.activity-description ul{margin-top:10px;margin-left:20px}div.ganttview-hzheader-month,div.ganttview-hzheader-day,div.ganttview-vtheader,div.ganttview-vtheader-item-name,div.ganttview-vtheader-series,div.ganttview-grid,div.ganttview-grid-row-cell{float:left}div.ganttview-hzheader-month,div.ganttview-hzheader-day{text-align:center}div.ganttview-grid-row-cell.last,div.ganttview-hzheader-day.last,div.ganttview-hzheader-month.last{border-right:none}div.ganttview{border:1px solid #999}div.ganttview-hzheader-month{width:60px;height:20px;border-right:1px solid #d0d0d0;line-height:20px;overflow:hidden}div.ganttview-hzheader-day{width:20px;height:20px;border-right:1px solid #f0f0f0;border-top:1px solid #d0d0d0;line-height:20px;color:#555}div.ganttview-vtheader{margin-top:41px;width:400px;overflow:hidden;background-color:#fff}div.ganttview-vtheader-item{color:#555}div.ganttview-vtheader-series-name{width:400px;height:31px;line-height:31px;padding-left:3px;border-top:1px solid #d0d0d0;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}div.ganttview-vtheader-series-name a{color:#555;text-decoration:none}div.ganttview-vtheader-series-name a:hover{color:#333;text-decoration:underline}div.ganttview-vtheader-series-name a i{color:#000}div.ganttview-vtheader-series-name a:hover i{color:#555}div.ganttview-slide-container{overflow:auto;border-left:1px solid #999}div.ganttview-grid-row-cell{width:20px;height:31px;border-right:1px solid #f0f0f0;border-top:1px solid #f0f0f0}div.ganttview-grid-row-cell.ganttview-weekend{background-color:#fafafa}div.ganttview-blocks{margin-top:40px}div.ganttview-block-container{height:28px;padding-top:4px}div.ganttview-block{position:relative;height:25px;background-color:#E5ECF9;border:1px solid #c0c0c0;border-radius:3px}.ganttview-block-movable{cursor:move}div.ganttview-block-not-defined{border-color:#000;background-color:#000}div.ganttview-block-text{position:absolute;height:12px;font-size:0.7em;color:#999;padding:2px 3px}div.ganttview-block div.ui-resizable-handle.ui-resizable-s{bottom:-0}.user-mention-link{font-weight:bold;color:#000;text-decoration:none}.user-mention-link:hover{color:#555} diff --git a/assets/sass/_mixins.sass b/assets/sass/_mixins.sass index 9b913a56..6addea7a 100644 --- a/assets/sass/_mixins.sass +++ b/assets/sass/_mixins.sass @@ -37,3 +37,8 @@ @content &:-ms-input-placeholder @content + +@mixin col-x($n) + @for $i from 1 through $n + .column-#{$i} + width: $i * 1% diff --git a/assets/sass/_sidebar.sass b/assets/sass/_sidebar.sass index 075f3ed4..80390e16 100644 --- a/assets/sass/_sidebar.sass +++ b/assets/sass/_sidebar.sass @@ -5,7 +5,7 @@ .sidebar-content padding-left: 10px - @include grid_width(80/100) + @include grid_width(82/100) @include xs-device @include grid_width(1) diff --git a/assets/sass/_table.sass b/assets/sass/_table.sass index de535ed1..c570ef16 100644 --- a/assets/sass/_table.sass +++ b/assets/sass/_table.sass @@ -1,4 +1,5 @@ @import variables +@import mixins table width: 100% @@ -6,106 +7,48 @@ table border-spacing: 0 margin-bottom: 20px -th - border: 1px solid #eee - padding: 0.5em 3px - -td - border: 1px solid #eee - padding: 0.5em 3px - vertical-align: top - -th - background: bg-color('primary') - text-align: left - -td li - margin-left: 20px - -.table-small - font-size: size('small') - -th a - text-decoration: none - color: color('primary') - &:focus, &:hover - text-decoration: underline - -.table-fixed - table-layout: fixed - white-space: nowrap - th - overflow: hidden - td + &.table-fixed + table-layout: fixed white-space: nowrap - overflow: hidden - text-overflow: ellipsis - -.table-stripped tr:nth-child(odd) - background: #fefefe - -.column-3 - width: 3% - -.column-5 - width: 5% - -.column-8 - width: 7.5% - -.column-10 - width: 10% + th + overflow: hidden + td + white-space: nowrap + overflow: hidden + text-overflow: ellipsis + + &.table-small + font-size: size('small') + + &.table-striped tr:nth-child(odd) + background: bg-color('lighter') + + &.table-scrolling + @include sm-device + overflow-x: auto + display: inline-block + vertical-align: top + max-width: 100% + white-space: nowrap -.column-12 - width: 12% - -.column-15 - width: 15% - -.column-18 - width: 18% - -.column-20 - width: 20% - -.column-25 - width: 25% - -.column-30 - width: 30% - -.column-35 - width: 35% - -.column-40 - width: 40% - -.column-50 - width: 50% - -.column-60 - width: 60% - -.column-70, .column-80 - width: 70% + th + text-align: left + padding: 0.5em 3px + border: 1px solid #eee + background: bg-color('primary') -.draggable-row-handle - cursor: move - color: #dedede - &:hover - color: color('primary') + a + text-decoration: none + color: color('primary') + &:focus, &:hover + text-decoration: underline -tr.draggable-item-selected - background: #fff - border: 2px solid #666 - box-shadow: 4px 2px 10px -4px rgba(0, 0, 0, 0.55) td - border-top: none - border-bottom: none - &:first-child - border-left: none - &:last-child - border-right: none + border: 1px solid #eee + padding: 0.5em 3px + vertical-align: top + + li + margin-left: 20px -.table-stripped tr.draggable-item-hover, tr.draggable-item-hover - background: #FEFFF2 +@include col-x(100) diff --git a/assets/sass/_table_drag_and_drop.sass b/assets/sass/_table_drag_and_drop.sass new file mode 100644 index 00000000..80f7e7fe --- /dev/null +++ b/assets/sass/_table_drag_and_drop.sass @@ -0,0 +1,23 @@ +@import variables + +.draggable-row-handle + cursor: move + color: color('lighter') + &:hover + color: color('primary') + +tr.draggable-item-selected + background: #fff + border: 2px solid #666 + box-shadow: 4px 2px 10px -4px rgba(0, 0, 0, 0.55) + td + border-top: none + border-bottom: none + &:first-child + border-left: none + &:last-child + border-right: none + +.table-stripped + tr.draggable-item-hover, tr.draggable-item-hover + background: #FEFFF2 diff --git a/assets/sass/_variables.sass b/assets/sass/_variables.sass index bd41e291..c557219c 100644 --- a/assets/sass/_variables.sass +++ b/assets/sass/_variables.sass @@ -4,7 +4,7 @@ $md-device-width: 1150px $colors: ('primary': #333, 'light': #999, 'lighter': #dedede, 'dark': #000, 'medium': #555, 'error': #b94a48) $link-colors: ('primary': #3366CC, 'focus': #DF5353, 'hover': #333) -$background-colors: ('primary': #fbfbfb, 'light': #fcfcfc) +$background-colors: ('primary': #fbfbfb, 'light': #fcfcfc, 'lighter': #fefefe) $alert-colors: ('default': #c09853, 'success': #468847, 'error': #b94a48, 'info': #3a87ad, 'normal': #333) $alert-background-colors: ('default': #fcf8e3, 'success': #dff0d8, 'error': #f2dede, 'info': #d9edf7, 'normal': #f0f0f0) diff --git a/assets/sass/app.sass b/assets/sass/app.sass index ce06fd8c..8c109ebb 100644 --- a/assets/sass/app.sass +++ b/assets/sass/app.sass @@ -3,6 +3,7 @@ @import links @import title @import table +@import table_drag_and_drop @import form @import input_addon @import alert -- cgit v1.2.3 From cb73946751942abb261eea3a8a2af6fabbc2a371 Mon Sep 17 00:00:00 2001 From: Frederic Guillot Date: Sun, 14 Aug 2016 13:46:46 -0400 Subject: Make project overview page more responsive --- app/Template/project_overview/columns.php | 2 +- assets/css/app.min.css | 2 +- assets/sass/_activity_stream.sass | 3 +++ assets/sass/_project_overview.sass | 11 +++++++++++ 4 files changed, 16 insertions(+), 2 deletions(-) (limited to 'app') diff --git a/app/Template/project_overview/columns.php b/app/Template/project_overview/columns.php index bed78043..daae9ca7 100644 --- a/app/Template/project_overview/columns.php +++ b/app/Template/project_overview/columns.php @@ -1,7 +1,7 @@
-
+ text->e($column['title']) ?>
diff --git a/assets/css/app.min.css b/assets/css/app.min.css index dc46461f..d2214072 100644 --- a/assets/css/app.min.css +++ b/assets/css/app.min.css @@ -1 +1 @@ -h1,li,ul,ol,table,tr,td,th,p,blockquote,body{margin:0;padding:0;font-size:100%}body{margin-left:10px;margin-right:10px;padding-bottom:10px;color:#333;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;text-rendering:optimizeLegibility}small{font-size:0.8em}hr{border:0;height:0;border-top:1px solid rgba(0,0,0,0.1);border-bottom:1px solid rgba(255,255,255,0.3)}.pull-right{text-align:right}ul.no-bullet li{list-style-type:none;margin-left:0}.chosen-select{min-height:27px}#app-loading-icon{position:fixed;right:3px;bottom:3px}.assign-me{vertical-align:bottom}a{color:#36c;border:none}a:focus{outline:0;color:#DF5353;text-decoration:none}a:hover{color:#333;text-decoration:none}h1,h2,h3{font-weight:normal;color:#333}h1{font-size:1.5em}h2{font-size:1.4em;margin-bottom:10px}h3{margin-top:10px;font-size:1.2em}table{width:100%;border-collapse:collapse;border-spacing:0;margin-bottom:20px}table.table-fixed{table-layout:fixed;white-space:nowrap}table.table-fixed th{overflow:hidden}table.table-fixed td{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}table.table-small{font-size:0.8em}table.table-striped tr:nth-child(odd){background:#fefefe}@media (max-width: 768px){table.table-scrolling{overflow-x:auto;display:inline-block;vertical-align:top;max-width:100%;white-space:nowrap}}table th{text-align:left;padding:0.5em 3px;border:1px solid #eee;background:#fbfbfb}table th a{text-decoration:none;color:#333}table th a:focus,table th a:hover{text-decoration:underline}table td{border:1px solid #eee;padding:0.5em 3px;vertical-align:top}table td li{margin-left:20px}.column-1{width:1%}.column-2{width:2%}.column-3{width:3%}.column-4{width:4%}.column-5{width:5%}.column-6{width:6%}.column-7{width:7%}.column-8{width:8%}.column-9{width:9%}.column-10{width:10%}.column-11{width:11%}.column-12{width:12%}.column-13{width:13%}.column-14{width:14%}.column-15{width:15%}.column-16{width:16%}.column-17{width:17%}.column-18{width:18%}.column-19{width:19%}.column-20{width:20%}.column-21{width:21%}.column-22{width:22%}.column-23{width:23%}.column-24{width:24%}.column-25{width:25%}.column-26{width:26%}.column-27{width:27%}.column-28{width:28%}.column-29{width:29%}.column-30{width:30%}.column-31{width:31%}.column-32{width:32%}.column-33{width:33%}.column-34{width:34%}.column-35{width:35%}.column-36{width:36%}.column-37{width:37%}.column-38{width:38%}.column-39{width:39%}.column-40{width:40%}.column-41{width:41%}.column-42{width:42%}.column-43{width:43%}.column-44{width:44%}.column-45{width:45%}.column-46{width:46%}.column-47{width:47%}.column-48{width:48%}.column-49{width:49%}.column-50{width:50%}.column-51{width:51%}.column-52{width:52%}.column-53{width:53%}.column-54{width:54%}.column-55{width:55%}.column-56{width:56%}.column-57{width:57%}.column-58{width:58%}.column-59{width:59%}.column-60{width:60%}.column-61{width:61%}.column-62{width:62%}.column-63{width:63%}.column-64{width:64%}.column-65{width:65%}.column-66{width:66%}.column-67{width:67%}.column-68{width:68%}.column-69{width:69%}.column-70{width:70%}.column-71{width:71%}.column-72{width:72%}.column-73{width:73%}.column-74{width:74%}.column-75{width:75%}.column-76{width:76%}.column-77{width:77%}.column-78{width:78%}.column-79{width:79%}.column-80{width:80%}.column-81{width:81%}.column-82{width:82%}.column-83{width:83%}.column-84{width:84%}.column-85{width:85%}.column-86{width:86%}.column-87{width:87%}.column-88{width:88%}.column-89{width:89%}.column-90{width:90%}.column-91{width:91%}.column-92{width:92%}.column-93{width:93%}.column-94{width:94%}.column-95{width:95%}.column-96{width:96%}.column-97{width:97%}.column-98{width:98%}.column-99{width:99%}.column-100{width:100%}.draggable-row-handle{cursor:move;color:#dedede}.draggable-row-handle:hover{color:#333}tr.draggable-item-selected{background:#fff;border:2px solid #666;box-shadow:4px 2px 10px -4px rgba(0,0,0,0.55)}tr.draggable-item-selected td{border-top:none;border-bottom:none}tr.draggable-item-selected td:first-child{border-left:none}tr.draggable-item-selected td:last-child{border-right:none}.table-stripped tr.draggable-item-hover,.table-stripped tr.draggable-item-hover{background:#FEFFF2}form{margin-bottom:20px}label{cursor:pointer;display:block;margin-top:10px}input[type="number"],input[type="date"],input[type="email"],input[type="password"],input[type="text"]:not(.input-addon-field){color:#999;border:1px solid #ccc;width:300px;max-width:95%;font-size:1em;height:25px;padding-bottom:0;font-family:sans-serif;margin-top:10px;-webkit-appearance:none;-moz-appearance:none}input[type="number"]::-webkit-input-placeholder,input[type="date"]::-webkit-input-placeholder,input[type="email"]::-webkit-input-placeholder,input[type="password"]::-webkit-input-placeholder,input[type="text"]:not(.input-addon-field)::-webkit-input-placeholder{color:#dedede}input[type="number"]:-moz-placeholder,input[type="date"]:-moz-placeholder,input[type="email"]:-moz-placeholder,input[type="password"]:-moz-placeholder,input[type="text"]:not(.input-addon-field):-moz-placeholder{color:#dedede}input[type="number"]::-moz-placeholder,input[type="date"]::-moz-placeholder,input[type="email"]::-moz-placeholder,input[type="password"]::-moz-placeholder,input[type="text"]:not(.input-addon-field)::-moz-placeholder{color:#dedede}input[type="number"]:-ms-input-placeholder,input[type="date"]:-ms-input-placeholder,input[type="email"]:-ms-input-placeholder,input[type="password"]:-ms-input-placeholder,input[type="text"]:not(.input-addon-field):-ms-input-placeholder{color:#dedede}input[type="number"]:focus,input[type="date"]:focus,input[type="email"]:focus,input[type="password"]:focus,input[type="text"]:focus{color:#000;border-color:rgba(82,168,236,0.8);outline:0;box-shadow:0 0 8px rgba(82,168,236,0.6)}input[type="number"]{width:70px}input[type="text"]:not(.input-addon-field).form-numeric{width:70px}input[type="text"]:not(.input-addon-field).form-datetime,input[type="text"]:not(.input-addon-field).form-date{width:150px}input[type="text"]:not(.input-addon-field).form-input-large{width:400px}input[type="text"]:not(.input-addon-field).form-input-small{width:150px}textarea:focus{color:#000;border-color:rgba(82,168,236,0.8);outline:0;box-shadow:0 0 8px rgba(82,168,236,0.6)}textarea{border:1px solid #ccc;width:400px;max-width:99%;height:200px;font-family:sans-serif}select{max-width:95%}select:focus{outline:0}.tag-autocomplete{width:400px}span.select2-container{margin-top:2px}.form-actions{padding-top:20px;clear:both}input.form-error,textarea.form-error{border:2px solid #b94a48}input.form-error:focus,textarea.form-error:focus{box-shadow:none;border:2px solid #b94a48}.form-required{color:red;padding-left:5px;font-weight:bold}.form-errors{color:#b94a48;list-style-type:none}ul.form-errors li{margin-left:0}.form-help{font-size:0.8em;color:brown;margin-bottom:15px}.form-inline{padding:0;margin:0;border:none}.form-inline label{display:inline}.form-inline input,.form-inline select{margin:0 15px 0 0}.form-inline .form-required{display:none}.form-inline-group{display:inline}.form-columns{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row}.form-column{margin-right:25px}.form-login{width:350px;margin:8% auto 0}.form-login li{margin-left:25px;line-height:25px}.form-login h2{margin-bottom:30px;font-weight:bold}.reset-password{margin-top:20px}.reset-password a{color:#999}.input-addon{display:flex}.input-addon-field{flex:1;font-size:1em;color:#999;margin:0;-webkit-appearance:none;-moz-appearance:none}.input-addon-item{background-color:rgba(147,128,108,0.1);color:#666;font:inherit;font-weight:normal}@media (max-width: 480px){.input-addon-item .dropdown .fa-caret-down{display:none}}.input-addon-field,.input-addon-item{border:1px solid rgba(147,128,108,0.25);padding:4px 0.75em}.input-addon-field:not(:first-child),.input-addon-item:not(:first-child){border-left:0}.input-addon-field:first-child,.input-addon-item:first-child{border-radius:5px 0 0 5px}.input-addon-field:last-child,.input-addon-item:last-child{border-radius:0 5px 5px 0}.alert{padding:8px 35px 8px 14px;margin-top:5px;margin-bottom:5px;color:#c09853;background-color:#fcf8e3;border:1px solid #fbeed5;border-radius:4px}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-normal{color:#333;background-color:#f0f0f0;border-color:#ddd}.alert ul{margin-top:10px;margin-bottom:10px}.alert li{margin-left:25px}.alert-fade-out{text-align:center;position:fixed;bottom:0;left:20%;width:60%;padding-top:5px;padding-bottom:5px;margin-bottom:0;border-width:1px 0 0;border-radius:4px 4px 0 0;z-index:9999}a.btn{text-decoration:none}.btn{-webkit-appearance:none;-moz-appearance:none;font-size:1.2em;font-weight:normal;cursor:pointer;display:inline-block;border-radius:2px;padding:3px 10px;margin:0;border:1px solid #ddd;background:#f5f5f5;color:#333}.btn:hover,.btn:focus{border-color:#bbb;background:#fafafa;color:#000}.btn-red{border-color:#b0281a;background:#d14836;color:#fff}.btn-red:hover,.btn-red:focus{border-color:#b0281a;background:#c53727;color:#fff}.btn-blue{border-color:#3079ed;background:#4d90fe;color:#fff}.btn-blue:hover,.btn-blue:focus{border-color:#3079ed;background:#357ae8;color:#fff}.btn:disabled{color:#ccc;border-color:#ccc;background:#f7f7f7}.buttons-header{font-size:0.8em;margin-top:5px;margin-bottom:15px}.tooltip-arrow:after{background:#fff;border:1px solid #aaaaaa;box-shadow:0 0 5px #aaa}div.ui-tooltip{min-width:200px;max-width:600px}.tooltip-arrow{width:20px;height:10px;overflow:hidden;position:absolute}.tooltip-arrow.top{top:-10px}.tooltip-arrow.bottom{bottom:-10px}.tooltip-arrow.align-left{left:10px}.tooltip-arrow.align-right{right:10px}.tooltip-arrow:after{content:"";position:absolute;width:14px;height:14px;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg)}.tooltip-arrow.bottom:after{top:-10px}.tooltip-arrow.top:after{bottom:-10px}.tooltip-arrow.align-left:after{left:0}.tooltip-arrow.align-right:after{right:0}.tooltip-large{width:600px}.ui-tooltip-content .markdown p{margin-bottom:0}.ui-tooltip li{list-style-type:none}.tooltip .fa-info-circle{color:#999}.dropdown{display:inline;position:relative}.dropdown ul{display:none}ul.dropdown-submenu-open{display:block;position:absolute;z-index:1000;min-width:285px;list-style:none;margin:3px 0 0 1px;padding:6px 0;background-color:#fff;border:1px solid #b2b2b2;border-radius:3px;box-shadow:0 1px 3px rgba(0,0,0,0.15)}.dropdown-submenu-open li{display:block;margin:0;padding:8px 10px;font-size:0.9em;border-bottom:1px solid #f8f8f8;cursor:pointer}.dropdown-submenu-open li.no-hover{cursor:default}.dropdown-submenu-open li:last-child{border:none}.dropdown-submenu-open li:not(.no-hover):hover{background:#4078C0;color:#fff}.dropdown-submenu-open li:hover a{color:#fff}.dropdown-submenu-open a{text-decoration:none;color:#333}.dropdown-submenu-open a:focus{text-decoration:underline}.dropdown-menu-link-text,.dropdown-menu-link-icon{color:#333;text-decoration:none}.dropdown-menu-link-text:hover{text-decoration:underline}.accordion-title{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAADCAYAAABS3WWCAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NEQ5RDgxQzc2RjQ5MTFFMjhEMUNENzFGRUMwRjhBRTciIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NEQ5RDgxQzg2RjQ5MTFFMjhEMUNENzFGRUMwRjhBRTciPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo0RDlEODFDNTZGNDkxMUUyOEQxQ0Q3MUZFQzBGOEFFNyIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo0RDlEODFDNjZGNDkxMUUyOEQxQ0Q3MUZFQzBGOEFFNyIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PvXFWFAAAAAYSURBVHjaYvj//z8D0/Pnz/8zgFgAAQYAS5UJscReGMIAAAAASUVORK5CYII=) repeat-x scroll 0 10px}.accordion-title h3{display:inline;padding-right:5px;background:#fff}.accordion-content{margin-top:15px;margin-bottom:25px}.accordion-toggle{color:#333;text-decoration:none}.accordion-toggle:focus{color:#333}.accordion-toggle:hover{color:#999}.accordion-toggle:before{content:"\f0d7"}.accordion-collapsed{margin-bottom:25px}.accordion-collapsed .accordion-toggle:before{content:"\f0da"}.accordion-collapsed .accordion-content{display:none}#main .confirm{max-width:700px}#popover-container{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.8);overflow:auto;z-index:100}#popover-content{position:absolute;width:70%;left:15%;top:1%;padding:15px;background:#fff;overflow:auto;max-height:90%}.popover-form{margin-bottom:0}.pagination{text-align:center}.pagination-next{margin-left:5px}.pagination-previous{margin-right:5px}header{box-sizing:border-box;display:flex;flex-wrap:wrap;margin-top:5px;margin-bottom:5px;border-bottom:1px solid #dedede}header>*{box-sizing:border-box}header>*{width:1%}header .menus-container{width:10%}@media (min-width: 768px) and (max-width: 1150px){header .menus-container{width:15%}}@media (max-width: 768px){header .menus-container{width:65%;order:2}}header .board-selector-container{width:15%}@media (min-width: 768px) and (max-width: 1150px){header .board-selector-container{width:20%}}@media (max-width: 768px){header .board-selector-container{width:35%;order:1;margin-bottom:5px}}header .title-container{width:75%}@media (min-width: 768px) and (max-width: 1150px){header .title-container{width:65%}}@media (max-width: 768px){header .title-container{width:100%;order:3}}header h1{font-size:1.5em}header h1 .tooltip{opacity:0.3;font-size:0.7em}.web-notification-icon{color:#36c}.web-notification-icon:focus,.web-notification-icon:hover{color:#000}.logo a{opacity:0.5;color:#d40000;text-decoration:none}.logo span{color:#333}.logo a:hover{opacity:0.8;color:#333}.logo a:focus span,.logo a:hover span{color:#d40000}.page-header{margin-bottom:20px}.page-header .dropdown{padding-right:10px}.page-header h2{margin:0;padding:0;font-weight:bold;border-bottom:1px dotted #ccc}.page-header h2 a{color:#333;text-decoration:none}.page-header h2 a:focus,.page-header h2 a:hover{color:#999}.page-header ul{text-align:left;margin-top:5px;display:inline-block}.page-header li{display:inline;padding-right:15px}@media (max-width: 480px){.page-header li{display:block;line-height:1.5em}}.page-header li.active a{color:#333;text-decoration:none;font-weight:bold}.page-header li.active a:hover,.page-header li.active a:focus{text-decoration:underline}.menu-inline{margin-bottom:5px}.menu-inline li{display:inline;padding-right:15px}.menu-inline li .active a{font-weight:bold;color:#000;text-decoration:none}.sidebar-container{box-sizing:border-box;display:flex;flex-wrap:wrap}.sidebar-container>*{box-sizing:border-box}.sidebar-container>*{width:1%}.sidebar-content{padding-left:10px;width:82%}@media (max-width: 480px){.sidebar-content{width:100%}}.sidebar{max-width:240px;min-width:190px;width:18%}@media (max-width: 480px){.sidebar{width:100%;max-width:99%;min-width:0}}.sidebar h2{margin-top:0}.sidebar>ul a{text-decoration:none;color:#999;font-weight:300}.sidebar>ul a:hover{color:#333}.sidebar>ul li{list-style-type:none;line-height:35px;border-bottom:1px dotted #efefef;padding-left:13px}.sidebar>ul li:hover{border-left:5px solid #555;padding-left:8px}.sidebar>ul li.active{border-left:5px solid #333;padding-left:8px}.sidebar>ul li.active a{color:#333;font-weight:bold}.sidebar-icons>ul li{padding-left:0}.sidebar-icons>ul li:hover,.sidebar-icons>ul li.active{padding-left:0;border-left:none}.sidebar>ul li.active a:focus,.sidebar>ul li.active a:hover{color:#555}.sidebar>ul li:last-child{margin-bottom:15px}.avatar img{vertical-align:bottom}.avatar-left{float:left;margin-right:10px}.avatar-inline{display:inline-block;margin-right:3px}.avatar-48 img,.avatar-48 div{border-radius:30px}.avatar-48 .avatar-letter{line-height:48px;width:48px;font-size:25px}.avatar-20 img,.avatar-20 div{border-radius:10px}.avatar-20 .avatar-letter{line-height:20px;width:20px;font-size:11px}.avatar-letter{color:#fff;text-align:center}#file-dropzone,#screenshot-zone{position:relative;border:2px dashed #ccc;width:99%;height:250px;overflow:auto}#file-dropzone-inner,#screenshot-inner{position:absolute;left:0;bottom:48%;width:100%;text-align:center;color:#aaa}#screenshot-zone.screenshot-pasted{border:2px solid #333}#file-list{margin:20px}#file-list li{list-style-type:none;padding-top:8px;padding-bottom:8px;border-bottom:1px dotted #ddd;width:95%}#file-list li.file-error{font-weight:bold;color:#b94a48}.color-picker{width:180px}.color-picker-option{height:25px}.color-picker-square{display:inline-block;width:18px;height:18px;margin-right:5px;border:1px solid #000}.color-picker-label{display:inline-block;vertical-align:bottom;padding-bottom:3px}.file-thumbnails{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;flex-wrap:wrap;-webkit-justify-content:flex-start;justify-content:flex-start}.file-thumbnail{width:250px;border:1px solid #efefef;border-radius:5px;margin-bottom:20px;box-shadow:4px 2px 10px -6px rgba(0,0,0,0.55);margin-right:15px}.file-thumbnail img{border-top-left-radius:5px;border-top-right-radius:5px}.file-thumbnail img:hover{opacity:0.5}.file-thumbnail-content{padding-left:8px;padding-right:8px}.file-thumbnail-title{font-weight:700;font-size:0.9em;color:#555}.file-thumbnail-description{font-size:0.8em;color:#999;margin-top:8px;margin-bottom:5px}.file-viewer{position:relative}.file-viewer img{max-width:95%;max-height:85%;margin-top:10px}.filter-box{max-width:800px}.project-header{margin-top:8px;margin-bottom:20px}.action-menu{color:#333;text-decoration:none}.action-menu:hover,.action-menu:focus{text-decoration:underline}.project-creation-options{max-width:500px;border-left:3px dotted #efefef;margin-top:20px;padding-left:15px;padding-bottom:5px;padding-top:5px}.project-overview-columns{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;align-items:center;-webkit-justify-content:center;justify-content:center;margin-bottom:20px;font-size:1.4em}.project-overview-column{text-align:center;margin-right:3%;padding:3px 15px 3px 15px;border:1px dashed #ddd}.project-overview-column small{color:#999}.project-overview-column strong{color:#555}.project-header{box-sizing:border-box;display:flex;flex-wrap:wrap}.project-header>*{box-sizing:border-box}.project-header>*{width:1%}.project-header .dropdown-component{width:5%}@media (min-width: 768px) and (max-width: 1150px){.project-header .dropdown-component{width:8%}}@media (max-width: 768px){.project-header .dropdown-component{width:100%}}.project-header .views-switcher-component{width:38%}@media (max-width: 1300px){.project-header .views-switcher-component{width:45%}}@media (min-width: 768px) and (max-width: 1150px){.project-header .views-switcher-component{width:92%}}@media (max-width: 768px){.project-header .views-switcher-component{width:100%}}.project-header .filter-box-component{margin:0;width:55%}@media (max-width: 1300px){.project-header .filter-box-component{width:50%}}@media (min-width: 768px) and (max-width: 1150px){.project-header .filter-box-component{width:100%;margin-top:10px}.project-header .filter-box-component .filter-box{max-width:100%}}@media (max-width: 768px){.project-header .filter-box-component{width:100%;margin-top:10px}.project-header .filter-box-component .filter-box{max-width:100%}}.project-header .filter-box-component form{margin:0}.views{display:inline-block;margin-right:10px;font-size:0.9em}@media (max-width: 560px){.views{width:100%}}@media (max-width: 768px){.views{margin-top:10px;font-size:1em}}.views li{white-space:nowrap;background:#fafafa;border:1px solid #ddd;border-right:none;padding:4px 8px;display:inline}@media (max-width: 560px){.views li{display:block;margin-top:5px;border-radius:5px;border:1px solid #ddd}}.views li.active a{font-weight:bold;color:#000;text-decoration:none}.views li:first-child{border-top-left-radius:5px;border-bottom-left-radius:5px}.views li:last-child{border-right:1px solid #ddd;border-top-right-radius:5px;border-bottom-right-radius:5px}.views a{color:#555;text-decoration:none}.views a:hover{color:#333;text-decoration:underline}.dashboard-project-stats small{margin-right:10px;color:#999}.dashboard-table-link{font-weight:bold;color:#000;text-decoration:none}.dashboard-table-link:focus,.dashboard-table-link:hover{color:#999}.public-board{margin-top:5px}.public-task{max-width:800px;margin:5px auto 0}#board-container{overflow-x:auto}#board{table-layout:fixed;margin-bottom:0}#board th.board-column-header{width:240px}#board td{vertical-align:top}.board-container-compact{overflow-x:initial}@media all and (-ms-high-contrast: active), (-ms-high-contrast: none){.board-container-compact #board{table-layout:auto}}#board th.board-column-header.board-column-compact{width:initial}.board-column-collapsed{display:none}td.board-column-task-collapsed{font-weight:bold;background-color:#fbfbfb}#board th.board-column-header-collapsed{width:28px;min-width:28px;text-align:center;overflow:hidden}.board-rotation-wrapper{position:relative;padding:8px 4px;min-height:150px;overflow:hidden}.board-rotation{white-space:nowrap;-webkit-backface-visibility:hidden;-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg);-webkit-transform-origin:0 100%;-moz-transform-origin:0 100%;-ms-transform-origin:0 100%;transform-origin:0 100%}.board-column-title .dropdown-menu{text-decoration:none}.board-add-icon{float:left;padding:0 5px}.board-add-icon a{text-decoration:none;color:#36c;font-size:1.6em;line-height:70%}.board-add-icon a:focus,.board-add-icon a:hover{text-decoration:none;color:red}.board-column-header-task-count{color:#999;font-weight:normal}a.board-swimlane-toggle{text-decoration:none}a.board-swimlane-toggle:hover,a.board-swimlane-toggle:focus{color:#000;text-decoration:none;border:none}.board-task-list{min-height:60px}.board-task-list-limit{background-color:#DF5353}.draggable-item{cursor:pointer;user-select:none;-webkit-user-select:none;-moz-user-select:none}.draggable-placeholder{border:2px dashed #000;background:#fafafa;height:70px;margin-bottom:10px}div.draggable-item-selected{border:1px solid #000}.task-board-sort-handle{float:left;padding-right:5px}.task-board{position:relative;margin-bottom:4px;border:1px solid #000;padding:2px;word-wrap:break-word;font-size:0.9em}div.task-board-recent{border-width:2px}div.task-board-status-closed{user-select:none;border:1px dotted #555}.task-board a{color:#000;text-decoration:none}.task-board .dropdown-menu{font-weight:bold}.task-board .task-score{font-weight:bold}.task-board-collapsed{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.task-board-title{margin-top:5px;margin-bottom:8px}.task-board-title a:hover{text-decoration:underline}.task-board-saving-state{opacity:0.3}.task-board-saving-icon{position:absolute;margin:auto;width:100%;text-align:center;color:#000}.task-board-category-container{text-align:right;margin-top:8px;margin-bottom:8px}.task-board-category{font-weight:500;color:#000;border:1px solid #555;padding:1px 2px 1px 2px;border-radius:4px}.task-board-category:hover{opacity:0.6}.task-board-avatars{text-align:right;float:right}.task-board-change-assignee{cursor:pointer}.task-board-change-assignee:hover{opacity:0.6}.task-board-icons{font-size:0.8em;text-align:right;margin-top:4px;margin-bottom:2px}.task-board-icons a{opacity:0.5}.task-board-icons span{opacity:0.5;margin-left:2px}.task-board-icons a:hover,.task-board-icons span:hover{opacity:1.0}.flag-milestone{color:green}.task-board-age{display:inline-block}span.task-board-age-total{border:#666 1px solid;padding:1px 3px 1px 3px;border-top-left-radius:3px;border-bottom-left-radius:3px}span.task-board-age-column{border:#666 1px solid;border-left:none;margin-left:-5px;padding:1px 3px 1px 3px;border-top-right-radius:3px;border-bottom-right-radius:3px}.task-board-date{font-weight:bold;color:#000}span.task-board-date-today{opacity:1.0}span.task-board-date-overdue{opacity:1.0}.task-tags li{display:inline;margin:0;margin-right:4px;padding:2px;color:#555;border:1px solid #666;border-radius:2px}.task-summary-container .task-tags{margin-top:10px}#task-summary{margin-bottom:15px}#task-summary h2{color:#555;font-size:1.6em;margin-top:0;padding-top:0}.task-summary-container{border:2px solid #000;border-radius:8px;padding:15px}.task-summary-columns{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-justify-content:space-between;justify-content:space-between}@media (max-width: 480px){.task-summary-columns{display:block}}.task-summary-column{color:#333}.task-summary-column span{color:#555}.task-summary-column li{line-height:23px}.task-table .dropdown-menu{color:#000;text-decoration:none;font-weight:bold}.task-table .dropdown-menu:focus,.task-table .dropdown-menu:hover{text-decoration:underline}td.task-table a{color:#000;text-decoration:none}td.task-table a:hover{text-decoration:underline}.comment-sorting{text-align:right}.comment-sorting a{color:#555;font-weight:normal;text-decoration:none}.comment-sorting a:hover{color:#999}.comment{padding:5px;margin-bottom:15px}.comment:hover{background:#fafafa}.comment-title{border-bottom:1px dotted #eee;margin-left:55px;margin-bottom:10px}.comment-date{color:#999;font-weight:200}.comment-actions{font-size:0.8em;margin-left:55px;margin-top:8px}.comment-actions li{display:inline}.comment-actions a{color:#999;text-decoration:none}.comment-actions a:focus,.comment-actions a:hover{color:#333;text-decoration:underline}.comment-content{margin-left:55px}.subtasks-table td{vertical-align:middle}.task-links-table td{vertical-align:middle}.task-links-task-count{color:#999}.task-link-closed{text-decoration:line-through}.markdown-editor-container{max-width:400px}div.CodeMirror,div.CodeMirror-scroll{max-height:250px;min-height:200px}.markdown-editor-small div.CodeMirror,.markdown-editor-small div.CodeMirror-scroll{min-height:100px;max-height:180px}.form-column div.CodeMirror{margin-bottom:10px}.markdown{line-height:1.4em}.markdown h1{margin-top:5px;margin-bottom:10px;font-weight:bold}.markdown h2{font-weight:bold}.markdown p{margin-bottom:10px}.markdown ol,.markdown ul{margin-left:25px;margin-top:10px;margin-bottom:10px}.markdown pre{background:#fbfbfb;padding:10px;border-radius:5px;border:1px solid #ddd;overflow:auto;color:#555}.markdown blockquote{font-style:italic;border-left:3px solid #ddd;padding-left:10px;margin-bottom:10px;margin-left:20px}.markdown img{display:block;max-width:80%;margin-top:10px}.documentation{margin:0 auto;padding:20px;max-width:850px;background:#fefefe;border:1px solid #ccc;border-radius:5px;color:#555}.documentation img{border:1px solid #333}.documentation h1{text-decoration:none;margin-bottom:30px}.documentation h2{text-decoration:none;border-bottom:1px solid #ccc;margin-bottom:25px}.documentation li{line-height:30px}.listing{border-radius:4px;padding:8px 35px 8px 14px;margin-bottom:20px;border:1px solid #ddd;color:#333;background-color:#fcfcfc;overflow:auto}.listing li{list-style-type:square;margin-left:20px;margin-bottom:3px}.listing ul{margin-top:15px;margin-bottom:15px}.activity-event{margin-bottom:15px;padding:10px}.activity-event:hover{background:#fafafa}.activity-date{margin-left:10px;font-weight:normal;color:#999}.activity-content{margin-left:55px}.activity-title{font-weight:bold;color:#000;border-bottom:1px dotted #efefef}.activity-description{color:#555;margin-top:10px}.activity-description li{list-style-type:circle}.activity-description ul{margin-top:10px;margin-left:20px}div.ganttview-hzheader-month,div.ganttview-hzheader-day,div.ganttview-vtheader,div.ganttview-vtheader-item-name,div.ganttview-vtheader-series,div.ganttview-grid,div.ganttview-grid-row-cell{float:left}div.ganttview-hzheader-month,div.ganttview-hzheader-day{text-align:center}div.ganttview-grid-row-cell.last,div.ganttview-hzheader-day.last,div.ganttview-hzheader-month.last{border-right:none}div.ganttview{border:1px solid #999}div.ganttview-hzheader-month{width:60px;height:20px;border-right:1px solid #d0d0d0;line-height:20px;overflow:hidden}div.ganttview-hzheader-day{width:20px;height:20px;border-right:1px solid #f0f0f0;border-top:1px solid #d0d0d0;line-height:20px;color:#555}div.ganttview-vtheader{margin-top:41px;width:400px;overflow:hidden;background-color:#fff}div.ganttview-vtheader-item{color:#555}div.ganttview-vtheader-series-name{width:400px;height:31px;line-height:31px;padding-left:3px;border-top:1px solid #d0d0d0;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}div.ganttview-vtheader-series-name a{color:#555;text-decoration:none}div.ganttview-vtheader-series-name a:hover{color:#333;text-decoration:underline}div.ganttview-vtheader-series-name a i{color:#000}div.ganttview-vtheader-series-name a:hover i{color:#555}div.ganttview-slide-container{overflow:auto;border-left:1px solid #999}div.ganttview-grid-row-cell{width:20px;height:31px;border-right:1px solid #f0f0f0;border-top:1px solid #f0f0f0}div.ganttview-grid-row-cell.ganttview-weekend{background-color:#fafafa}div.ganttview-blocks{margin-top:40px}div.ganttview-block-container{height:28px;padding-top:4px}div.ganttview-block{position:relative;height:25px;background-color:#E5ECF9;border:1px solid #c0c0c0;border-radius:3px}.ganttview-block-movable{cursor:move}div.ganttview-block-not-defined{border-color:#000;background-color:#000}div.ganttview-block-text{position:absolute;height:12px;font-size:0.7em;color:#999;padding:2px 3px}div.ganttview-block div.ui-resizable-handle.ui-resizable-s{bottom:-0}.user-mention-link{font-weight:bold;color:#000;text-decoration:none}.user-mention-link:hover{color:#555} +h1,li,ul,ol,table,tr,td,th,p,blockquote,body{margin:0;padding:0;font-size:100%}body{margin-left:10px;margin-right:10px;padding-bottom:10px;color:#333;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;text-rendering:optimizeLegibility}small{font-size:0.8em}hr{border:0;height:0;border-top:1px solid rgba(0,0,0,0.1);border-bottom:1px solid rgba(255,255,255,0.3)}.pull-right{text-align:right}ul.no-bullet li{list-style-type:none;margin-left:0}.chosen-select{min-height:27px}#app-loading-icon{position:fixed;right:3px;bottom:3px}.assign-me{vertical-align:bottom}a{color:#36c;border:none}a:focus{outline:0;color:#DF5353;text-decoration:none}a:hover{color:#333;text-decoration:none}h1,h2,h3{font-weight:normal;color:#333}h1{font-size:1.5em}h2{font-size:1.4em;margin-bottom:10px}h3{margin-top:10px;font-size:1.2em}table{width:100%;border-collapse:collapse;border-spacing:0;margin-bottom:20px}table.table-fixed{table-layout:fixed;white-space:nowrap}table.table-fixed th{overflow:hidden}table.table-fixed td{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}table.table-small{font-size:0.8em}table.table-striped tr:nth-child(odd){background:#fefefe}@media (max-width: 768px){table.table-scrolling{overflow-x:auto;display:inline-block;vertical-align:top;max-width:100%;white-space:nowrap}}table th{text-align:left;padding:0.5em 3px;border:1px solid #eee;background:#fbfbfb}table th a{text-decoration:none;color:#333}table th a:focus,table th a:hover{text-decoration:underline}table td{border:1px solid #eee;padding:0.5em 3px;vertical-align:top}table td li{margin-left:20px}.column-1{width:1%}.column-2{width:2%}.column-3{width:3%}.column-4{width:4%}.column-5{width:5%}.column-6{width:6%}.column-7{width:7%}.column-8{width:8%}.column-9{width:9%}.column-10{width:10%}.column-11{width:11%}.column-12{width:12%}.column-13{width:13%}.column-14{width:14%}.column-15{width:15%}.column-16{width:16%}.column-17{width:17%}.column-18{width:18%}.column-19{width:19%}.column-20{width:20%}.column-21{width:21%}.column-22{width:22%}.column-23{width:23%}.column-24{width:24%}.column-25{width:25%}.column-26{width:26%}.column-27{width:27%}.column-28{width:28%}.column-29{width:29%}.column-30{width:30%}.column-31{width:31%}.column-32{width:32%}.column-33{width:33%}.column-34{width:34%}.column-35{width:35%}.column-36{width:36%}.column-37{width:37%}.column-38{width:38%}.column-39{width:39%}.column-40{width:40%}.column-41{width:41%}.column-42{width:42%}.column-43{width:43%}.column-44{width:44%}.column-45{width:45%}.column-46{width:46%}.column-47{width:47%}.column-48{width:48%}.column-49{width:49%}.column-50{width:50%}.column-51{width:51%}.column-52{width:52%}.column-53{width:53%}.column-54{width:54%}.column-55{width:55%}.column-56{width:56%}.column-57{width:57%}.column-58{width:58%}.column-59{width:59%}.column-60{width:60%}.column-61{width:61%}.column-62{width:62%}.column-63{width:63%}.column-64{width:64%}.column-65{width:65%}.column-66{width:66%}.column-67{width:67%}.column-68{width:68%}.column-69{width:69%}.column-70{width:70%}.column-71{width:71%}.column-72{width:72%}.column-73{width:73%}.column-74{width:74%}.column-75{width:75%}.column-76{width:76%}.column-77{width:77%}.column-78{width:78%}.column-79{width:79%}.column-80{width:80%}.column-81{width:81%}.column-82{width:82%}.column-83{width:83%}.column-84{width:84%}.column-85{width:85%}.column-86{width:86%}.column-87{width:87%}.column-88{width:88%}.column-89{width:89%}.column-90{width:90%}.column-91{width:91%}.column-92{width:92%}.column-93{width:93%}.column-94{width:94%}.column-95{width:95%}.column-96{width:96%}.column-97{width:97%}.column-98{width:98%}.column-99{width:99%}.column-100{width:100%}.draggable-row-handle{cursor:move;color:#dedede}.draggable-row-handle:hover{color:#333}tr.draggable-item-selected{background:#fff;border:2px solid #666;box-shadow:4px 2px 10px -4px rgba(0,0,0,0.55)}tr.draggable-item-selected td{border-top:none;border-bottom:none}tr.draggable-item-selected td:first-child{border-left:none}tr.draggable-item-selected td:last-child{border-right:none}.table-stripped tr.draggable-item-hover,.table-stripped tr.draggable-item-hover{background:#FEFFF2}form{margin-bottom:20px}label{cursor:pointer;display:block;margin-top:10px}input[type="number"],input[type="date"],input[type="email"],input[type="password"],input[type="text"]:not(.input-addon-field){color:#999;border:1px solid #ccc;width:300px;max-width:95%;font-size:1em;height:25px;padding-bottom:0;font-family:sans-serif;margin-top:10px;-webkit-appearance:none;-moz-appearance:none}input[type="number"]::-webkit-input-placeholder,input[type="date"]::-webkit-input-placeholder,input[type="email"]::-webkit-input-placeholder,input[type="password"]::-webkit-input-placeholder,input[type="text"]:not(.input-addon-field)::-webkit-input-placeholder{color:#dedede}input[type="number"]:-moz-placeholder,input[type="date"]:-moz-placeholder,input[type="email"]:-moz-placeholder,input[type="password"]:-moz-placeholder,input[type="text"]:not(.input-addon-field):-moz-placeholder{color:#dedede}input[type="number"]::-moz-placeholder,input[type="date"]::-moz-placeholder,input[type="email"]::-moz-placeholder,input[type="password"]::-moz-placeholder,input[type="text"]:not(.input-addon-field)::-moz-placeholder{color:#dedede}input[type="number"]:-ms-input-placeholder,input[type="date"]:-ms-input-placeholder,input[type="email"]:-ms-input-placeholder,input[type="password"]:-ms-input-placeholder,input[type="text"]:not(.input-addon-field):-ms-input-placeholder{color:#dedede}input[type="number"]:focus,input[type="date"]:focus,input[type="email"]:focus,input[type="password"]:focus,input[type="text"]:focus{color:#000;border-color:rgba(82,168,236,0.8);outline:0;box-shadow:0 0 8px rgba(82,168,236,0.6)}input[type="number"]{width:70px}input[type="text"]:not(.input-addon-field).form-numeric{width:70px}input[type="text"]:not(.input-addon-field).form-datetime,input[type="text"]:not(.input-addon-field).form-date{width:150px}input[type="text"]:not(.input-addon-field).form-input-large{width:400px}input[type="text"]:not(.input-addon-field).form-input-small{width:150px}textarea:focus{color:#000;border-color:rgba(82,168,236,0.8);outline:0;box-shadow:0 0 8px rgba(82,168,236,0.6)}textarea{border:1px solid #ccc;width:400px;max-width:99%;height:200px;font-family:sans-serif}select{max-width:95%}select:focus{outline:0}.tag-autocomplete{width:400px}span.select2-container{margin-top:2px}.form-actions{padding-top:20px;clear:both}input.form-error,textarea.form-error{border:2px solid #b94a48}input.form-error:focus,textarea.form-error:focus{box-shadow:none;border:2px solid #b94a48}.form-required{color:red;padding-left:5px;font-weight:bold}.form-errors{color:#b94a48;list-style-type:none}ul.form-errors li{margin-left:0}.form-help{font-size:0.8em;color:brown;margin-bottom:15px}.form-inline{padding:0;margin:0;border:none}.form-inline label{display:inline}.form-inline input,.form-inline select{margin:0 15px 0 0}.form-inline .form-required{display:none}.form-inline-group{display:inline}.form-columns{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row}.form-column{margin-right:25px}.form-login{width:350px;margin:8% auto 0}.form-login li{margin-left:25px;line-height:25px}.form-login h2{margin-bottom:30px;font-weight:bold}.reset-password{margin-top:20px}.reset-password a{color:#999}.input-addon{display:flex}.input-addon-field{flex:1;font-size:1em;color:#999;margin:0;-webkit-appearance:none;-moz-appearance:none}.input-addon-item{background-color:rgba(147,128,108,0.1);color:#666;font:inherit;font-weight:normal}@media (max-width: 480px){.input-addon-item .dropdown .fa-caret-down{display:none}}.input-addon-field,.input-addon-item{border:1px solid rgba(147,128,108,0.25);padding:4px 0.75em}.input-addon-field:not(:first-child),.input-addon-item:not(:first-child){border-left:0}.input-addon-field:first-child,.input-addon-item:first-child{border-radius:5px 0 0 5px}.input-addon-field:last-child,.input-addon-item:last-child{border-radius:0 5px 5px 0}.alert{padding:8px 35px 8px 14px;margin-top:5px;margin-bottom:5px;color:#c09853;background-color:#fcf8e3;border:1px solid #fbeed5;border-radius:4px}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-normal{color:#333;background-color:#f0f0f0;border-color:#ddd}.alert ul{margin-top:10px;margin-bottom:10px}.alert li{margin-left:25px}.alert-fade-out{text-align:center;position:fixed;bottom:0;left:20%;width:60%;padding-top:5px;padding-bottom:5px;margin-bottom:0;border-width:1px 0 0;border-radius:4px 4px 0 0;z-index:9999}a.btn{text-decoration:none}.btn{-webkit-appearance:none;-moz-appearance:none;font-size:1.2em;font-weight:normal;cursor:pointer;display:inline-block;border-radius:2px;padding:3px 10px;margin:0;border:1px solid #ddd;background:#f5f5f5;color:#333}.btn:hover,.btn:focus{border-color:#bbb;background:#fafafa;color:#000}.btn-red{border-color:#b0281a;background:#d14836;color:#fff}.btn-red:hover,.btn-red:focus{border-color:#b0281a;background:#c53727;color:#fff}.btn-blue{border-color:#3079ed;background:#4d90fe;color:#fff}.btn-blue:hover,.btn-blue:focus{border-color:#3079ed;background:#357ae8;color:#fff}.btn:disabled{color:#ccc;border-color:#ccc;background:#f7f7f7}.buttons-header{font-size:0.8em;margin-top:5px;margin-bottom:15px}.tooltip-arrow:after{background:#fff;border:1px solid #aaaaaa;box-shadow:0 0 5px #aaa}div.ui-tooltip{min-width:200px;max-width:600px}.tooltip-arrow{width:20px;height:10px;overflow:hidden;position:absolute}.tooltip-arrow.top{top:-10px}.tooltip-arrow.bottom{bottom:-10px}.tooltip-arrow.align-left{left:10px}.tooltip-arrow.align-right{right:10px}.tooltip-arrow:after{content:"";position:absolute;width:14px;height:14px;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg)}.tooltip-arrow.bottom:after{top:-10px}.tooltip-arrow.top:after{bottom:-10px}.tooltip-arrow.align-left:after{left:0}.tooltip-arrow.align-right:after{right:0}.tooltip-large{width:600px}.ui-tooltip-content .markdown p{margin-bottom:0}.ui-tooltip li{list-style-type:none}.tooltip .fa-info-circle{color:#999}.dropdown{display:inline;position:relative}.dropdown ul{display:none}ul.dropdown-submenu-open{display:block;position:absolute;z-index:1000;min-width:285px;list-style:none;margin:3px 0 0 1px;padding:6px 0;background-color:#fff;border:1px solid #b2b2b2;border-radius:3px;box-shadow:0 1px 3px rgba(0,0,0,0.15)}.dropdown-submenu-open li{display:block;margin:0;padding:8px 10px;font-size:0.9em;border-bottom:1px solid #f8f8f8;cursor:pointer}.dropdown-submenu-open li.no-hover{cursor:default}.dropdown-submenu-open li:last-child{border:none}.dropdown-submenu-open li:not(.no-hover):hover{background:#4078C0;color:#fff}.dropdown-submenu-open li:hover a{color:#fff}.dropdown-submenu-open a{text-decoration:none;color:#333}.dropdown-submenu-open a:focus{text-decoration:underline}.dropdown-menu-link-text,.dropdown-menu-link-icon{color:#333;text-decoration:none}.dropdown-menu-link-text:hover{text-decoration:underline}.accordion-title{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAADCAYAAABS3WWCAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NEQ5RDgxQzc2RjQ5MTFFMjhEMUNENzFGRUMwRjhBRTciIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NEQ5RDgxQzg2RjQ5MTFFMjhEMUNENzFGRUMwRjhBRTciPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo0RDlEODFDNTZGNDkxMUUyOEQxQ0Q3MUZFQzBGOEFFNyIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo0RDlEODFDNjZGNDkxMUUyOEQxQ0Q3MUZFQzBGOEFFNyIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PvXFWFAAAAAYSURBVHjaYvj//z8D0/Pnz/8zgFgAAQYAS5UJscReGMIAAAAASUVORK5CYII=) repeat-x scroll 0 10px}.accordion-title h3{display:inline;padding-right:5px;background:#fff}.accordion-content{margin-top:15px;margin-bottom:25px}.accordion-toggle{color:#333;text-decoration:none}.accordion-toggle:focus{color:#333}.accordion-toggle:hover{color:#999}.accordion-toggle:before{content:"\f0d7"}.accordion-collapsed{margin-bottom:25px}.accordion-collapsed .accordion-toggle:before{content:"\f0da"}.accordion-collapsed .accordion-content{display:none}#main .confirm{max-width:700px}#popover-container{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.8);overflow:auto;z-index:100}#popover-content{position:absolute;width:70%;left:15%;top:1%;padding:15px;background:#fff;overflow:auto;max-height:90%}.popover-form{margin-bottom:0}.pagination{text-align:center}.pagination-next{margin-left:5px}.pagination-previous{margin-right:5px}header{box-sizing:border-box;display:flex;flex-wrap:wrap;margin-top:5px;margin-bottom:5px;border-bottom:1px solid #dedede}header>*{box-sizing:border-box}header>*{width:1%}header .menus-container{width:10%}@media (min-width: 768px) and (max-width: 1150px){header .menus-container{width:15%}}@media (max-width: 768px){header .menus-container{width:65%;order:2}}header .board-selector-container{width:15%}@media (min-width: 768px) and (max-width: 1150px){header .board-selector-container{width:20%}}@media (max-width: 768px){header .board-selector-container{width:35%;order:1;margin-bottom:5px}}header .title-container{width:75%}@media (min-width: 768px) and (max-width: 1150px){header .title-container{width:65%}}@media (max-width: 768px){header .title-container{width:100%;order:3}}header h1{font-size:1.5em}header h1 .tooltip{opacity:0.3;font-size:0.7em}.web-notification-icon{color:#36c}.web-notification-icon:focus,.web-notification-icon:hover{color:#000}.logo a{opacity:0.5;color:#d40000;text-decoration:none}.logo span{color:#333}.logo a:hover{opacity:0.8;color:#333}.logo a:focus span,.logo a:hover span{color:#d40000}.page-header{margin-bottom:20px}.page-header .dropdown{padding-right:10px}.page-header h2{margin:0;padding:0;font-weight:bold;border-bottom:1px dotted #ccc}.page-header h2 a{color:#333;text-decoration:none}.page-header h2 a:focus,.page-header h2 a:hover{color:#999}.page-header ul{text-align:left;margin-top:5px;display:inline-block}.page-header li{display:inline;padding-right:15px}@media (max-width: 480px){.page-header li{display:block;line-height:1.5em}}.page-header li.active a{color:#333;text-decoration:none;font-weight:bold}.page-header li.active a:hover,.page-header li.active a:focus{text-decoration:underline}.menu-inline{margin-bottom:5px}.menu-inline li{display:inline;padding-right:15px}.menu-inline li .active a{font-weight:bold;color:#000;text-decoration:none}.sidebar-container{box-sizing:border-box;display:flex;flex-wrap:wrap}.sidebar-container>*{box-sizing:border-box}.sidebar-container>*{width:1%}.sidebar-content{padding-left:10px;width:82%}@media (max-width: 480px){.sidebar-content{width:100%}}.sidebar{max-width:240px;min-width:190px;width:18%}@media (max-width: 480px){.sidebar{width:100%;max-width:99%;min-width:0}}.sidebar h2{margin-top:0}.sidebar>ul a{text-decoration:none;color:#999;font-weight:300}.sidebar>ul a:hover{color:#333}.sidebar>ul li{list-style-type:none;line-height:35px;border-bottom:1px dotted #efefef;padding-left:13px}.sidebar>ul li:hover{border-left:5px solid #555;padding-left:8px}.sidebar>ul li.active{border-left:5px solid #333;padding-left:8px}.sidebar>ul li.active a{color:#333;font-weight:bold}.sidebar-icons>ul li{padding-left:0}.sidebar-icons>ul li:hover,.sidebar-icons>ul li.active{padding-left:0;border-left:none}.sidebar>ul li.active a:focus,.sidebar>ul li.active a:hover{color:#555}.sidebar>ul li:last-child{margin-bottom:15px}.avatar img{vertical-align:bottom}.avatar-left{float:left;margin-right:10px}.avatar-inline{display:inline-block;margin-right:3px}.avatar-48 img,.avatar-48 div{border-radius:30px}.avatar-48 .avatar-letter{line-height:48px;width:48px;font-size:25px}.avatar-20 img,.avatar-20 div{border-radius:10px}.avatar-20 .avatar-letter{line-height:20px;width:20px;font-size:11px}.avatar-letter{color:#fff;text-align:center}#file-dropzone,#screenshot-zone{position:relative;border:2px dashed #ccc;width:99%;height:250px;overflow:auto}#file-dropzone-inner,#screenshot-inner{position:absolute;left:0;bottom:48%;width:100%;text-align:center;color:#aaa}#screenshot-zone.screenshot-pasted{border:2px solid #333}#file-list{margin:20px}#file-list li{list-style-type:none;padding-top:8px;padding-bottom:8px;border-bottom:1px dotted #ddd;width:95%}#file-list li.file-error{font-weight:bold;color:#b94a48}.color-picker{width:180px}.color-picker-option{height:25px}.color-picker-square{display:inline-block;width:18px;height:18px;margin-right:5px;border:1px solid #000}.color-picker-label{display:inline-block;vertical-align:bottom;padding-bottom:3px}.file-thumbnails{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;flex-wrap:wrap;-webkit-justify-content:flex-start;justify-content:flex-start}.file-thumbnail{width:250px;border:1px solid #efefef;border-radius:5px;margin-bottom:20px;box-shadow:4px 2px 10px -6px rgba(0,0,0,0.55);margin-right:15px}.file-thumbnail img{border-top-left-radius:5px;border-top-right-radius:5px}.file-thumbnail img:hover{opacity:0.5}.file-thumbnail-content{padding-left:8px;padding-right:8px}.file-thumbnail-title{font-weight:700;font-size:0.9em;color:#555}.file-thumbnail-description{font-size:0.8em;color:#999;margin-top:8px;margin-bottom:5px}.file-viewer{position:relative}.file-viewer img{max-width:95%;max-height:85%;margin-top:10px}.filter-box{max-width:800px}.project-header{margin-top:8px;margin-bottom:20px}.action-menu{color:#333;text-decoration:none}.action-menu:hover,.action-menu:focus{text-decoration:underline}.project-creation-options{max-width:500px;border-left:3px dotted #efefef;margin-top:20px;padding-left:15px;padding-bottom:5px;padding-top:5px}.project-overview-columns{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;align-items:center;-webkit-justify-content:center;justify-content:center;margin-bottom:20px;font-size:1.4em}@media (max-width: 480px){.project-overview-columns{display:block}}.project-overview-column{text-align:center;margin-right:3%;margin-top:5px;padding:3px 15px 3px 15px;border:1px dashed #ddd}@media (max-width: 480px){.project-overview-column{text-align:left}}.project-overview-column small{color:#999}.project-overview-column strong{color:#555;display:block}@media (max-width: 480px){.project-overview-column strong{display:inline}}.project-header{box-sizing:border-box;display:flex;flex-wrap:wrap}.project-header>*{box-sizing:border-box}.project-header>*{width:1%}.project-header .dropdown-component{width:5%}@media (min-width: 768px) and (max-width: 1150px){.project-header .dropdown-component{width:8%}}@media (max-width: 768px){.project-header .dropdown-component{width:100%}}.project-header .views-switcher-component{width:38%}@media (max-width: 1300px){.project-header .views-switcher-component{width:45%}}@media (min-width: 768px) and (max-width: 1150px){.project-header .views-switcher-component{width:92%}}@media (max-width: 768px){.project-header .views-switcher-component{width:100%}}.project-header .filter-box-component{margin:0;width:55%}@media (max-width: 1300px){.project-header .filter-box-component{width:50%}}@media (min-width: 768px) and (max-width: 1150px){.project-header .filter-box-component{width:100%;margin-top:10px}.project-header .filter-box-component .filter-box{max-width:100%}}@media (max-width: 768px){.project-header .filter-box-component{width:100%;margin-top:10px}.project-header .filter-box-component .filter-box{max-width:100%}}.project-header .filter-box-component form{margin:0}.views{display:inline-block;margin-right:10px;font-size:0.9em}@media (max-width: 560px){.views{width:100%}}@media (max-width: 768px){.views{margin-top:10px;font-size:1em}}.views li{white-space:nowrap;background:#fafafa;border:1px solid #ddd;border-right:none;padding:4px 8px;display:inline}@media (max-width: 560px){.views li{display:block;margin-top:5px;border-radius:5px;border:1px solid #ddd}}.views li.active a{font-weight:bold;color:#000;text-decoration:none}.views li:first-child{border-top-left-radius:5px;border-bottom-left-radius:5px}.views li:last-child{border-right:1px solid #ddd;border-top-right-radius:5px;border-bottom-right-radius:5px}.views a{color:#555;text-decoration:none}.views a:hover{color:#333;text-decoration:underline}.dashboard-project-stats small{margin-right:10px;color:#999}.dashboard-table-link{font-weight:bold;color:#000;text-decoration:none}.dashboard-table-link:focus,.dashboard-table-link:hover{color:#999}.public-board{margin-top:5px}.public-task{max-width:800px;margin:5px auto 0}#board-container{overflow-x:auto}#board{table-layout:fixed;margin-bottom:0}#board th.board-column-header{width:240px}#board td{vertical-align:top}.board-container-compact{overflow-x:initial}@media all and (-ms-high-contrast: active), (-ms-high-contrast: none){.board-container-compact #board{table-layout:auto}}#board th.board-column-header.board-column-compact{width:initial}.board-column-collapsed{display:none}td.board-column-task-collapsed{font-weight:bold;background-color:#fbfbfb}#board th.board-column-header-collapsed{width:28px;min-width:28px;text-align:center;overflow:hidden}.board-rotation-wrapper{position:relative;padding:8px 4px;min-height:150px;overflow:hidden}.board-rotation{white-space:nowrap;-webkit-backface-visibility:hidden;-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg);-webkit-transform-origin:0 100%;-moz-transform-origin:0 100%;-ms-transform-origin:0 100%;transform-origin:0 100%}.board-column-title .dropdown-menu{text-decoration:none}.board-add-icon{float:left;padding:0 5px}.board-add-icon a{text-decoration:none;color:#36c;font-size:1.6em;line-height:70%}.board-add-icon a:focus,.board-add-icon a:hover{text-decoration:none;color:red}.board-column-header-task-count{color:#999;font-weight:normal}a.board-swimlane-toggle{text-decoration:none}a.board-swimlane-toggle:hover,a.board-swimlane-toggle:focus{color:#000;text-decoration:none;border:none}.board-task-list{min-height:60px}.board-task-list-limit{background-color:#DF5353}.draggable-item{cursor:pointer;user-select:none;-webkit-user-select:none;-moz-user-select:none}.draggable-placeholder{border:2px dashed #000;background:#fafafa;height:70px;margin-bottom:10px}div.draggable-item-selected{border:1px solid #000}.task-board-sort-handle{float:left;padding-right:5px}.task-board{position:relative;margin-bottom:4px;border:1px solid #000;padding:2px;word-wrap:break-word;font-size:0.9em}div.task-board-recent{border-width:2px}div.task-board-status-closed{user-select:none;border:1px dotted #555}.task-board a{color:#000;text-decoration:none}.task-board .dropdown-menu{font-weight:bold}.task-board .task-score{font-weight:bold}.task-board-collapsed{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.task-board-title{margin-top:5px;margin-bottom:8px}.task-board-title a:hover{text-decoration:underline}.task-board-saving-state{opacity:0.3}.task-board-saving-icon{position:absolute;margin:auto;width:100%;text-align:center;color:#000}.task-board-category-container{text-align:right;margin-top:8px;margin-bottom:8px}.task-board-category{font-weight:500;color:#000;border:1px solid #555;padding:1px 2px 1px 2px;border-radius:4px}.task-board-category:hover{opacity:0.6}.task-board-avatars{text-align:right;float:right}.task-board-change-assignee{cursor:pointer}.task-board-change-assignee:hover{opacity:0.6}.task-board-icons{font-size:0.8em;text-align:right;margin-top:4px;margin-bottom:2px}.task-board-icons a{opacity:0.5}.task-board-icons span{opacity:0.5;margin-left:2px}.task-board-icons a:hover,.task-board-icons span:hover{opacity:1.0}.flag-milestone{color:green}.task-board-age{display:inline-block}span.task-board-age-total{border:#666 1px solid;padding:1px 3px 1px 3px;border-top-left-radius:3px;border-bottom-left-radius:3px}span.task-board-age-column{border:#666 1px solid;border-left:none;margin-left:-5px;padding:1px 3px 1px 3px;border-top-right-radius:3px;border-bottom-right-radius:3px}.task-board-date{font-weight:bold;color:#000}span.task-board-date-today{opacity:1.0}span.task-board-date-overdue{opacity:1.0}.task-tags li{display:inline;margin:0;margin-right:4px;padding:2px;color:#555;border:1px solid #666;border-radius:2px}.task-summary-container .task-tags{margin-top:10px}#task-summary{margin-bottom:15px}#task-summary h2{color:#555;font-size:1.6em;margin-top:0;padding-top:0}.task-summary-container{border:2px solid #000;border-radius:8px;padding:15px}.task-summary-columns{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-justify-content:space-between;justify-content:space-between}@media (max-width: 480px){.task-summary-columns{display:block}}.task-summary-column{color:#333}.task-summary-column span{color:#555}.task-summary-column li{line-height:23px}.task-table .dropdown-menu{color:#000;text-decoration:none;font-weight:bold}.task-table .dropdown-menu:focus,.task-table .dropdown-menu:hover{text-decoration:underline}td.task-table a{color:#000;text-decoration:none}td.task-table a:hover{text-decoration:underline}.comment-sorting{text-align:right}.comment-sorting a{color:#555;font-weight:normal;text-decoration:none}.comment-sorting a:hover{color:#999}.comment{padding:5px;margin-bottom:15px}.comment:hover{background:#fafafa}.comment-title{border-bottom:1px dotted #eee;margin-left:55px;margin-bottom:10px}.comment-date{color:#999;font-weight:200}.comment-actions{font-size:0.8em;margin-left:55px;margin-top:8px}.comment-actions li{display:inline}.comment-actions a{color:#999;text-decoration:none}.comment-actions a:focus,.comment-actions a:hover{color:#333;text-decoration:underline}.comment-content{margin-left:55px}.subtasks-table td{vertical-align:middle}.task-links-table td{vertical-align:middle}.task-links-task-count{color:#999}.task-link-closed{text-decoration:line-through}.markdown-editor-container{max-width:400px}div.CodeMirror,div.CodeMirror-scroll{max-height:250px;min-height:200px}.markdown-editor-small div.CodeMirror,.markdown-editor-small div.CodeMirror-scroll{min-height:100px;max-height:180px}.form-column div.CodeMirror{margin-bottom:10px}.markdown{line-height:1.4em}.markdown h1{margin-top:5px;margin-bottom:10px;font-weight:bold}.markdown h2{font-weight:bold}.markdown p{margin-bottom:10px}.markdown ol,.markdown ul{margin-left:25px;margin-top:10px;margin-bottom:10px}.markdown pre{background:#fbfbfb;padding:10px;border-radius:5px;border:1px solid #ddd;overflow:auto;color:#555}.markdown blockquote{font-style:italic;border-left:3px solid #ddd;padding-left:10px;margin-bottom:10px;margin-left:20px}.markdown img{display:block;max-width:80%;margin-top:10px}.documentation{margin:0 auto;padding:20px;max-width:850px;background:#fefefe;border:1px solid #ccc;border-radius:5px;color:#555}.documentation img{border:1px solid #333}.documentation h1{text-decoration:none;margin-bottom:30px}.documentation h2{text-decoration:none;border-bottom:1px solid #ccc;margin-bottom:25px}.documentation li{line-height:30px}.listing{border-radius:4px;padding:8px 35px 8px 14px;margin-bottom:20px;border:1px solid #ddd;color:#333;background-color:#fcfcfc;overflow:auto}.listing li{list-style-type:square;margin-left:20px;margin-bottom:3px}.listing ul{margin-top:15px;margin-bottom:15px}.activity-event{margin-bottom:15px;padding:10px}.activity-event:hover{background:#fafafa}.activity-date{margin-left:10px;font-weight:normal;color:#999}.activity-content{margin-left:55px}.activity-title{font-weight:bold;color:#000;border-bottom:1px dotted #efefef}.activity-description{color:#555;margin-top:10px}@media (max-width: 480px){.activity-description{overflow:auto}}.activity-description li{list-style-type:circle}.activity-description ul{margin-top:10px;margin-left:20px}div.ganttview-hzheader-month,div.ganttview-hzheader-day,div.ganttview-vtheader,div.ganttview-vtheader-item-name,div.ganttview-vtheader-series,div.ganttview-grid,div.ganttview-grid-row-cell{float:left}div.ganttview-hzheader-month,div.ganttview-hzheader-day{text-align:center}div.ganttview-grid-row-cell.last,div.ganttview-hzheader-day.last,div.ganttview-hzheader-month.last{border-right:none}div.ganttview{border:1px solid #999}div.ganttview-hzheader-month{width:60px;height:20px;border-right:1px solid #d0d0d0;line-height:20px;overflow:hidden}div.ganttview-hzheader-day{width:20px;height:20px;border-right:1px solid #f0f0f0;border-top:1px solid #d0d0d0;line-height:20px;color:#555}div.ganttview-vtheader{margin-top:41px;width:400px;overflow:hidden;background-color:#fff}div.ganttview-vtheader-item{color:#555}div.ganttview-vtheader-series-name{width:400px;height:31px;line-height:31px;padding-left:3px;border-top:1px solid #d0d0d0;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}div.ganttview-vtheader-series-name a{color:#555;text-decoration:none}div.ganttview-vtheader-series-name a:hover{color:#333;text-decoration:underline}div.ganttview-vtheader-series-name a i{color:#000}div.ganttview-vtheader-series-name a:hover i{color:#555}div.ganttview-slide-container{overflow:auto;border-left:1px solid #999}div.ganttview-grid-row-cell{width:20px;height:31px;border-right:1px solid #f0f0f0;border-top:1px solid #f0f0f0}div.ganttview-grid-row-cell.ganttview-weekend{background-color:#fafafa}div.ganttview-blocks{margin-top:40px}div.ganttview-block-container{height:28px;padding-top:4px}div.ganttview-block{position:relative;height:25px;background-color:#E5ECF9;border:1px solid #c0c0c0;border-radius:3px}.ganttview-block-movable{cursor:move}div.ganttview-block-not-defined{border-color:#000;background-color:#000}div.ganttview-block-text{position:absolute;height:12px;font-size:0.7em;color:#999;padding:2px 3px}div.ganttview-block div.ui-resizable-handle.ui-resizable-s{bottom:-0}.user-mention-link{font-weight:bold;color:#000;text-decoration:none}.user-mention-link:hover{color:#555} diff --git a/assets/sass/_activity_stream.sass b/assets/sass/_activity_stream.sass index b9ffcdda..3ec201e6 100644 --- a/assets/sass/_activity_stream.sass +++ b/assets/sass/_activity_stream.sass @@ -1,4 +1,5 @@ @import variables +@import mixins .activity-event margin-bottom: 15px @@ -22,6 +23,8 @@ .activity-description color: color('medium') margin-top: 10px + @include xs-device + overflow: auto li list-style-type: circle ul diff --git a/assets/sass/_project_overview.sass b/assets/sass/_project_overview.sass index 6f9faa0b..8ab4f1dc 100644 --- a/assets/sass/_project_overview.sass +++ b/assets/sass/_project_overview.sass @@ -7,13 +7,24 @@ +align-content(center) margin-bottom: 20px font-size: size('large') + @include xs-device + display: block .project-overview-column text-align: center margin-right: 3% + margin-top: 5px padding: 3px 15px 3px 15px border: 1px dashed #ddd + + @include xs-device + text-align: left + small color: color('light') strong color: color('medium') + display: block + + @include xs-device + display: inline -- cgit v1.2.3 From e24c37290b97eb00bf08a45b8ce913cd5da3bd51 Mon Sep 17 00:00:00 2001 From: Frederic Guillot Date: Sun, 14 Aug 2016 14:19:20 -0400 Subject: Make form columns and popover more responsive --- app/Template/group/index.php | 2 +- assets/css/app.min.css | 2 +- assets/sass/_files.sass | 43 ------------------------------------------- assets/sass/_form.sass | 25 ++++++++++++++----------- assets/sass/_popover.sass | 15 ++++++++++++--- assets/sass/_thumbnails.sass | 43 +++++++++++++++++++++++++++++++++++++++++++ assets/sass/app.sass | 2 +- 7 files changed, 72 insertions(+), 60 deletions(-) delete mode 100644 assets/sass/_files.sass create mode 100644 assets/sass/_thumbnails.sass (limited to 'app') diff --git a/app/Template/group/index.php b/app/Template/group/index.php index 1062e18c..fe8a07e7 100644 --- a/app/Template/group/index.php +++ b/app/Template/group/index.php @@ -8,7 +8,7 @@ isEmpty()): ?>

-
order(t('Task'), 'task_title') ?> order(t('Subtask'), 'subtask_title') ?>
+
diff --git a/assets/css/app.min.css b/assets/css/app.min.css index d5d06954..c90087c5 100644 --- a/assets/css/app.min.css +++ b/assets/css/app.min.css @@ -1 +1 @@ -h1,li,ul,ol,table,tr,td,th,p,blockquote,body{margin:0;padding:0;font-size:100%}body{margin-left:10px;margin-right:10px;padding-bottom:10px;color:#333;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;text-rendering:optimizeLegibility}small{font-size:0.8em}hr{border:0;height:0;border-top:1px solid rgba(0,0,0,0.1);border-bottom:1px solid rgba(255,255,255,0.3)}.pull-right{text-align:right}ul.no-bullet li{list-style-type:none;margin-left:0}.chosen-select{min-height:27px}#app-loading-icon{position:fixed;right:3px;bottom:3px}.assign-me{vertical-align:bottom}a{color:#36c;border:none}a:focus{outline:0;color:#DF5353;text-decoration:none}a:hover{color:#333;text-decoration:none}h1,h2,h3{font-weight:normal;color:#333}h1{font-size:1.5em}h2{font-size:1.4em;margin-bottom:10px}h3{margin-top:10px;font-size:1.2em}table{width:100%;border-collapse:collapse;border-spacing:0;margin-bottom:20px}table.table-fixed{table-layout:fixed;white-space:nowrap}table.table-fixed th{overflow:hidden}table.table-fixed td{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}table.table-small{font-size:0.8em}table.table-striped tr:nth-child(odd){background:#fefefe}@media (max-width: 768px){table.table-scrolling{overflow-x:auto;display:inline-block;vertical-align:top;max-width:100%;white-space:nowrap}}table th{text-align:left;padding:0.5em 3px;border:1px solid #eee;background:#fbfbfb}table th a{text-decoration:none;color:#333}table th a:focus,table th a:hover{text-decoration:underline}table td{border:1px solid #eee;padding:0.5em 3px;vertical-align:top}table td li{margin-left:20px}.column-1{width:1%}.column-2{width:2%}.column-3{width:3%}.column-4{width:4%}.column-5{width:5%}.column-6{width:6%}.column-7{width:7%}.column-8{width:8%}.column-9{width:9%}.column-10{width:10%}.column-11{width:11%}.column-12{width:12%}.column-13{width:13%}.column-14{width:14%}.column-15{width:15%}.column-16{width:16%}.column-17{width:17%}.column-18{width:18%}.column-19{width:19%}.column-20{width:20%}.column-21{width:21%}.column-22{width:22%}.column-23{width:23%}.column-24{width:24%}.column-25{width:25%}.column-26{width:26%}.column-27{width:27%}.column-28{width:28%}.column-29{width:29%}.column-30{width:30%}.column-31{width:31%}.column-32{width:32%}.column-33{width:33%}.column-34{width:34%}.column-35{width:35%}.column-36{width:36%}.column-37{width:37%}.column-38{width:38%}.column-39{width:39%}.column-40{width:40%}.column-41{width:41%}.column-42{width:42%}.column-43{width:43%}.column-44{width:44%}.column-45{width:45%}.column-46{width:46%}.column-47{width:47%}.column-48{width:48%}.column-49{width:49%}.column-50{width:50%}.column-51{width:51%}.column-52{width:52%}.column-53{width:53%}.column-54{width:54%}.column-55{width:55%}.column-56{width:56%}.column-57{width:57%}.column-58{width:58%}.column-59{width:59%}.column-60{width:60%}.column-61{width:61%}.column-62{width:62%}.column-63{width:63%}.column-64{width:64%}.column-65{width:65%}.column-66{width:66%}.column-67{width:67%}.column-68{width:68%}.column-69{width:69%}.column-70{width:70%}.column-71{width:71%}.column-72{width:72%}.column-73{width:73%}.column-74{width:74%}.column-75{width:75%}.column-76{width:76%}.column-77{width:77%}.column-78{width:78%}.column-79{width:79%}.column-80{width:80%}.column-81{width:81%}.column-82{width:82%}.column-83{width:83%}.column-84{width:84%}.column-85{width:85%}.column-86{width:86%}.column-87{width:87%}.column-88{width:88%}.column-89{width:89%}.column-90{width:90%}.column-91{width:91%}.column-92{width:92%}.column-93{width:93%}.column-94{width:94%}.column-95{width:95%}.column-96{width:96%}.column-97{width:97%}.column-98{width:98%}.column-99{width:99%}.column-100{width:100%}.draggable-row-handle{cursor:move;color:#dedede}.draggable-row-handle:hover{color:#333}tr.draggable-item-selected{background:#fff;border:2px solid #666;box-shadow:4px 2px 10px -4px rgba(0,0,0,0.55)}tr.draggable-item-selected td{border-top:none;border-bottom:none}tr.draggable-item-selected td:first-child{border-left:none}tr.draggable-item-selected td:last-child{border-right:none}.table-stripped tr.draggable-item-hover,.table-stripped tr.draggable-item-hover{background:#FEFFF2}form{margin-bottom:20px}label{cursor:pointer;display:block;margin-top:10px}input[type="number"],input[type="date"],input[type="email"],input[type="password"],input[type="text"]:not(.input-addon-field){color:#999;border:1px solid #ccc;width:300px;max-width:95%;font-size:1em;height:25px;padding-bottom:0;font-family:sans-serif;margin-top:10px;-webkit-appearance:none;-moz-appearance:none}input[type="number"]::-webkit-input-placeholder,input[type="date"]::-webkit-input-placeholder,input[type="email"]::-webkit-input-placeholder,input[type="password"]::-webkit-input-placeholder,input[type="text"]:not(.input-addon-field)::-webkit-input-placeholder{color:#dedede}input[type="number"]:-moz-placeholder,input[type="date"]:-moz-placeholder,input[type="email"]:-moz-placeholder,input[type="password"]:-moz-placeholder,input[type="text"]:not(.input-addon-field):-moz-placeholder{color:#dedede}input[type="number"]::-moz-placeholder,input[type="date"]::-moz-placeholder,input[type="email"]::-moz-placeholder,input[type="password"]::-moz-placeholder,input[type="text"]:not(.input-addon-field)::-moz-placeholder{color:#dedede}input[type="number"]:-ms-input-placeholder,input[type="date"]:-ms-input-placeholder,input[type="email"]:-ms-input-placeholder,input[type="password"]:-ms-input-placeholder,input[type="text"]:not(.input-addon-field):-ms-input-placeholder{color:#dedede}input[type="number"]:focus,input[type="date"]:focus,input[type="email"]:focus,input[type="password"]:focus,input[type="text"]:focus{color:#000;border-color:rgba(82,168,236,0.8);outline:0;box-shadow:0 0 8px rgba(82,168,236,0.6)}input[type="number"]{width:70px}input[type="text"]:not(.input-addon-field).form-numeric{width:70px}input[type="text"]:not(.input-addon-field).form-datetime,input[type="text"]:not(.input-addon-field).form-date{width:150px}input[type="text"]:not(.input-addon-field).form-input-large{width:400px}input[type="text"]:not(.input-addon-field).form-input-small{width:150px}textarea:focus{color:#000;border-color:rgba(82,168,236,0.8);outline:0;box-shadow:0 0 8px rgba(82,168,236,0.6)}textarea{border:1px solid #ccc;width:400px;max-width:99%;height:200px;font-family:sans-serif}select{max-width:95%}select:focus{outline:0}.tag-autocomplete{width:400px}span.select2-container{margin-top:2px}.form-actions{padding-top:20px;clear:both}input.form-error,textarea.form-error{border:2px solid #b94a48}input.form-error:focus,textarea.form-error:focus{box-shadow:none;border:2px solid #b94a48}.form-required{color:red;padding-left:5px;font-weight:bold}.form-errors{color:#b94a48;list-style-type:none}ul.form-errors li{margin-left:0}.form-help{font-size:0.8em;color:brown;margin-bottom:15px}.form-inline{padding:0;margin:0;border:none}.form-inline label{display:inline}.form-inline input,.form-inline select{margin:0 15px 0 0}.form-inline .form-required{display:none}.form-inline-group{display:inline}.form-columns{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row}.form-column{margin-right:25px}.form-login{width:350px;margin:8% auto 0}.form-login li{margin-left:25px;line-height:25px}.form-login h2{margin-bottom:30px;font-weight:bold}.reset-password{margin-top:20px}.reset-password a{color:#999}.input-addon{display:flex}.input-addon-field{flex:1;font-size:1em;color:#999;margin:0;-webkit-appearance:none;-moz-appearance:none}.input-addon-item{background-color:rgba(147,128,108,0.1);color:#666;font:inherit;font-weight:normal}@media (max-width: 480px){.input-addon-item .dropdown .fa-caret-down{display:none}}.input-addon-field,.input-addon-item{border:1px solid rgba(147,128,108,0.25);padding:4px 0.75em}.input-addon-field:not(:first-child),.input-addon-item:not(:first-child){border-left:0}.input-addon-field:first-child,.input-addon-item:first-child{border-radius:5px 0 0 5px}.input-addon-field:last-child,.input-addon-item:last-child{border-radius:0 5px 5px 0}.alert{padding:8px 35px 8px 14px;margin-top:5px;margin-bottom:5px;color:#c09853;background-color:#fcf8e3;border:1px solid #fbeed5;border-radius:4px}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-normal{color:#333;background-color:#f0f0f0;border-color:#ddd}.alert ul{margin-top:10px;margin-bottom:10px}.alert li{margin-left:25px}.alert-fade-out{text-align:center;position:fixed;bottom:0;left:20%;width:60%;padding-top:5px;padding-bottom:5px;margin-bottom:0;border-width:1px 0 0;border-radius:4px 4px 0 0;z-index:9999}a.btn{text-decoration:none}.btn{-webkit-appearance:none;-moz-appearance:none;font-size:1.2em;font-weight:normal;cursor:pointer;display:inline-block;border-radius:2px;padding:3px 10px;margin:0;border:1px solid #ddd;background:#f5f5f5;color:#333}.btn:hover,.btn:focus{border-color:#bbb;background:#fafafa;color:#000}.btn-red{border-color:#b0281a;background:#d14836;color:#fff}.btn-red:hover,.btn-red:focus{border-color:#b0281a;background:#c53727;color:#fff}.btn-blue{border-color:#3079ed;background:#4d90fe;color:#fff}.btn-blue:hover,.btn-blue:focus{border-color:#3079ed;background:#357ae8;color:#fff}.btn:disabled{color:#ccc;border-color:#ccc;background:#f7f7f7}.buttons-header{font-size:0.8em;margin-top:5px;margin-bottom:15px}.tooltip-arrow:after{background:#fff;border:1px solid #aaaaaa;box-shadow:0 0 5px #aaa}div.ui-tooltip{min-width:200px;max-width:600px}.tooltip-arrow{width:20px;height:10px;overflow:hidden;position:absolute}.tooltip-arrow.top{top:-10px}.tooltip-arrow.bottom{bottom:-10px}.tooltip-arrow.align-left{left:10px}.tooltip-arrow.align-right{right:10px}.tooltip-arrow:after{content:"";position:absolute;width:14px;height:14px;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg)}.tooltip-arrow.bottom:after{top:-10px}.tooltip-arrow.top:after{bottom:-10px}.tooltip-arrow.align-left:after{left:0}.tooltip-arrow.align-right:after{right:0}.tooltip-large{width:600px}.ui-tooltip-content .markdown p{margin-bottom:0}.ui-tooltip li{list-style-type:none}.tooltip .fa-info-circle{color:#999}.dropdown{display:inline;position:relative}.dropdown ul{display:none}ul.dropdown-submenu-open{display:block;position:absolute;z-index:1000;min-width:285px;list-style:none;margin:3px 0 0 1px;padding:6px 0;background-color:#fff;border:1px solid #b2b2b2;border-radius:3px;box-shadow:0 1px 3px rgba(0,0,0,0.15)}.dropdown-submenu-open li{display:block;margin:0;padding:8px 10px;font-size:0.9em;border-bottom:1px solid #f8f8f8;cursor:pointer}.dropdown-submenu-open li.no-hover{cursor:default}.dropdown-submenu-open li:last-child{border:none}.dropdown-submenu-open li:not(.no-hover):hover{background:#4078C0;color:#fff}.dropdown-submenu-open li:hover a{color:#fff}.dropdown-submenu-open a{text-decoration:none;color:#333}.dropdown-submenu-open a:focus{text-decoration:underline}.dropdown-menu-link-text,.dropdown-menu-link-icon{color:#333;text-decoration:none}.dropdown-menu-link-text:hover{text-decoration:underline}.accordion-title{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAADCAYAAABS3WWCAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NEQ5RDgxQzc2RjQ5MTFFMjhEMUNENzFGRUMwRjhBRTciIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NEQ5RDgxQzg2RjQ5MTFFMjhEMUNENzFGRUMwRjhBRTciPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo0RDlEODFDNTZGNDkxMUUyOEQxQ0Q3MUZFQzBGOEFFNyIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo0RDlEODFDNjZGNDkxMUUyOEQxQ0Q3MUZFQzBGOEFFNyIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PvXFWFAAAAAYSURBVHjaYvj//z8D0/Pnz/8zgFgAAQYAS5UJscReGMIAAAAASUVORK5CYII=) repeat-x scroll 0 10px}.accordion-title h3{display:inline;padding-right:5px;background:#fff}.accordion-content{margin-top:15px;margin-bottom:25px}.accordion-toggle{color:#333;text-decoration:none}.accordion-toggle:focus{color:#333}.accordion-toggle:hover{color:#999}.accordion-toggle:before{content:"\f0d7"}.accordion-collapsed{margin-bottom:25px}.accordion-collapsed .accordion-toggle:before{content:"\f0da"}.accordion-collapsed .accordion-content{display:none}#main .confirm{max-width:700px}#popover-container{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.8);overflow:auto;z-index:100}#popover-content{position:absolute;width:70%;left:15%;top:1%;padding:15px;background:#fff;overflow:auto;max-height:90%}.popover-form{margin-bottom:0}.pagination{text-align:center}.pagination-next{margin-left:5px}.pagination-previous{margin-right:5px}header{box-sizing:border-box;display:flex;flex-wrap:wrap;margin-top:5px;margin-bottom:5px;border-bottom:1px solid #dedede}header>*{box-sizing:border-box}header>*{width:1%}header .menus-container{width:10%}@media (min-width: 768px) and (max-width: 1150px){header .menus-container{width:15%}}@media (max-width: 768px){header .menus-container{width:65%;order:2}}header .board-selector-container{width:15%}@media (min-width: 768px) and (max-width: 1150px){header .board-selector-container{width:20%}}@media (max-width: 768px){header .board-selector-container{width:35%;order:1;margin-bottom:5px}}header .title-container{width:75%}@media (min-width: 768px) and (max-width: 1150px){header .title-container{width:65%}}@media (max-width: 768px){header .title-container{width:100%;order:3}}header h1{font-size:1.5em}header h1 .tooltip{opacity:0.3;font-size:0.7em}.web-notification-icon{color:#36c}.web-notification-icon:focus,.web-notification-icon:hover{color:#000}.logo a{opacity:0.5;color:#d40000;text-decoration:none}.logo span{color:#333}.logo a:hover{opacity:0.8;color:#333}.logo a:focus span,.logo a:hover span{color:#d40000}.page-header{margin-bottom:20px}.page-header .dropdown{padding-right:10px}.page-header h2{margin:0;padding:0;font-weight:bold;border-bottom:1px dotted #ccc}.page-header h2 a{color:#333;text-decoration:none}.page-header h2 a:focus,.page-header h2 a:hover{color:#999}.page-header ul{text-align:left;margin-top:5px;display:inline-block}.page-header li{display:inline;padding-right:15px}@media (max-width: 480px){.page-header li{display:block;line-height:1.5em}}.page-header li.active a{color:#333;text-decoration:none;font-weight:bold}.page-header li.active a:hover,.page-header li.active a:focus{text-decoration:underline}.menu-inline{margin-bottom:5px}.menu-inline li{display:inline;padding-right:15px}.menu-inline li .active a{font-weight:bold;color:#000;text-decoration:none}.sidebar-container{box-sizing:border-box;display:flex;flex-wrap:wrap}.sidebar-container>*{box-sizing:border-box}.sidebar-container>*{width:1%}.sidebar-content{padding-left:10px;width:82%}@media (max-width: 480px){.sidebar-content{width:100%}}.sidebar{max-width:240px;min-width:190px;width:18%}@media (max-width: 480px){.sidebar{width:100%;max-width:99%;min-width:0}}.sidebar h2{margin-top:0}.sidebar>ul a{text-decoration:none;color:#999;font-weight:300}.sidebar>ul a:hover{color:#333}.sidebar>ul li{list-style-type:none;line-height:35px;border-bottom:1px dotted #efefef;padding-left:13px}.sidebar>ul li:hover{border-left:5px solid #555;padding-left:8px}.sidebar>ul li.active{border-left:5px solid #333;padding-left:8px}.sidebar>ul li.active a{color:#333;font-weight:bold}.sidebar-icons>ul li{padding-left:0}.sidebar-icons>ul li:hover,.sidebar-icons>ul li.active{padding-left:0;border-left:none}.sidebar>ul li.active a:focus,.sidebar>ul li.active a:hover{color:#555}.sidebar>ul li:last-child{margin-bottom:15px}.avatar img{vertical-align:bottom}.avatar-left{float:left;margin-right:10px}.avatar-inline{display:inline-block;margin-right:3px}.avatar-48 img,.avatar-48 div{border-radius:30px}.avatar-48 .avatar-letter{line-height:48px;width:48px;font-size:25px}.avatar-20 img,.avatar-20 div{border-radius:10px}.avatar-20 .avatar-letter{line-height:20px;width:20px;font-size:11px}.avatar-letter{color:#fff;text-align:center}#file-dropzone,#screenshot-zone{position:relative;border:2px dashed #ccc;width:99%;height:250px;overflow:auto}#file-dropzone-inner,#screenshot-inner{position:absolute;left:0;bottom:48%;width:100%;text-align:center;color:#aaa}#screenshot-zone.screenshot-pasted{border:2px solid #333}#file-list{margin:20px}#file-list li{list-style-type:none;padding-top:8px;padding-bottom:8px;border-bottom:1px dotted #ddd;width:95%}#file-list li.file-error{font-weight:bold;color:#b94a48}.color-picker{width:180px}.color-picker-option{height:25px}.color-picker-square{display:inline-block;width:18px;height:18px;margin-right:5px;border:1px solid #000}.color-picker-label{display:inline-block;vertical-align:bottom;padding-bottom:3px}.file-thumbnails{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;flex-wrap:wrap;-webkit-justify-content:flex-start;justify-content:flex-start}.file-thumbnail{width:250px;border:1px solid #efefef;border-radius:5px;margin-bottom:20px;box-shadow:4px 2px 10px -6px rgba(0,0,0,0.55);margin-right:15px}.file-thumbnail img{border-top-left-radius:5px;border-top-right-radius:5px}.file-thumbnail img:hover{opacity:0.5}.file-thumbnail-content{padding-left:8px;padding-right:8px}.file-thumbnail-title{font-weight:700;font-size:0.9em;color:#555}.file-thumbnail-description{font-size:0.8em;color:#999;margin-top:8px;margin-bottom:5px}.file-viewer{position:relative}.file-viewer img{max-width:95%;max-height:85%;margin-top:10px}.filter-box{max-width:800px}.project-header{margin-top:8px;margin-bottom:20px}.action-menu{color:#333;text-decoration:none}.action-menu:hover,.action-menu:focus{text-decoration:underline}.project-creation-options{max-width:500px;border-left:3px dotted #efefef;margin-top:20px;padding-left:15px;padding-bottom:5px;padding-top:5px}.project-overview-columns{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;align-items:center;-webkit-justify-content:center;justify-content:center;margin-bottom:20px;font-size:1.4em}@media (max-width: 480px){.project-overview-columns{display:block}}.project-overview-column{text-align:center;margin-right:3%;margin-top:5px;padding:3px 15px 3px 15px;border:1px dashed #ddd}@media (max-width: 480px){.project-overview-column{text-align:left}}.project-overview-column small{color:#999}.project-overview-column strong{color:#555;display:block}@media (max-width: 480px){.project-overview-column strong{display:inline}}.project-header{box-sizing:border-box;display:flex;flex-wrap:wrap}.project-header>*{box-sizing:border-box}.project-header>*{width:1%}.project-header .dropdown-component{width:5%}@media (min-width: 768px) and (max-width: 1150px){.project-header .dropdown-component{width:8%}}@media (max-width: 768px){.project-header .dropdown-component{width:100%}}.project-header .views-switcher-component{width:38%}@media (max-width: 1300px){.project-header .views-switcher-component{width:45%}}@media (min-width: 768px) and (max-width: 1150px){.project-header .views-switcher-component{width:92%}}@media (max-width: 768px){.project-header .views-switcher-component{width:100%}}.project-header .filter-box-component{margin:0;width:55%}@media (max-width: 1300px){.project-header .filter-box-component{width:50%}}@media (min-width: 768px) and (max-width: 1150px){.project-header .filter-box-component{width:100%;margin-top:10px}.project-header .filter-box-component .filter-box{max-width:100%}}@media (max-width: 768px){.project-header .filter-box-component{width:100%;margin-top:10px}.project-header .filter-box-component .filter-box{max-width:100%}}.project-header .filter-box-component form{margin:0}.views{display:inline-block;margin-right:10px;font-size:0.9em}@media (max-width: 560px){.views{width:100%}}@media (max-width: 768px){.views{margin-top:10px;font-size:1em}}.views li{white-space:nowrap;background:#fafafa;border:1px solid #ddd;border-right:none;padding:4px 8px;display:inline}@media (max-width: 560px){.views li{display:block;margin-top:5px;border-radius:5px;border:1px solid #ddd}}.views li.active a{font-weight:bold;color:#000;text-decoration:none}.views li:first-child{border-top-left-radius:5px;border-bottom-left-radius:5px}.views li:last-child{border-right:1px solid #ddd;border-top-right-radius:5px;border-bottom-right-radius:5px}.views a{color:#555;text-decoration:none}.views a:hover{color:#333;text-decoration:underline}.dashboard-project-stats small{margin-right:10px;color:#999}.dashboard-table-link{font-weight:bold;color:#000;text-decoration:none}.dashboard-table-link:focus,.dashboard-table-link:hover{color:#999}.public-board{margin-top:5px}.public-task{max-width:800px;margin:5px auto 0}#board-container{overflow-x:auto}#board{table-layout:fixed;margin-bottom:0}#board th.board-column-header{width:240px}#board td{vertical-align:top}.board-container-compact{overflow-x:initial}@media all and (-ms-high-contrast: active), (-ms-high-contrast: none){.board-container-compact #board{table-layout:auto}}#board th.board-column-header.board-column-compact{width:initial}.board-column-collapsed{display:none}td.board-column-task-collapsed{font-weight:bold;background-color:#fbfbfb}#board th.board-column-header-collapsed{width:28px;min-width:28px;text-align:center;overflow:hidden}.board-rotation-wrapper{position:relative;padding:8px 4px;min-height:150px;overflow:hidden}.board-rotation{white-space:nowrap;-webkit-backface-visibility:hidden;-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg);-webkit-transform-origin:0 100%;-moz-transform-origin:0 100%;-ms-transform-origin:0 100%;transform-origin:0 100%}.board-column-title .dropdown-menu{text-decoration:none}.board-add-icon{float:left;padding:0 5px}.board-add-icon a{text-decoration:none;color:#36c;font-size:1.6em;line-height:70%}.board-add-icon a:focus,.board-add-icon a:hover{text-decoration:none;color:red}.board-column-header-task-count{color:#999;font-weight:normal}a.board-swimlane-toggle{text-decoration:none}a.board-swimlane-toggle:hover,a.board-swimlane-toggle:focus{color:#000;text-decoration:none;border:none}.board-task-list{min-height:60px}.board-task-list-limit{background-color:#DF5353}.draggable-item{cursor:pointer;user-select:none;-webkit-user-select:none;-moz-user-select:none}.draggable-placeholder{border:2px dashed #000;background:#fafafa;height:70px;margin-bottom:10px}div.draggable-item-selected{border:1px solid #000}.task-board-sort-handle{float:left;padding-right:5px}.task-board{position:relative;margin-bottom:4px;border:1px solid #000;padding:2px;word-wrap:break-word;font-size:0.9em}div.task-board-recent{border-width:2px}div.task-board-status-closed{user-select:none;border:1px dotted #555}.task-board a{color:#000;text-decoration:none}.task-board .dropdown-menu{font-weight:bold}.task-board .task-score{font-weight:bold}.task-board-collapsed{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.task-board-title{margin-top:5px;margin-bottom:8px}.task-board-title a:hover{text-decoration:underline}.task-board-saving-state{opacity:0.3}.task-board-saving-icon{position:absolute;margin:auto;width:100%;text-align:center;color:#000}.task-board-category-container{text-align:right;margin-top:8px;margin-bottom:8px}.task-board-category{font-weight:500;color:#000;border:1px solid #555;padding:1px 2px 1px 2px;border-radius:4px}.task-board-category:hover{opacity:0.6}.task-board-avatars{text-align:right;float:right}.task-board-change-assignee{cursor:pointer}.task-board-change-assignee:hover{opacity:0.6}.task-board-icons{font-size:0.8em;text-align:right;margin-top:4px;margin-bottom:2px}.task-board-icons a{opacity:0.5}.task-board-icons span{opacity:0.5;margin-left:2px}.task-board-icons a:hover,.task-board-icons span:hover{opacity:1.0}.flag-milestone{color:green}.task-board-age{display:inline-block}span.task-board-age-total{border:#666 1px solid;padding:1px 3px 1px 3px;border-top-left-radius:3px;border-bottom-left-radius:3px}span.task-board-age-column{border:#666 1px solid;border-left:none;margin-left:-5px;padding:1px 3px 1px 3px;border-top-right-radius:3px;border-bottom-right-radius:3px}.task-board-date{font-weight:bold;color:#000}span.task-board-date-today{opacity:1.0}span.task-board-date-overdue{opacity:1.0}.task-tags li{display:inline;margin:0 4px 0 0;padding:2px;color:#555;border:1px solid #666;border-radius:2px}.task-summary-container .task-tags{margin-top:10px}#task-summary{margin-bottom:15px}#task-summary h2{color:#555;font-size:1.6em;margin-top:0;padding-top:0}.task-summary-container{border:2px solid #000;border-radius:8px;padding:15px}.task-summary-columns{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-justify-content:space-between;justify-content:space-between}@media (max-width: 480px){.task-summary-columns{display:block}}.task-summary-column{color:#333}.task-summary-column span{color:#555}.task-summary-column li{line-height:23px}.task-table .dropdown-menu{color:#000;text-decoration:none;font-weight:bold}.task-table .dropdown-menu:focus,.task-table .dropdown-menu:hover{text-decoration:underline}td.task-table a{color:#000;text-decoration:none}td.task-table a:hover{text-decoration:underline}.comment-sorting{text-align:right}.comment-sorting a{color:#555;font-weight:normal;text-decoration:none}.comment-sorting a:hover{color:#999}.comment{padding:5px;margin-bottom:15px}.comment:hover{background:#fafafa}.comment-title{border-bottom:1px dotted #eee;margin-left:55px;margin-bottom:10px}.comment-date{color:#999;font-weight:200}.comment-actions{font-size:0.8em;margin-left:55px;margin-top:8px}.comment-actions li{display:inline}.comment-actions a{color:#999;text-decoration:none}.comment-actions a:focus,.comment-actions a:hover{color:#333;text-decoration:underline}.comment-content{margin-left:55px}.subtasks-table td{vertical-align:middle}.task-links-table td{vertical-align:middle}.task-links-task-count{color:#999}.task-link-closed{text-decoration:line-through}.markdown-editor-container{max-width:400px}div.CodeMirror,div.CodeMirror-scroll{max-height:250px;min-height:200px}.markdown-editor-small div.CodeMirror,.markdown-editor-small div.CodeMirror-scroll{min-height:100px;max-height:180px}.form-column div.CodeMirror{margin-bottom:10px}.markdown{line-height:1.4em}.markdown h1{margin-top:5px;margin-bottom:10px;font-weight:bold}.markdown h2{font-weight:bold}.markdown p{margin-bottom:10px}.markdown ol,.markdown ul{margin-left:25px;margin-top:10px;margin-bottom:10px}.markdown pre{background:#fbfbfb;padding:10px;border-radius:5px;border:1px solid #ddd;overflow:auto;color:#555}.markdown blockquote{font-style:italic;border-left:3px solid #ddd;padding-left:10px;margin-bottom:10px;margin-left:20px}.markdown img{display:block;max-width:80%;margin-top:10px}.documentation{margin:0 auto;padding:20px;max-width:850px;background:#fefefe;border:1px solid #ccc;border-radius:5px;color:#555}.documentation img{border:1px solid #333}.documentation h1{text-decoration:none;margin-bottom:30px}.documentation h2{text-decoration:none;border-bottom:1px solid #ccc;margin-bottom:25px}.documentation li{line-height:30px}.listing{border-radius:4px;padding:8px 35px 8px 14px;margin-bottom:20px;border:1px solid #ddd;color:#333;background-color:#fcfcfc;overflow:auto}.listing li{list-style-type:square;margin-left:20px;margin-bottom:3px}.listing ul{margin-top:15px;margin-bottom:15px}.activity-event{margin-bottom:15px;padding:10px}.activity-event:hover{background:#fafafa}.activity-date{margin-left:10px;font-weight:normal;color:#999}.activity-content{margin-left:55px}.activity-title{font-weight:bold;color:#000;border-bottom:1px dotted #efefef}.activity-description{color:#555;margin-top:10px}@media (max-width: 480px){.activity-description{overflow:auto}}.activity-description li{list-style-type:circle}.activity-description ul{margin-top:10px;margin-left:20px}div.ganttview-hzheader-month,div.ganttview-hzheader-day,div.ganttview-vtheader,div.ganttview-vtheader-item-name,div.ganttview-vtheader-series,div.ganttview-grid,div.ganttview-grid-row-cell{float:left}div.ganttview-hzheader-month,div.ganttview-hzheader-day{text-align:center}div.ganttview-grid-row-cell.last,div.ganttview-hzheader-day.last,div.ganttview-hzheader-month.last{border-right:none}div.ganttview{border:1px solid #999}div.ganttview-hzheader-month{width:60px;height:20px;border-right:1px solid #d0d0d0;line-height:20px;overflow:hidden}div.ganttview-hzheader-day{width:20px;height:20px;border-right:1px solid #f0f0f0;border-top:1px solid #d0d0d0;line-height:20px;color:#555}div.ganttview-vtheader{margin-top:41px;width:400px;overflow:hidden;background-color:#fff}div.ganttview-vtheader-item{color:#555}div.ganttview-vtheader-series-name{width:400px;height:31px;line-height:31px;padding-left:3px;border-top:1px solid #d0d0d0;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}div.ganttview-vtheader-series-name a{color:#555;text-decoration:none}div.ganttview-vtheader-series-name a:hover{color:#333;text-decoration:underline}div.ganttview-vtheader-series-name a i{color:#000}div.ganttview-vtheader-series-name a:hover i{color:#555}div.ganttview-slide-container{overflow:auto;border-left:1px solid #999}div.ganttview-grid-row-cell{width:20px;height:31px;border-right:1px solid #f0f0f0;border-top:1px solid #f0f0f0}div.ganttview-grid-row-cell.ganttview-weekend{background-color:#fafafa}div.ganttview-blocks{margin-top:40px}div.ganttview-block-container{height:28px;padding-top:4px}div.ganttview-block{position:relative;height:25px;background-color:#E5ECF9;border:1px solid #c0c0c0;border-radius:3px}.ganttview-block-movable{cursor:move}div.ganttview-block-not-defined{border-color:#000;background-color:#000}div.ganttview-block-text{position:absolute;height:12px;font-size:0.7em;color:#999;padding:2px 3px}div.ganttview-block div.ui-resizable-handle.ui-resizable-s{bottom:-0}.user-mention-link{font-weight:bold;color:#000;text-decoration:none}.user-mention-link:hover{color:#555} +h1,li,ul,ol,table,tr,td,th,p,blockquote,body{margin:0;padding:0;font-size:100%}body{margin-left:10px;margin-right:10px;padding-bottom:10px;color:#333;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;text-rendering:optimizeLegibility}small{font-size:0.8em}hr{border:0;height:0;border-top:1px solid rgba(0,0,0,0.1);border-bottom:1px solid rgba(255,255,255,0.3)}.pull-right{text-align:right}ul.no-bullet li{list-style-type:none;margin-left:0}.chosen-select{min-height:27px}#app-loading-icon{position:fixed;right:3px;bottom:3px}.assign-me{vertical-align:bottom}a{color:#36c;border:none}a:focus{outline:0;color:#DF5353;text-decoration:none}a:hover{color:#333;text-decoration:none}h1,h2,h3{font-weight:normal;color:#333}h1{font-size:1.5em}h2{font-size:1.4em;margin-bottom:10px}h3{margin-top:10px;font-size:1.2em}table{width:100%;border-collapse:collapse;border-spacing:0;margin-bottom:20px}table.table-fixed{table-layout:fixed;white-space:nowrap}table.table-fixed th{overflow:hidden}table.table-fixed td{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}table.table-small{font-size:0.8em}table.table-striped tr:nth-child(odd){background:#fefefe}@media (max-width: 768px){table.table-scrolling{overflow-x:auto;display:inline-block;vertical-align:top;max-width:100%;white-space:nowrap}}table th{text-align:left;padding:0.5em 3px;border:1px solid #eee;background:#fbfbfb}table th a{text-decoration:none;color:#333}table th a:focus,table th a:hover{text-decoration:underline}table td{border:1px solid #eee;padding:0.5em 3px;vertical-align:top}table td li{margin-left:20px}.column-1{width:1%}.column-2{width:2%}.column-3{width:3%}.column-4{width:4%}.column-5{width:5%}.column-6{width:6%}.column-7{width:7%}.column-8{width:8%}.column-9{width:9%}.column-10{width:10%}.column-11{width:11%}.column-12{width:12%}.column-13{width:13%}.column-14{width:14%}.column-15{width:15%}.column-16{width:16%}.column-17{width:17%}.column-18{width:18%}.column-19{width:19%}.column-20{width:20%}.column-21{width:21%}.column-22{width:22%}.column-23{width:23%}.column-24{width:24%}.column-25{width:25%}.column-26{width:26%}.column-27{width:27%}.column-28{width:28%}.column-29{width:29%}.column-30{width:30%}.column-31{width:31%}.column-32{width:32%}.column-33{width:33%}.column-34{width:34%}.column-35{width:35%}.column-36{width:36%}.column-37{width:37%}.column-38{width:38%}.column-39{width:39%}.column-40{width:40%}.column-41{width:41%}.column-42{width:42%}.column-43{width:43%}.column-44{width:44%}.column-45{width:45%}.column-46{width:46%}.column-47{width:47%}.column-48{width:48%}.column-49{width:49%}.column-50{width:50%}.column-51{width:51%}.column-52{width:52%}.column-53{width:53%}.column-54{width:54%}.column-55{width:55%}.column-56{width:56%}.column-57{width:57%}.column-58{width:58%}.column-59{width:59%}.column-60{width:60%}.column-61{width:61%}.column-62{width:62%}.column-63{width:63%}.column-64{width:64%}.column-65{width:65%}.column-66{width:66%}.column-67{width:67%}.column-68{width:68%}.column-69{width:69%}.column-70{width:70%}.column-71{width:71%}.column-72{width:72%}.column-73{width:73%}.column-74{width:74%}.column-75{width:75%}.column-76{width:76%}.column-77{width:77%}.column-78{width:78%}.column-79{width:79%}.column-80{width:80%}.column-81{width:81%}.column-82{width:82%}.column-83{width:83%}.column-84{width:84%}.column-85{width:85%}.column-86{width:86%}.column-87{width:87%}.column-88{width:88%}.column-89{width:89%}.column-90{width:90%}.column-91{width:91%}.column-92{width:92%}.column-93{width:93%}.column-94{width:94%}.column-95{width:95%}.column-96{width:96%}.column-97{width:97%}.column-98{width:98%}.column-99{width:99%}.column-100{width:100%}.draggable-row-handle{cursor:move;color:#dedede}.draggable-row-handle:hover{color:#333}tr.draggable-item-selected{background:#fff;border:2px solid #666;box-shadow:4px 2px 10px -4px rgba(0,0,0,0.55)}tr.draggable-item-selected td{border-top:none;border-bottom:none}tr.draggable-item-selected td:first-child{border-left:none}tr.draggable-item-selected td:last-child{border-right:none}.table-stripped tr.draggable-item-hover,.table-stripped tr.draggable-item-hover{background:#FEFFF2}form{margin-bottom:20px}label{cursor:pointer;display:block;margin-top:10px}input[type="number"],input[type="date"],input[type="email"],input[type="password"],input[type="text"]:not(.input-addon-field){color:#999;border:1px solid #ccc;width:300px;max-width:95%;font-size:1em;height:25px;padding-bottom:0;font-family:sans-serif;margin-top:10px;-webkit-appearance:none;-moz-appearance:none}input[type="number"]::-webkit-input-placeholder,input[type="date"]::-webkit-input-placeholder,input[type="email"]::-webkit-input-placeholder,input[type="password"]::-webkit-input-placeholder,input[type="text"]:not(.input-addon-field)::-webkit-input-placeholder{color:#dedede}input[type="number"]:-moz-placeholder,input[type="date"]:-moz-placeholder,input[type="email"]:-moz-placeholder,input[type="password"]:-moz-placeholder,input[type="text"]:not(.input-addon-field):-moz-placeholder{color:#dedede}input[type="number"]::-moz-placeholder,input[type="date"]::-moz-placeholder,input[type="email"]::-moz-placeholder,input[type="password"]::-moz-placeholder,input[type="text"]:not(.input-addon-field)::-moz-placeholder{color:#dedede}input[type="number"]:-ms-input-placeholder,input[type="date"]:-ms-input-placeholder,input[type="email"]:-ms-input-placeholder,input[type="password"]:-ms-input-placeholder,input[type="text"]:not(.input-addon-field):-ms-input-placeholder{color:#dedede}input[type="number"]:focus,input[type="date"]:focus,input[type="email"]:focus,input[type="password"]:focus,input[type="text"]:focus{color:#000;border-color:rgba(82,168,236,0.8);outline:0;box-shadow:0 0 8px rgba(82,168,236,0.6)}input[type="number"]{width:70px}input[type="text"]:not(.input-addon-field).form-numeric{width:70px}input[type="text"]:not(.input-addon-field).form-datetime,input[type="text"]:not(.input-addon-field).form-date{width:150px}input[type="text"]:not(.input-addon-field).form-input-large{width:400px}input[type="text"]:not(.input-addon-field).form-input-small{width:150px}textarea:focus{color:#000;border-color:rgba(82,168,236,0.8);outline:0;box-shadow:0 0 8px rgba(82,168,236,0.6)}textarea{border:1px solid #ccc;width:400px;max-width:99%;height:200px;font-family:sans-serif}select{max-width:95%}select:focus{outline:0}.tag-autocomplete{width:400px}span.select2-container{margin-top:2px}.form-actions{padding-top:20px;clear:both}.form-required{color:red;padding-left:5px;font-weight:bold}@media (max-width: 480px){.form-required{display:none}}input.form-error,textarea.form-error{border:2px solid #b94a48}input.form-error:focus,textarea.form-error:focus{box-shadow:none;border:2px solid #b94a48}.form-errors{color:#b94a48;list-style-type:none}ul.form-errors li{margin-left:0}.form-help{font-size:0.8em;color:brown;margin-bottom:15px}.form-inline{padding:0;margin:0;border:none}.form-inline label{display:inline}.form-inline input,.form-inline select{margin:0 15px 0 0}.form-inline .form-required{display:none}.form-inline-group{display:inline}.form-columns{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;flex-wrap:wrap;-webkit-justify-content:flex-start;justify-content:flex-start}.form-columns .form-column{margin-right:25px}.form-login{width:350px;margin:8% auto 0}.form-login li{margin-left:25px;line-height:25px}.form-login h2{margin-bottom:30px;font-weight:bold}.reset-password{margin-top:20px}.reset-password a{color:#999}.input-addon{display:flex}.input-addon-field{flex:1;font-size:1em;color:#999;margin:0;-webkit-appearance:none;-moz-appearance:none}.input-addon-item{background-color:rgba(147,128,108,0.1);color:#666;font:inherit;font-weight:normal}@media (max-width: 480px){.input-addon-item .dropdown .fa-caret-down{display:none}}.input-addon-field,.input-addon-item{border:1px solid rgba(147,128,108,0.25);padding:4px 0.75em}.input-addon-field:not(:first-child),.input-addon-item:not(:first-child){border-left:0}.input-addon-field:first-child,.input-addon-item:first-child{border-radius:5px 0 0 5px}.input-addon-field:last-child,.input-addon-item:last-child{border-radius:0 5px 5px 0}.alert{padding:8px 35px 8px 14px;margin-top:5px;margin-bottom:5px;color:#c09853;background-color:#fcf8e3;border:1px solid #fbeed5;border-radius:4px}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-normal{color:#333;background-color:#f0f0f0;border-color:#ddd}.alert ul{margin-top:10px;margin-bottom:10px}.alert li{margin-left:25px}.alert-fade-out{text-align:center;position:fixed;bottom:0;left:20%;width:60%;padding-top:5px;padding-bottom:5px;margin-bottom:0;border-width:1px 0 0;border-radius:4px 4px 0 0;z-index:9999}a.btn{text-decoration:none}.btn{-webkit-appearance:none;-moz-appearance:none;font-size:1.2em;font-weight:normal;cursor:pointer;display:inline-block;border-radius:2px;padding:3px 10px;margin:0;border:1px solid #ddd;background:#f5f5f5;color:#333}.btn:hover,.btn:focus{border-color:#bbb;background:#fafafa;color:#000}.btn-red{border-color:#b0281a;background:#d14836;color:#fff}.btn-red:hover,.btn-red:focus{border-color:#b0281a;background:#c53727;color:#fff}.btn-blue{border-color:#3079ed;background:#4d90fe;color:#fff}.btn-blue:hover,.btn-blue:focus{border-color:#3079ed;background:#357ae8;color:#fff}.btn:disabled{color:#ccc;border-color:#ccc;background:#f7f7f7}.buttons-header{font-size:0.8em;margin-top:5px;margin-bottom:15px}.tooltip-arrow:after{background:#fff;border:1px solid #aaaaaa;box-shadow:0 0 5px #aaa}div.ui-tooltip{min-width:200px;max-width:600px}.tooltip-arrow{width:20px;height:10px;overflow:hidden;position:absolute}.tooltip-arrow.top{top:-10px}.tooltip-arrow.bottom{bottom:-10px}.tooltip-arrow.align-left{left:10px}.tooltip-arrow.align-right{right:10px}.tooltip-arrow:after{content:"";position:absolute;width:14px;height:14px;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg)}.tooltip-arrow.bottom:after{top:-10px}.tooltip-arrow.top:after{bottom:-10px}.tooltip-arrow.align-left:after{left:0}.tooltip-arrow.align-right:after{right:0}.tooltip-large{width:600px}.ui-tooltip-content .markdown p{margin-bottom:0}.ui-tooltip li{list-style-type:none}.tooltip .fa-info-circle{color:#999}.dropdown{display:inline;position:relative}.dropdown ul{display:none}ul.dropdown-submenu-open{display:block;position:absolute;z-index:1000;min-width:285px;list-style:none;margin:3px 0 0 1px;padding:6px 0;background-color:#fff;border:1px solid #b2b2b2;border-radius:3px;box-shadow:0 1px 3px rgba(0,0,0,0.15)}.dropdown-submenu-open li{display:block;margin:0;padding:8px 10px;font-size:0.9em;border-bottom:1px solid #f8f8f8;cursor:pointer}.dropdown-submenu-open li.no-hover{cursor:default}.dropdown-submenu-open li:last-child{border:none}.dropdown-submenu-open li:not(.no-hover):hover{background:#4078C0;color:#fff}.dropdown-submenu-open li:hover a{color:#fff}.dropdown-submenu-open a{text-decoration:none;color:#333}.dropdown-submenu-open a:focus{text-decoration:underline}.dropdown-menu-link-text,.dropdown-menu-link-icon{color:#333;text-decoration:none}.dropdown-menu-link-text:hover{text-decoration:underline}.accordion-title{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAADCAYAAABS3WWCAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NEQ5RDgxQzc2RjQ5MTFFMjhEMUNENzFGRUMwRjhBRTciIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NEQ5RDgxQzg2RjQ5MTFFMjhEMUNENzFGRUMwRjhBRTciPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo0RDlEODFDNTZGNDkxMUUyOEQxQ0Q3MUZFQzBGOEFFNyIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo0RDlEODFDNjZGNDkxMUUyOEQxQ0Q3MUZFQzBGOEFFNyIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PvXFWFAAAAAYSURBVHjaYvj//z8D0/Pnz/8zgFgAAQYAS5UJscReGMIAAAAASUVORK5CYII=) repeat-x scroll 0 10px}.accordion-title h3{display:inline;padding-right:5px;background:#fff}.accordion-content{margin-top:15px;margin-bottom:25px}.accordion-toggle{color:#333;text-decoration:none}.accordion-toggle:focus{color:#333}.accordion-toggle:hover{color:#999}.accordion-toggle:before{content:"\f0d7"}.accordion-collapsed{margin-bottom:25px}.accordion-collapsed .accordion-toggle:before{content:"\f0da"}.accordion-collapsed .accordion-content{display:none}#main .confirm{max-width:700px}#popover-container{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.8);overflow:auto;z-index:100}#popover-content{position:absolute;width:75%;left:12%;top:1%;padding:15px;background:#fff;overflow:auto;max-height:95%}@media (max-width: 480px){#popover-content{left:0;width:100%}}@media (max-width: 768px){#popover-content{left:2.5%;width:85%}}.popover-form{margin-bottom:0}.pagination{text-align:center}.pagination-next{margin-left:5px}.pagination-previous{margin-right:5px}header{box-sizing:border-box;display:flex;flex-wrap:wrap;margin-top:5px;margin-bottom:5px;border-bottom:1px solid #dedede}header>*{box-sizing:border-box}header>*{width:1%}header .menus-container{width:10%}@media (min-width: 768px) and (max-width: 1150px){header .menus-container{width:15%}}@media (max-width: 768px){header .menus-container{width:65%;order:2}}header .board-selector-container{width:15%}@media (min-width: 768px) and (max-width: 1150px){header .board-selector-container{width:20%}}@media (max-width: 768px){header .board-selector-container{width:35%;order:1;margin-bottom:5px}}header .title-container{width:75%}@media (min-width: 768px) and (max-width: 1150px){header .title-container{width:65%}}@media (max-width: 768px){header .title-container{width:100%;order:3}}header h1{font-size:1.5em}header h1 .tooltip{opacity:0.3;font-size:0.7em}.web-notification-icon{color:#36c}.web-notification-icon:focus,.web-notification-icon:hover{color:#000}.logo a{opacity:0.5;color:#d40000;text-decoration:none}.logo span{color:#333}.logo a:hover{opacity:0.8;color:#333}.logo a:focus span,.logo a:hover span{color:#d40000}.page-header{margin-bottom:20px}.page-header .dropdown{padding-right:10px}.page-header h2{margin:0;padding:0;font-weight:bold;border-bottom:1px dotted #ccc}.page-header h2 a{color:#333;text-decoration:none}.page-header h2 a:focus,.page-header h2 a:hover{color:#999}.page-header ul{text-align:left;margin-top:5px;display:inline-block}.page-header li{display:inline;padding-right:15px}@media (max-width: 480px){.page-header li{display:block;line-height:1.5em}}.page-header li.active a{color:#333;text-decoration:none;font-weight:bold}.page-header li.active a:hover,.page-header li.active a:focus{text-decoration:underline}.menu-inline{margin-bottom:5px}.menu-inline li{display:inline;padding-right:15px}.menu-inline li .active a{font-weight:bold;color:#000;text-decoration:none}.sidebar-container{box-sizing:border-box;display:flex;flex-wrap:wrap}.sidebar-container>*{box-sizing:border-box}.sidebar-container>*{width:1%}.sidebar-content{padding-left:10px;width:82%}@media (max-width: 480px){.sidebar-content{width:100%}}.sidebar{max-width:240px;min-width:190px;width:18%}@media (max-width: 480px){.sidebar{width:100%;max-width:99%;min-width:0}}.sidebar h2{margin-top:0}.sidebar>ul a{text-decoration:none;color:#999;font-weight:300}.sidebar>ul a:hover{color:#333}.sidebar>ul li{list-style-type:none;line-height:35px;border-bottom:1px dotted #efefef;padding-left:13px}.sidebar>ul li:hover{border-left:5px solid #555;padding-left:8px}.sidebar>ul li.active{border-left:5px solid #333;padding-left:8px}.sidebar>ul li.active a{color:#333;font-weight:bold}.sidebar-icons>ul li{padding-left:0}.sidebar-icons>ul li:hover,.sidebar-icons>ul li.active{padding-left:0;border-left:none}.sidebar>ul li.active a:focus,.sidebar>ul li.active a:hover{color:#555}.sidebar>ul li:last-child{margin-bottom:15px}.avatar img{vertical-align:bottom}.avatar-left{float:left;margin-right:10px}.avatar-inline{display:inline-block;margin-right:3px}.avatar-48 img,.avatar-48 div{border-radius:30px}.avatar-48 .avatar-letter{line-height:48px;width:48px;font-size:25px}.avatar-20 img,.avatar-20 div{border-radius:10px}.avatar-20 .avatar-letter{line-height:20px;width:20px;font-size:11px}.avatar-letter{color:#fff;text-align:center}#file-dropzone,#screenshot-zone{position:relative;border:2px dashed #ccc;width:99%;height:250px;overflow:auto}#file-dropzone-inner,#screenshot-inner{position:absolute;left:0;bottom:48%;width:100%;text-align:center;color:#aaa}#screenshot-zone.screenshot-pasted{border:2px solid #333}#file-list{margin:20px}#file-list li{list-style-type:none;padding-top:8px;padding-bottom:8px;border-bottom:1px dotted #ddd;width:95%}#file-list li.file-error{font-weight:bold;color:#b94a48}.file-thumbnails{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;flex-wrap:wrap;-webkit-justify-content:flex-start;justify-content:flex-start}.file-thumbnail{width:250px;border:1px solid #efefef;border-radius:5px;margin-bottom:20px;box-shadow:4px 2px 10px -6px rgba(0,0,0,0.55);margin-right:15px}.file-thumbnail img{border-top-left-radius:5px;border-top-right-radius:5px}.file-thumbnail img:hover{opacity:0.5}.file-thumbnail-content{padding-left:8px;padding-right:8px}.file-thumbnail-title{font-weight:700;font-size:0.9em;color:#555}.file-thumbnail-description{font-size:0.8em;color:#999;margin-top:8px;margin-bottom:5px}.file-viewer{position:relative}.file-viewer img{max-width:95%;max-height:85%;margin-top:10px}.color-picker{width:180px}.color-picker-option{height:25px}.color-picker-square{display:inline-block;width:18px;height:18px;margin-right:5px;border:1px solid #000}.color-picker-label{display:inline-block;vertical-align:bottom;padding-bottom:3px}.filter-box{max-width:800px}.project-header{margin-top:8px;margin-bottom:20px}.action-menu{color:#333;text-decoration:none}.action-menu:hover,.action-menu:focus{text-decoration:underline}.project-creation-options{max-width:500px;border-left:3px dotted #efefef;margin-top:20px;padding-left:15px;padding-bottom:5px;padding-top:5px}.project-overview-columns{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;align-items:center;-webkit-justify-content:center;justify-content:center;margin-bottom:20px;font-size:1.4em}@media (max-width: 480px){.project-overview-columns{display:block}}.project-overview-column{text-align:center;margin-right:3%;margin-top:5px;padding:3px 15px 3px 15px;border:1px dashed #ddd}@media (max-width: 480px){.project-overview-column{text-align:left}}.project-overview-column small{color:#999}.project-overview-column strong{color:#555;display:block}@media (max-width: 480px){.project-overview-column strong{display:inline}}.project-header{box-sizing:border-box;display:flex;flex-wrap:wrap}.project-header>*{box-sizing:border-box}.project-header>*{width:1%}.project-header .dropdown-component{width:5%}@media (min-width: 768px) and (max-width: 1150px){.project-header .dropdown-component{width:8%}}@media (max-width: 768px){.project-header .dropdown-component{width:100%}}.project-header .views-switcher-component{width:38%}@media (max-width: 1300px){.project-header .views-switcher-component{width:45%}}@media (min-width: 768px) and (max-width: 1150px){.project-header .views-switcher-component{width:92%}}@media (max-width: 768px){.project-header .views-switcher-component{width:100%}}.project-header .filter-box-component{margin:0;width:55%}@media (max-width: 1300px){.project-header .filter-box-component{width:50%}}@media (min-width: 768px) and (max-width: 1150px){.project-header .filter-box-component{width:100%;margin-top:10px}.project-header .filter-box-component .filter-box{max-width:100%}}@media (max-width: 768px){.project-header .filter-box-component{width:100%;margin-top:10px}.project-header .filter-box-component .filter-box{max-width:100%}}.project-header .filter-box-component form{margin:0}.views{display:inline-block;margin-right:10px;font-size:0.9em}@media (max-width: 560px){.views{width:100%}}@media (max-width: 768px){.views{margin-top:10px;font-size:1em}}.views li{white-space:nowrap;background:#fafafa;border:1px solid #ddd;border-right:none;padding:4px 8px;display:inline}@media (max-width: 560px){.views li{display:block;margin-top:5px;border-radius:5px;border:1px solid #ddd}}.views li.active a{font-weight:bold;color:#000;text-decoration:none}.views li:first-child{border-top-left-radius:5px;border-bottom-left-radius:5px}.views li:last-child{border-right:1px solid #ddd;border-top-right-radius:5px;border-bottom-right-radius:5px}.views a{color:#555;text-decoration:none}.views a:hover{color:#333;text-decoration:underline}.dashboard-project-stats small{margin-right:10px;color:#999}.dashboard-table-link{font-weight:bold;color:#000;text-decoration:none}.dashboard-table-link:focus,.dashboard-table-link:hover{color:#999}.public-board{margin-top:5px}.public-task{max-width:800px;margin:5px auto 0}#board-container{overflow-x:auto}#board{table-layout:fixed;margin-bottom:0}#board th.board-column-header{width:240px}#board td{vertical-align:top}.board-container-compact{overflow-x:initial}@media all and (-ms-high-contrast: active), (-ms-high-contrast: none){.board-container-compact #board{table-layout:auto}}#board th.board-column-header.board-column-compact{width:initial}.board-column-collapsed{display:none}td.board-column-task-collapsed{font-weight:bold;background-color:#fbfbfb}#board th.board-column-header-collapsed{width:28px;min-width:28px;text-align:center;overflow:hidden}.board-rotation-wrapper{position:relative;padding:8px 4px;min-height:150px;overflow:hidden}.board-rotation{white-space:nowrap;-webkit-backface-visibility:hidden;-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg);-webkit-transform-origin:0 100%;-moz-transform-origin:0 100%;-ms-transform-origin:0 100%;transform-origin:0 100%}.board-column-title .dropdown-menu{text-decoration:none}.board-add-icon{float:left;padding:0 5px}.board-add-icon a{text-decoration:none;color:#36c;font-size:1.6em;line-height:70%}.board-add-icon a:focus,.board-add-icon a:hover{text-decoration:none;color:red}.board-column-header-task-count{color:#999;font-weight:normal}a.board-swimlane-toggle{text-decoration:none}a.board-swimlane-toggle:hover,a.board-swimlane-toggle:focus{color:#000;text-decoration:none;border:none}.board-task-list{min-height:60px}.board-task-list-limit{background-color:#DF5353}.draggable-item{cursor:pointer;user-select:none;-webkit-user-select:none;-moz-user-select:none}.draggable-placeholder{border:2px dashed #000;background:#fafafa;height:70px;margin-bottom:10px}div.draggable-item-selected{border:1px solid #000}.task-board-sort-handle{float:left;padding-right:5px}.task-board{position:relative;margin-bottom:4px;border:1px solid #000;padding:2px;word-wrap:break-word;font-size:0.9em}div.task-board-recent{border-width:2px}div.task-board-status-closed{user-select:none;border:1px dotted #555}.task-board a{color:#000;text-decoration:none}.task-board .dropdown-menu{font-weight:bold}.task-board .task-score{font-weight:bold}.task-board-collapsed{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.task-board-title{margin-top:5px;margin-bottom:8px}.task-board-title a:hover{text-decoration:underline}.task-board-saving-state{opacity:0.3}.task-board-saving-icon{position:absolute;margin:auto;width:100%;text-align:center;color:#000}.task-board-category-container{text-align:right;margin-top:8px;margin-bottom:8px}.task-board-category{font-weight:500;color:#000;border:1px solid #555;padding:1px 2px 1px 2px;border-radius:4px}.task-board-category:hover{opacity:0.6}.task-board-avatars{text-align:right;float:right}.task-board-change-assignee{cursor:pointer}.task-board-change-assignee:hover{opacity:0.6}.task-board-icons{font-size:0.8em;text-align:right;margin-top:4px;margin-bottom:2px}.task-board-icons a{opacity:0.5}.task-board-icons span{opacity:0.5;margin-left:2px}.task-board-icons a:hover,.task-board-icons span:hover{opacity:1.0}.flag-milestone{color:green}.task-board-age{display:inline-block}span.task-board-age-total{border:#666 1px solid;padding:1px 3px 1px 3px;border-top-left-radius:3px;border-bottom-left-radius:3px}span.task-board-age-column{border:#666 1px solid;border-left:none;margin-left:-5px;padding:1px 3px 1px 3px;border-top-right-radius:3px;border-bottom-right-radius:3px}.task-board-date{font-weight:bold;color:#000}span.task-board-date-today{opacity:1.0}span.task-board-date-overdue{opacity:1.0}.task-tags li{display:inline;margin:0 4px 0 0;padding:2px;color:#555;border:1px solid #666;border-radius:2px}.task-summary-container .task-tags{margin-top:10px}#task-summary{margin-bottom:15px}#task-summary h2{color:#555;font-size:1.6em;margin-top:0;padding-top:0}.task-summary-container{border:2px solid #000;border-radius:8px;padding:15px}.task-summary-columns{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-justify-content:space-between;justify-content:space-between}@media (max-width: 480px){.task-summary-columns{display:block}}.task-summary-column{color:#333}.task-summary-column span{color:#555}.task-summary-column li{line-height:23px}.task-table .dropdown-menu{color:#000;text-decoration:none;font-weight:bold}.task-table .dropdown-menu:focus,.task-table .dropdown-menu:hover{text-decoration:underline}td.task-table a{color:#000;text-decoration:none}td.task-table a:hover{text-decoration:underline}.comment-sorting{text-align:right}.comment-sorting a{color:#555;font-weight:normal;text-decoration:none}.comment-sorting a:hover{color:#999}.comment{padding:5px;margin-bottom:15px}.comment:hover{background:#fafafa}.comment-title{border-bottom:1px dotted #eee;margin-left:55px;margin-bottom:10px}.comment-date{color:#999;font-weight:200}.comment-actions{font-size:0.8em;margin-left:55px;margin-top:8px}.comment-actions li{display:inline}.comment-actions a{color:#999;text-decoration:none}.comment-actions a:focus,.comment-actions a:hover{color:#333;text-decoration:underline}.comment-content{margin-left:55px}.subtasks-table td{vertical-align:middle}.task-links-table td{vertical-align:middle}.task-links-task-count{color:#999}.task-link-closed{text-decoration:line-through}.markdown-editor-container{max-width:400px}div.CodeMirror,div.CodeMirror-scroll{max-height:250px;min-height:200px}.markdown-editor-small div.CodeMirror,.markdown-editor-small div.CodeMirror-scroll{min-height:100px;max-height:180px}.form-column div.CodeMirror{margin-bottom:10px}.markdown{line-height:1.4em}.markdown h1{margin-top:5px;margin-bottom:10px;font-weight:bold}.markdown h2{font-weight:bold}.markdown p{margin-bottom:10px}.markdown ol,.markdown ul{margin-left:25px;margin-top:10px;margin-bottom:10px}.markdown pre{background:#fbfbfb;padding:10px;border-radius:5px;border:1px solid #ddd;overflow:auto;color:#555}.markdown blockquote{font-style:italic;border-left:3px solid #ddd;padding-left:10px;margin-bottom:10px;margin-left:20px}.markdown img{display:block;max-width:80%;margin-top:10px}.documentation{margin:0 auto;padding:20px;max-width:850px;background:#fefefe;border:1px solid #ccc;border-radius:5px;color:#555}.documentation img{border:1px solid #333}.documentation h1{text-decoration:none;margin-bottom:30px}.documentation h2{text-decoration:none;border-bottom:1px solid #ccc;margin-bottom:25px}.documentation li{line-height:30px}.listing{border-radius:4px;padding:8px 35px 8px 14px;margin-bottom:20px;border:1px solid #ddd;color:#333;background-color:#fcfcfc;overflow:auto}.listing li{list-style-type:square;margin-left:20px;margin-bottom:3px}.listing ul{margin-top:15px;margin-bottom:15px}.activity-event{margin-bottom:15px;padding:10px}.activity-event:hover{background:#fafafa}.activity-date{margin-left:10px;font-weight:normal;color:#999}.activity-content{margin-left:55px}.activity-title{font-weight:bold;color:#000;border-bottom:1px dotted #efefef}.activity-description{color:#555;margin-top:10px}@media (max-width: 480px){.activity-description{overflow:auto}}.activity-description li{list-style-type:circle}.activity-description ul{margin-top:10px;margin-left:20px}div.ganttview-hzheader-month,div.ganttview-hzheader-day,div.ganttview-vtheader,div.ganttview-vtheader-item-name,div.ganttview-vtheader-series,div.ganttview-grid,div.ganttview-grid-row-cell{float:left}div.ganttview-hzheader-month,div.ganttview-hzheader-day{text-align:center}div.ganttview-grid-row-cell.last,div.ganttview-hzheader-day.last,div.ganttview-hzheader-month.last{border-right:none}div.ganttview{border:1px solid #999}div.ganttview-hzheader-month{width:60px;height:20px;border-right:1px solid #d0d0d0;line-height:20px;overflow:hidden}div.ganttview-hzheader-day{width:20px;height:20px;border-right:1px solid #f0f0f0;border-top:1px solid #d0d0d0;line-height:20px;color:#555}div.ganttview-vtheader{margin-top:41px;width:400px;overflow:hidden;background-color:#fff}div.ganttview-vtheader-item{color:#555}div.ganttview-vtheader-series-name{width:400px;height:31px;line-height:31px;padding-left:3px;border-top:1px solid #d0d0d0;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}div.ganttview-vtheader-series-name a{color:#555;text-decoration:none}div.ganttview-vtheader-series-name a:hover{color:#333;text-decoration:underline}div.ganttview-vtheader-series-name a i{color:#000}div.ganttview-vtheader-series-name a:hover i{color:#555}div.ganttview-slide-container{overflow:auto;border-left:1px solid #999}div.ganttview-grid-row-cell{width:20px;height:31px;border-right:1px solid #f0f0f0;border-top:1px solid #f0f0f0}div.ganttview-grid-row-cell.ganttview-weekend{background-color:#fafafa}div.ganttview-blocks{margin-top:40px}div.ganttview-block-container{height:28px;padding-top:4px}div.ganttview-block{position:relative;height:25px;background-color:#E5ECF9;border:1px solid #c0c0c0;border-radius:3px}.ganttview-block-movable{cursor:move}div.ganttview-block-not-defined{border-color:#000;background-color:#000}div.ganttview-block-text{position:absolute;height:12px;font-size:0.7em;color:#999;padding:2px 3px}div.ganttview-block div.ui-resizable-handle.ui-resizable-s{bottom:-0}.user-mention-link{font-weight:bold;color:#000;text-decoration:none}.user-mention-link:hover{color:#555} diff --git a/assets/sass/_files.sass b/assets/sass/_files.sass deleted file mode 100644 index 9e130576..00000000 --- a/assets/sass/_files.sass +++ /dev/null @@ -1,43 +0,0 @@ -@import variables -@import mixins - -.file-thumbnails - +display-flex - +flex-direction(row) - +flex-wrap - +justify-content(flex-start) - -.file-thumbnail - width: 250px - border: 1px solid #efefef - border-radius: 5px - margin-bottom: 20px - box-shadow: 4px 2px 10px -6px rgba(0, 0, 0, 0.55) - margin-right: 15px - img - border-top-left-radius: 5px - border-top-right-radius: 5px - &:hover - opacity: 0.5 - -.file-thumbnail-content - padding-left: 8px - padding-right: 8px - -.file-thumbnail-title - font-weight: 700 - font-size: size('compact') - color: color('medium') - -.file-thumbnail-description - font-size: size('small') - color: color('light') - margin-top: 8px - margin-bottom: 5px - -.file-viewer - position: relative - img - max-width: 95% - max-height: 85% - margin-top: 10px diff --git a/assets/sass/_form.sass b/assets/sass/_form.sass index d70d505c..8db142af 100644 --- a/assets/sass/_form.sass +++ b/assets/sass/_form.sass @@ -70,6 +70,14 @@ span.select2-container padding-top: 20px clear: both +.form-required + color: red + padding-left: 5px + font-weight: bold + + @include xs-device + display: none + input.form-error, textarea.form-error border: 2px solid #b94a48 @@ -77,11 +85,6 @@ input.form-error:focus, textarea.form-error:focus box-shadow: none border: 2px solid #b94a48 -.form-required - color: red - padding-left: 5px - font-weight: bold - .form-errors color: color('error') list-style-type: none @@ -109,13 +112,13 @@ ul.form-errors li display: inline .form-columns - display: -webkit-flex - display: flex - -webkit-flex-direction: row - flex-direction: row + +display-flex + +flex-direction(row) + +flex-wrap + +justify-content(flex-start) -.form-column - margin-right: 25px + .form-column + margin-right: 25px .form-login width: 350px diff --git a/assets/sass/_popover.sass b/assets/sass/_popover.sass index ed58cfbc..3939f059 100644 --- a/assets/sass/_popover.sass +++ b/assets/sass/_popover.sass @@ -1,4 +1,5 @@ @import variables +@import mixins #popover-container position: fixed @@ -12,13 +13,21 @@ #popover-content position: absolute - width: 70% - left: 15% + width: 75% + left: 12% top: 1% padding: 15px background: #fff overflow: auto - max-height: 90% + max-height: 95% + + @include xs-device + left: 0 + width: 100% + + @include sm-device + left: 2.5% + width: 85% .popover-form margin-bottom: 0 diff --git a/assets/sass/_thumbnails.sass b/assets/sass/_thumbnails.sass new file mode 100644 index 00000000..9e130576 --- /dev/null +++ b/assets/sass/_thumbnails.sass @@ -0,0 +1,43 @@ +@import variables +@import mixins + +.file-thumbnails + +display-flex + +flex-direction(row) + +flex-wrap + +justify-content(flex-start) + +.file-thumbnail + width: 250px + border: 1px solid #efefef + border-radius: 5px + margin-bottom: 20px + box-shadow: 4px 2px 10px -6px rgba(0, 0, 0, 0.55) + margin-right: 15px + img + border-top-left-radius: 5px + border-top-right-radius: 5px + &:hover + opacity: 0.5 + +.file-thumbnail-content + padding-left: 8px + padding-right: 8px + +.file-thumbnail-title + font-weight: 700 + font-size: size('compact') + color: color('medium') + +.file-thumbnail-description + font-size: size('small') + color: color('light') + margin-top: 8px + margin-bottom: 5px + +.file-viewer + position: relative + img + max-width: 95% + max-height: 85% + margin-top: 10px diff --git a/assets/sass/app.sass b/assets/sass/app.sass index 8c109ebb..9a93e4ab 100644 --- a/assets/sass/app.sass +++ b/assets/sass/app.sass @@ -20,8 +20,8 @@ @import sidebar @import avatar @import file_upload +@import thumbnails @import color_picker -@import files @import filter_box @import project @import project_overview -- cgit v1.2.3 From 5f82a942c0011bf91947b2c1d627c0907bda0c92 Mon Sep 17 00:00:00 2001 From: Frederic Guillot Date: Mon, 15 Aug 2016 20:46:26 -0400 Subject: Fix PHP notice when sending overdue notifications --- ChangeLog | 4 ++++ app/Notification/MailNotification.php | 2 +- tests/units/Notification/MailNotificationTest.php | 5 +++++ 3 files changed, 10 insertions(+), 1 deletion(-) (limited to 'app') diff --git a/ChangeLog b/ChangeLog index 1ef7ebd3..a559b4ff 100644 --- a/ChangeLog +++ b/ChangeLog @@ -13,6 +13,10 @@ Improvements: * Show project name in task forms * Convert vanilla CSS to SASS +Bug fixes: + +* Fix PHP notice when sending overdue notifications + Version 1.0.32 -------------- diff --git a/app/Notification/MailNotification.php b/app/Notification/MailNotification.php index a5f51b89..9e042820 100644 --- a/app/Notification/MailNotification.php +++ b/app/Notification/MailNotification.php @@ -80,7 +80,7 @@ class MailNotification extends Base implements NotificationInterface { return sprintf( '[%s] %s', - $eventData['task']['project_name'], + isset($eventData['project_name']) ? $eventData['project_name'] : $eventData['task']['project_name'], $this->notificationModel->getTitleWithoutAuthor($eventName, $eventData) ); } diff --git a/tests/units/Notification/MailNotificationTest.php b/tests/units/Notification/MailNotificationTest.php index 05f1f882..93eeef0c 100644 --- a/tests/units/Notification/MailNotificationTest.php +++ b/tests/units/Notification/MailNotificationTest.php @@ -58,6 +58,11 @@ class MailNotificationTest extends Base $this->assertNotEmpty($mailNotification->getMailContent($eventName, $eventData)); $this->assertStringStartsWith('[test] ', $mailNotification->getMailSubject($eventName, $eventData)); } + + $this->assertStringStartsWith('[Test1, Test2] ', $mailNotification->getMailSubject(TaskModel::EVENT_OVERDUE, array( + 'tasks' => array(array('id' => 123), array('id' => 456)), + 'project_name' => 'Test1, Test2', + ))); } public function testSendWithEmailAddress() -- cgit v1.2.3
order(t('Id'), 'id') ?> order(t('External Id'), 'external_id') ?>