Boards use language settings, columns have task limit

This commit is contained in:
kiswa 2017-07-28 19:36:33 +00:00
parent d133903a37
commit 29edbaaed6
13 changed files with 356 additions and 92 deletions

View File

@ -6,7 +6,7 @@ linters:
width: 4
NestingDepth:
max_depth: 4
max_depth: 5
SelectorDepth:
max_depth: 4

View File

@ -151,11 +151,11 @@ Because I like seeing the numbers.
Language | Files | Blank | Comment | Code
-------------|--------:|---------:|--------:|---------:
TypeScript | 60 | 711 | 30 | 3294
PHP | 18 | 562 | 19 | 1755
HTML | 19 | 137 | 0 | 1193
SASS | 14 | 225 | 12 | 1029
__SUM:__ | __111__ | __1635__ | __61__ | __7271__
TypeScript | 60 | 728 | 30 | 3352
PHP | 18 | 562 | 19 | 1756
HTML | 19 | 138 | 0 | 1223
SASS | 14 | 231 | 12 | 1057
__SUM:__ | __111__ | __1659__ | __61__ | __7388__
Command: `cloc --exclude-dir=vendor --exclude-ext=json src/`

View File

@ -26,7 +26,7 @@ class Columns extends BaseController {
}
$this->apiJson->setSuccess();
$this->apiJson->addData($column);
$this->apiJson->addData(R::exportAll($column));
return $this->jsonResponse($response);
}
@ -108,6 +108,7 @@ class Columns extends BaseController {
$this->apiJson->setSuccess();
$this->apiJson->addAlert('success', 'Column ' .
$update->name . ' updated.');
$this->apiJson->addData(R::exportAll($update));
return $this->jsonResponse($response);
}

View File

@ -2,10 +2,12 @@
<div class="board-nav">
<label *ngIf="boards && boards.length">
Select Board:
{{ strings['boards_selectBoard'] }}:
<select [(ngModel)]="boardNavId"
(change)="goToBoard()">
<option [ngValue]="null">Select Board...</option>
<option [ngValue]="null">
{{ strings['boards_selectBoard'] }}...
</option>
<option *ngFor="let board of boards"
[ngValue]="board.id">
{{ board.name }}
@ -14,11 +16,11 @@
</label>
<div class="right" *ngIf="activeBoard">
<label>
Hide Filtered Items:
{{ strings['boards_hideFiltered'] }}:
<input type="checkbox">
</label>
<label>
User Filter:
{{ strings['boards_userFilter'] }}:
<select [(ngModel)]="userFilter">
<option [ngValue]="null">Any</option>
<option *ngFor="let user of activeBoard.users"
@ -28,7 +30,7 @@
</select>
</label>
<label>
Category Filter:
{{ strings['boards_categoryFilter'] }}:
<select [(ngModel)]="categoryFilter">
<option [ngValue]="null">Any</option>
<option *ngFor="let category of activeBoard.categories"
@ -41,20 +43,21 @@
</div>
<div class="no-boards center" *ngIf="noBoards()">
<h1>No Boards</h1>
<h1>{{ strings['boards_noBoards'] }}</h1>
<p>{{ noBoardsMessage }}</p>
</div>
<div class="no-boards center"
*ngIf="!loading && !activeBoard && !noBoards() && !activeUser.default_board_id">
<h1>No Default Board</h1>
<h1>{{ strings['boards_noDefault'] }}</h1>
<p>
You have not selected a default board. You may select a
default board in your <a href="javascript:" [routerLink]="['/settings']">Settings</a>.
<p>{{ strings['boards_noDefaultMessage'] }}
<a href="javascript:" [routerLink]="['/settings']">
{{ strings['settings'] }}
</a>.
</p>
<p>Until then, select a board from the list above.</p>
<p></p>
</div>
<div class="board" *ngIf="activeBoard">

View File

@ -27,6 +27,7 @@ export class BoardDisplay implements OnInit {
private activeBoard: Board;
private boards: Array<Board>;
private strings: any;
private boardNavId: number;
private userFilter: number;
private categoryFilter: number;
@ -52,6 +53,15 @@ export class BoardDisplay implements OnInit {
this.pageName = 'Boards';
this.loading = true;
stringsService.stringsChanged.subscribe(newStrings => {
this.strings = newStrings;
// Updating the active user updates some display strings.
if (this.activeUser) {
this.updateActiveUser(this.activeUser);
}
});
boardService.getBoards().subscribe((response: ApiResponse) => {
this.updateBoardsList(response.data[1]);
this.loading = false;
@ -151,11 +161,10 @@ export class BoardDisplay implements OnInit {
activeUser.username,
activeUser.board_access);
this.noBoardsMessage = 'You are not assigned to any boards. ' +
'Contact an admin user to be added to a board.';
this.noBoardsMessage = this.strings.boards_noBoardsMessageUser;
if (+activeUser.security_level === 1) {
this.noBoardsMessage = 'Go to Settings to create a board.';
this.noBoardsMessage = this.strings.boards_noBoardsMessageAdmin;
}
}

View File

@ -9,6 +9,7 @@ import 'rxjs/add/operator/catch';
import {
ApiResponse,
Column,
Board,
Task,
User
@ -41,6 +42,12 @@ export class BoardService {
.catch(this.errorHandler);
}
updateColumn(column: Column): Observable<ApiResponse> {
return this.http.post('api/columns/' + column.id, column)
.map(this.toApiResponse)
.catch(this.errorHandler);
}
addTask(task: Task): Observable<ApiResponse> {
return this.http.post('api/tasks', task)
.map(this.toApiResponse)
@ -59,7 +66,6 @@ export class BoardService {
.catch(this.errorHandler);
}
// TODO: Determine when to use this
refreshToken(): void {
this.http.post('api/refresh', {}).subscribe();
}

View File

@ -1,42 +1,57 @@
<h3>
<h3 [class.near-limit]="columnData.hasTaskLimit() &&
columnData.task_limit - columnData.tasks.length === 1"
[class.limit-reached]="columnData.hasTaskLimit() &&
columnData.task_limit - columnData.tasks.length < 1">
<span class="icon icon-minus-squared-alt"
title="Collapse All Tasks"
[title]="strings['boards_collapseAllTasks']"
*ngIf="!collapseTasks"
(click)="toggleTaskCollapse()"></span>
<span class="icon icon-plus-squared-alt"
title="Expand All Tasks"
[title]="strings['boards_expandAllTasks']"
*ngIf="collapseTasks"
(click)="toggleTaskCollapse()"></span>
{{ columnData.name }}
<span class="badge" title="Tasks in Column">
{{ columnData.tasks && columnData.tasks.length || 0 }}
</span>
<span class="icon icon-angle-double-up"
title="Expand Column" (click)="toggleCollapsed()"></span>
<span class="right icon icon-angle-double-down"
title="Collapse Column" (click)="toggleCollapsed()"></span>
<span class="count" *ngIf="columnData.hasTaskLimit()">
{{ columnData.tasks.length + ' / ' + columnData.task_limit }}
</span>
<span class="count-editor" title="Edit Task Limit"
<span class="badge" [title]="strings['boards_tasksInColumn']">
{{ columnData.tasks && columnData.tasks.length || 0 }}
</span>
<span class="icon icon-angle-double-up"
[title]="strings['boards_expandColumn']" (click)="toggleCollapsed()"></span>
<span class="right icon icon-angle-double-down"
[title]="strings['boards_collapseColumn']" (click)="toggleCollapsed()"></span>
<span class="count-editor"
*ngIf="activeUser.isAdmin() || activeUser.isBoardAdmin()">
<i class="icon icon-hashtag"
(click)="showLimitEditor = !showLimitEditor"></i>
[title]="strings['boards_editTaskLimit']"
(click)="beginLimitEdit()"></i>
<div class="limit-editor" *ngIf="showLimitEditor">
<input type="number" min="0" [(ngModel)]="columnData.task_limit">
<input type="number" min="0"
[title]="'0 = ' + strings['boards_noLimit']"
[(ngModel)]="taskLimit">
<i class="icon icon-cancel right"
[title]="strings['boards_limitCancel']"
(click)="cancelLimitChanges()"></i>
<i class="icon icon-floppy primary right"
[title]="strings['boards_limitSave']"
(click)="saveLimitChanges()"></i>
</div>
</span>
</h3>
<div class="quick-add">
<input type="text" placeholder="Quick Add Task - Title Only"
[(ngModel)]="quickAdd.title">
<button class="flat" (click)="quickAddClicked()">
<input type="text" [placeholder]="strings['boards_quickAdd']"
[(ngModel)]="quickAdd.title" (keyup.enter)="quickAddClicked($event)">
<button class="flat"
[title] = "strings['boards_addTask']"
(click)="quickAddClicked($event)">
<i class="icon icon-plus"></i>
</button>
</div>
@ -52,36 +67,44 @@
<tb-context-menu [menu-items]="contextMenuItems"></tb-context-menu>
<tb-modal modal-title="Confirm Task Removal" blocking="true"
<tb-modal modal-title="{{ strings['boards_confirmRemoveTask'] }}" blocking="true"
modal-id="{{ MODAL_CONFIRM_ID + columnData.id }}">
<div class="center">Removing a task cannot be undone.<br>Continue?</div>
<div class="center">
{{ strings['boards_confirmWarning'] }}<br>
{{ strings['boards_confirmContinue'] }}
</div>
<div class="buttons">
<button class="flat"
(click)="removeTask()">Yes</button>
(click)="removeTask()">{{ strings['yes'] }}</button>
<button #defaultAction #focusMe
(click)="modal.close(MODAL_CONFIRM_ID + columnData.id)">No</button>
(click)="modal.close(MODAL_CONFIRM_ID + columnData.id)">
{{ strings['no'] }}
</button>
</div>
</tb-modal>
<tb-modal *ngIf="activeBoard"
modal-title="{{ modalProps.id === 0 ? 'Add' : 'Edit' }} Task"
modal-title="{{ modalProps.id === 0
? strings['boards_addTask']
: strings['boards_editTask'] }}"
modal-id="{{ MODAL_ID + columnData.id }}">
<label>
Title
<input #focusMe type="text" name="title" placeholder="Task Title"
[(ngModel)]="modalProps.title">
{{ strings['boards_taskTitle'] }}
<input #focusMe type="text" name="title"
[placeholder]="strings['boards_taskTitlePlaceholder']"
[(ngModel)]="modalProps.title">
</label>
<label>
Description
{{ strings['boards_taskDescription'] }}
<textarea name="description" rows="5"
placeholder="What needs to get done?"
[placeholder]="strings['boards_taskDescriptionPlaceholder']"
(keyup.enter)="preventEnter($event)"
[(ngModel)]="modalProps.description"></textarea>
</label>
<label>
Assignees
{{ strings['boards_taskAssignees'] }}
<select name="assignees" multiple [(ngModel)]="modalProps.assignees">
<option *ngFor="let user of activeBoard.users"
[ngValue]="user">{{ user.username }}</option>
@ -89,7 +112,7 @@
</label>
<label>
Categories
{{ strings['boards_taskCategories'] }}
<select name="categories" multiple [ngModel]="modalProps.categories"
(ngModelChange)="updateTaskColorByCategory($event)">
<option *ngFor="let category of activeBoard.categories"
@ -99,7 +122,7 @@
<div class="half">
<label>
Column
{{ strings['boards_taskColumn'] }}
<select name="column" [(ngModel)]="modalProps.column_id">
<option *ngFor="let column of activeBoard.columns"
[ngValue]="column.id">{{ column.name }}</option>
@ -107,19 +130,19 @@
</label>
<label>
Color
{{ strings['boards_taskColor'] }}
<input type="color" [(ngModel)]="modalProps.color">
</label>
</div>
<div class="half">
<label>
Date Due
{{ strings['boards_taskDateDue'] }}
<input type="date" [(ngModel)]="modalProps.due_date">
</label>
<label>
Points
{{ strings['boards_taskPoints'] }}
<input type="number" [(ngModel)]="modalProps.points">
</label>
</div>
@ -128,15 +151,15 @@
<button #defaultAction *ngIf="modalProps.id === 0"
(click)="addTask()" [disabled]="saving">
<i class="icon icon-plus"></i>
Add Task
{{ strings['boards_addTask'] }}
</button>
<button #defaultAction *ngIf="modalProps.id !== 0"
(click)="updateTask()" [disabled]="saving">
<i class="icon icon-floppy"></i>
Save Task
{{ strings['boards_saveTask'] }}
</button>
<button class="flat" (click)="modal.close(MODAL_ID + columnData.id)">
Cancel
{{ strings['cancel'] }}
</button>
</div>
</tb-modal>

View File

@ -29,10 +29,11 @@ import { BoardService } from '../board.service';
templateUrl: 'app/board/column/column.component.html'
})
export class ColumnDisplay implements OnInit {
private strings: any;
private templateElement: any;
private collapseTasks: boolean;
private saving: boolean;
private hasTaskLimit: boolean;
private showLimitEditor: boolean;
private activeUser: User;
private activeBoard: Board;
@ -47,6 +48,7 @@ export class ColumnDisplay implements OnInit {
private quickAdd: Task;
private modalProps: Task;
private taskToRemove: number;
private taskLimit: number;
@Input('column') columnData: Column;
@Input('boards') boards: Array<Board>;
@ -61,17 +63,21 @@ export class ColumnDisplay implements OnInit {
this.tasks = [];
this.collapseTasks = false;
this.contextMenuItems = [
new ContextMenuItem('Add Task',
this.getShowModalFunction())
];
this.MODAL_ID = 'add-task-form-';
this.MODAL_CONFIRM_ID = 'task-remove-confirm';
this.quickAdd = new Task();
this.modalProps = new Task();
stringsService.stringsChanged.subscribe(newStrings => {
this.strings = newStrings;
this.contextMenuItems = [
new ContextMenuItem(this.strings.boards_addTask,
this.getShowModalFunction())
];
});
boardService.activeBoardChanged.subscribe((board: Board) => {
this.activeBoard = board;
});
@ -108,6 +114,8 @@ export class ColumnDisplay implements OnInit {
if (isCollapsed) {
this.templateElement.classList.add('collapsed');
}
this.taskLimit = this.columnData.task_limit;
}
toggleCollapsed() {
@ -169,6 +177,8 @@ export class ColumnDisplay implements OnInit {
this.boardService.updateActiveBoard(response.data[2][0]);
this.modal.close(this.MODAL_ID + this.columnData.id);
this.boardService.refreshToken();
});
}
@ -185,6 +195,41 @@ export class ColumnDisplay implements OnInit {
});
}
beginLimitEdit() {
this.taskLimit = this.columnData.task_limit;
this.showLimitEditor = true;
}
cancelLimitChanges() {
this.showLimitEditor = false;
}
saveLimitChanges() {
let originalLimit = this.columnData.task_limit;
this.columnData.task_limit = this.taskLimit;
this.boardService.updateColumn(this.columnData)
.subscribe((response: ApiResponse) => {
response.alerts.forEach(note => this.notes.add(note));
if (response.status !== 'success') {
this.columnData.task_limit = originalLimit;
return;
}
let colData = response.data[1][0];
this.columnData = new Column(colData.id,
colData.name,
colData.position,
colData.board_id,
colData.task_limit,
colData.ownTask);
});
this.showLimitEditor = false;
}
private validateTask(task: Task) {
if (task.title === '') {
this.notes.add(
@ -206,7 +251,9 @@ export class ColumnDisplay implements OnInit {
return () => { this.showModal(taskId); };
}
private quickAddClicked() {
private quickAddClicked(event: any) {
this.preventEnter(event);
if (this.quickAdd.title === '') {
this.showModal();
return;

View File

@ -6,10 +6,13 @@
[style.color]="getTextColor(taskData.color)"
[ngClass]="{ 'icon-minus-squared-alt': !isCollapsed,
'icon-plus-squared-alt': isCollapsed }"
title="{{ isCollapsed ? 'Expand' : 'Collapse' }} Task"
[title]="isCollapsed
? strings['boards_expandTask']
: strings['boards_collapseTask']"
(click)="isCollapsed = !isCollapsed"></span>
{{ taskData.title }}
<span *ngIf="taskData.points > 0" class="badge right" title="Points">
<span *ngIf="taskData.points > 0" class="badge right"
[title]="strings['boards_taskPoints'] ">
{{ taskData.points }}</span>
</h4>
@ -18,25 +21,27 @@
<div class="stats">
<span *ngIf="userOptions.show_assignee">
Assigned To:
{{ strings['boards_taskAssignedTo'] }}:
<span *ngFor="let assignee of taskData.assignees">
{{ assignee.username }}
</span>
<span *ngIf="!taskData.assignees || !taskData.assignees.length">
Unassigned
{{ strings['boards_taskUnassigned'] }}
</span>
</span>
<span class="right">
<span *ngIf="taskData.due_date">
Due: {{ taskData.due_date }}
{{ strings['boards_taskDue'] }}: {{ taskData.due_date }}
</span>
<span *ngIf="taskData.comments.length" class="icon icon-chat-empty"
title="{{ taskData.comments.length }} Comments"></span>
[title]="taskData.comments.length +
strings['boards_taskComments']"></span>
<span *ngIf="taskData.attachments.length" class="icon icon-attach"
title="{{ taskData.attachments.length }} Attachments"></span>
<span *ngFor="let category of taskData.categories"
class="category" title="Category">
[title]="taskData.attachments.length +
strings['boards_taskAttachments']"></span>
<span *ngFor="let category of taskData.categories" class="category"
[title]="strings['boards_taskCategory']">
{{ category.name }}
</span>
</span>

View File

@ -19,7 +19,8 @@ import {
UserOptions,
AuthService,
ModalService,
NotificationsService
NotificationsService,
StringsService
} from '../../shared/index';
import { BoardService } from '../board.service';
@ -28,6 +29,7 @@ import { BoardService } from '../board.service';
templateUrl: 'app/board/task/task.component.html'
})
export class TaskDisplay implements OnInit {
private strings: any;
private userOptions: UserOptions;
private contextMenuItems: Array<ContextMenuItem>;
private selectMenuItem: ContextMenuItem;
@ -55,12 +57,21 @@ export class TaskDisplay implements OnInit {
private sanitizer: DomSanitizer,
private boardService: BoardService,
private modal: ModalService,
private notes: NotificationsService) {
private notes: NotificationsService,
private stringsService: StringsService) {
this.totalTasks = 0;
this.completeTasks = 0;
this.percentComplete = 0;
this.contextMenuItems = [];
stringsService.stringsChanged.subscribe(newStrings => {
this.strings = newStrings;
if (this.taskData) {
this.generateContextMenuItems();
}
});
auth.userChanged.subscribe(() => {
this.userOptions = auth.userOptions;
});
@ -98,7 +109,9 @@ export class TaskDisplay implements OnInit {
}
getPercentTitle() {
return 'Task ' + (this.percentComplete * 100) + '% Complete';
return this.strings.boards_task + ' ' +
(this.percentComplete * 100).toFixed(0) + '% ' +
this.strings.boards_taskComplete;
}
// Expects a color in full HEX with leading #, e.g. #ffffe0
@ -112,7 +125,8 @@ export class TaskDisplay implements OnInit {
}
private getMoveMenuItem() {
let menuText = 'Move to Column: <select id="columnsList' + this.taskData.id + '">';
let menuText = this.strings.boards_moveTask +
': <select id="columnsList' + this.taskData.id + '">';
this.activeBoard.columns.forEach((column: Column) => {
menuText += '<option value="' + column.id + '">' + column.name + '</option>';
@ -161,29 +175,28 @@ export class TaskDisplay implements OnInit {
private generateContextMenuItems() {
this.contextMenuItems = [
new ContextMenuItem('View Task'),
new ContextMenuItem('Edit Task', this.editTask),
new ContextMenuItem('Remove Task', this.removeTask),
new ContextMenuItem(this.strings.boards_viewTask),
new ContextMenuItem(this.strings.boards_editTask, this.editTask),
new ContextMenuItem(this.strings.boards_removeTask, this.removeTask),
new ContextMenuItem('', null, true),
this.getMoveMenuItem(),
new ContextMenuItem('', null, true),
new ContextMenuItem('Add Task', this.addTask)
new ContextMenuItem(this.strings.boards_addTask, this.addTask)
];
if (this.boardsList.length > 1) {
this.contextMenuItems
.splice(3, 0,
new ContextMenuItem('', null, true),
this.getMenuItem('Copy'),
this.getMenuItem('Move'));
this.getMenuItem(this.strings.boards_copyTaskTo),
this.getMenuItem(this.strings.boards_moveTaskTo));
}
}
private getMenuItem(text: string): ContextMenuItem {
let menuText = text + ' to Board: ' +
let menuText = text + ': ' +
'<i class="icon icon-help-circled" ' +
'data-help="The task will be placed in the first ' +
'column of the selected board."></i> ' +
'data-help="' + this.strings.boards_copyMoveHelp + '"></i> ' +
'<select id="boardsList' + text + '">';
this.boardsList.forEach((board: Board) => {

View File

@ -128,6 +128,64 @@
"settings_selectAssignee": "Select Assignee",
"settings_alterByPoints": "Alter color by points",
"settings_noActions": "There are no automatic actions. Contact an admin user to create one.",
"settings_noActionsAdmin": "There are no automatic actions. Use the <strong>Add Action</strong> form below to add one."
"settings_noActionsAdmin": "There are no automatic actions. Use the <strong>Add Action</strong> form below to add one.",
"boards_selectBoard": "Select Board",
"boards_hideFiltered": "Hide filtered items",
"boards_userFilter": "User Filter",
"boards_categoryFilter": "Category Filter",
"boards_noBoards": "No Boards",
"boards_noBoardsMessageUser": "You are not assigned to any boards. Contact an admin user to be added to a board.",
"boards_noBoardsMessageAdmin": "Go to Settings to create a board.",
"boards_noDefault": "No Default Board",
"boards_noDefaultMessage": "You have not selected a default board. You may select a default board in your",
"boards_noDefaultMessage2": "Until then, select a board from the list above.",
"boards_collapseAllTasks": "Collapse All Tasks",
"boards_expandAllTasks": "Expand All Tasks",
"boards_tasksInColumn": "Tasks in Column",
"boards_expandColumn": "Expand Column",
"boards_collapseColumn": "Collapse Column",
"boards_editTaskLimit": "Edit Task Limit",
"boards_noLimit": "no limit",
"boards_limitCancel": "Cancel Changes",
"boards_limitSave": "Save Changes",
"boards_quickAdd": "Quick Add Task - Title Only",
"boards_confirmRemoveTask": "Confirm Task Removal",
"boards_confirmWarning": "Removing a task cannot be undone.",
"boards_confirmContinue": "Continue?",
"boards_addTask": "Add Task",
"boards_editTask": "Edit Task",
"boards_viewTask": "View Task",
"boards_removeTask": "Remove Task",
"boards_moveTask": "Move to Column",
"boards_taskTitle": "Title",
"boards_taskTitlePlaceholder": "Task Title",
"boards_taskDescription": "Description",
"boards_taskDescriptionPlaceholder": "What needs to get done?",
"boards_taskAssignees": "Assignees",
"boards_taskCategories": "Categories",
"boards_taskColumn": "Column",
"boards_taskColor": "Color",
"boards_taskDateDue": "Date Due",
"boards_taskPoints": "Points",
"boards_saveTask": "Save Task",
"boards_copyTaskTo": "Copy to Board",
"boards_moveTaskTo": "Move to Board",
"boards_copyMoveHelp": "The task will be placed in the first column of the selected board.",
"boards_expandTask": "Expand Task",
"boards_collapseTask": "Collapse Task",
"boards_taskAssignedTo": "Assigned To",
"boards_taskUnassigned": "Unassigned",
"boards_taskDue": "Due",
"boards_taskComments": "Comments",
"boards_taskAttachments": "Attachments",
"boards_taskCategory": "Category",
"boards_task": "Task",
"boards_taskComplete": "Complete"
}

View File

@ -8,7 +8,7 @@
"dashboard": "Salpicadero",
"boards": "Tableros",
"settings": "Ajustes",
"settings": "Configuración",
"logout": "Cerrar Sesión",
"settings_userSettings": "Mi Configuración",
@ -128,6 +128,64 @@
"settings_selectAssignee": "Seleccionar Cesionario",
"settings_alterByPoints": "Alterar color por puntos",
"settings_noActions": "No hay acciones automáticas. Póngase en contacto con un usuario administrador para crear uno.",
"settings_noActionsAdmin": "No hay acciones automáticas. Utilice el botón <strong>Agregar Acción</strong> de abajo para agregar uno."
"settings_noActionsAdmin": "No hay acciones automáticas. Utilice el botón <strong>Agregar Acción</strong> de abajo para agregar uno.",
"boards_selectBoard": "Seleccionar el Tablero",
"boards_hideFiltered": "Ocultar los elementos filtrados",
"boards_userFilter": "Filtro de usuario",
"boards_categoryFilter": "Filtro de categoría",
"boards_noBoards": "No Hay Tableros",
"boards_noBoardsMessageUser": "Usted no está asignado a ninguno tablero. Póngase en contacto con un usuario administrador que se añade a un tablero.",
"boards_noBoardsMessageAdmin": "Vaya a Configuración para crear un tablero.",
"boards_noDefault": "Ningún Tablero Predeterminado",
"boards_noDefaultMessage": "No ha seleccionado una tarjeta predeterminada. Puede seleccionar una tarjeta predeterminada en su",
"boards_noDefaultMessage2": "Hasta entonces, seleccione un tablero de la lista anterior.",
"boards_collapseAllTasks": "Contraer Todas las Tareas",
"boards_expandAllTasks": "Expandir Todas las Tareas",
"boards_tasksInColumn": "Tareas en la Columna",
"boards_expandColumn": "Expandir Columna",
"boards_collapseColumn": "Contraer Columna",
"boards_editTaskLimit": "Editar Límite de Tareas",
"boards_noLimit": "sin límite",
"boards_limitCancel": "Cancelar Cambios",
"boards_limitSave": "Guardar Cambios",
"boards_quickAdd": "Tarea de Añadir Rápido - Sólo Título",
"boards_confirmRemoveTask": "Confirmar la Eliminación de Tarea",
"boards_confirmWarning": "No se puede deshacer la eliminación de una tarea.",
"boards_confirmContinue": "¿Continuar?",
"boards_addTask": "Agregar Tarea",
"boards_editTask": "Editar Tarea",
"boards_viewTask": "Ver Tarea",
"boards_removeTask": "Eliminar tarea",
"boards_moveTask": "Mover a la Columna",
"boards_taskTitle": "Título",
"boards_taskTitlePlaceholder": "Tarea Título",
"boards_taskDescription": "Descripción",
"boards_taskDescriptionPlaceholder": "¿Qué se necesita hacer?",
"boards_taskAssignees": "Cesionarios",
"boards_taskCategories": "Categorías",
"boards_taskColumn": "Columna",
"boards_taskColor": "Color",
"boards_taskDateDue": "Fecha de Vencimiento",
"boards_taskPoints": "Puntos",
"boards_saveTask": "Guardar Tarea",
"boards_copyTaskTo": "Copiar a el Tablero",
"boards_moveTaskTo": "Mover a el Tablero",
"boards_copyMoveHelp": "La tarea se colocará en la primera columna de la tabla seleccionada.",
"boards_expandTask": "Expandir Tarea",
"boards_collapseTask": "Contraer Tarea",
"boards_taskAssignedTo": "Asignado a",
"boards_taskUnassigned": "Sin asignar",
"boards_taskDue": "Debido",
"boards_taskComments": "Comentarios",
"boards_taskAttachments": "Archivos Adjuntos",
"boards_taskCategory": "Categoría",
"boards_task": "Tarea",
"boards_taskComplete": "Completar"
}

View File

@ -52,6 +52,26 @@
font-size: 24px;
padding: 5px;
&.near-limit {
box-shadow: 0 2px 2px 0 rgba(255, 150, 0, .4),
0 1px 5px 0 rgba(255, 150, 0, .2),
0 3px 1px -2px rgba(255, 150, 0, .2);
.count {
color: rgb(255, 150, 0);
}
}
&.limit-reached {
box-shadow: 0 2px 2px 0 rgba(255, 20, 0, .4),
0 1px 5px 0 rgba(255, 20, 0, .2),
0 3px 1px -2px rgba(255, 20, 0, .2);
.count {
color: rgb(255, 20, 0);
}
}
span {
cursor: pointer;
}
@ -66,6 +86,28 @@
margin-top: -4px;
}
.limit-editor {
@include shadow-float;
background-color: $white;
border-radius: 3px;
padding: 1em;
position: absolute;
right: 1.5em;
width: 70px;
z-index: 100;
}
.icon-cancel,
.icon-floppy {
margin: 5px;
margin-bottom: 0;
}
.icon-cancel {
color: $color-text;
}
.icon-angle-double-up,
.badge {
display: none;
@ -121,7 +163,6 @@
.icon-minus-squared-alt,
.icon-plus-squared-alt,
.tasks,
.count,
.quick-add {
display: none;
}