WIP
This commit is contained in:
parent
f5fc653fff
commit
0510e1d835
10
src/api/composer.lock
generated
10
src/api/composer.lock
generated
@ -1643,16 +1643,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/yaml",
|
||||
"version": "v3.3.5",
|
||||
"version": "v3.3.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/yaml.git",
|
||||
"reference": "1f93a8d19b8241617f5074a123e282575b821df8"
|
||||
"reference": "ddc23324e6cfe066f3dd34a37ff494fa80b617ed"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/yaml/zipball/1f93a8d19b8241617f5074a123e282575b821df8",
|
||||
"reference": "1f93a8d19b8241617f5074a123e282575b821df8",
|
||||
"url": "https://api.github.com/repos/symfony/yaml/zipball/ddc23324e6cfe066f3dd34a37ff494fa80b617ed",
|
||||
"reference": "ddc23324e6cfe066f3dd34a37ff494fa80b617ed",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1694,7 +1694,7 @@
|
||||
],
|
||||
"description": "Symfony Yaml Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2017-06-15T12:58:50+00:00"
|
||||
"time": "2017-07-23T12:43:26+00:00"
|
||||
},
|
||||
{
|
||||
"name": "webmozart/assert",
|
||||
|
@ -59,6 +59,8 @@ class Tasks extends BaseController {
|
||||
R::store($task);
|
||||
|
||||
$actor = R::load('user', Auth::GetUserId($request));
|
||||
$this->updateTaskOrder($task, $actor);
|
||||
|
||||
$this->dbLogger->logChange($actor->id,
|
||||
$actor->username . ' added task ' . $task->title . '.',
|
||||
'', json_encode($task), 'task', $task->id);
|
||||
@ -168,5 +170,26 @@ class Tasks extends BaseController {
|
||||
|
||||
return $column->board_id;
|
||||
}
|
||||
|
||||
private function updateTaskOrder($task, $user) {
|
||||
$column = R::load('column', $task->column_id);
|
||||
$user_opts = R::load('useroption', $user->user_option_id);
|
||||
|
||||
$index = count($column->xownTaskList);
|
||||
$newTask = $column->xownTaskList[$index];
|
||||
|
||||
if ($user_opts->new_tasks_at_bottom) {
|
||||
$newTask->position = $index;
|
||||
R::store($newTask);
|
||||
return;
|
||||
}
|
||||
|
||||
for ($i = count($column->xownTaskList); $i > 0; --$i) {
|
||||
$updateTask = $column->xownTaskList[$i];
|
||||
$updateTask->position = $i;
|
||||
|
||||
R::store($column);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,6 +64,7 @@
|
||||
<tb-column class="column"
|
||||
*ngFor="let column of activeBoard.columns"
|
||||
[column]="column"
|
||||
[boards]="boards"></tb-column>
|
||||
[boards]="boards"
|
||||
(on-update-boards)="updateBoards()"></tb-column>
|
||||
</div>
|
||||
|
||||
|
@ -50,7 +50,6 @@ export class BoardDisplay implements OnInit {
|
||||
this.userFilter = null;
|
||||
this.categoryFilter = null;
|
||||
|
||||
this.pageName = 'Boards';
|
||||
this.loading = true;
|
||||
|
||||
stringsService.stringsChanged.subscribe(newStrings => {
|
||||
@ -62,10 +61,8 @@ export class BoardDisplay implements OnInit {
|
||||
}
|
||||
});
|
||||
|
||||
boardService.getBoards().subscribe((response: ApiResponse) => {
|
||||
this.updateBoardsList(response.data[1]);
|
||||
this.loading = false;
|
||||
});
|
||||
this.pageName = this.strings.boards;
|
||||
this.updateBoards();
|
||||
|
||||
boardService.activeBoardChanged.subscribe((board: Board) => {
|
||||
if (!board) {
|
||||
@ -107,6 +104,14 @@ export class BoardDisplay implements OnInit {
|
||||
this.router.navigate(['/boards/' + this.boardNavId]);
|
||||
}
|
||||
|
||||
updateBoards() {
|
||||
this.boardService.getBoards().subscribe((response: ApiResponse) => {
|
||||
this.boards = [];
|
||||
this.updateBoardsList(response.data[1]);
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
private updateBoardsList(boards: Array<any>): void {
|
||||
let activeBoards: Array<Board> = [];
|
||||
|
||||
|
@ -27,7 +27,7 @@
|
||||
[title]="strings['boards_collapseColumn']" (click)="toggleCollapsed()"></span>
|
||||
|
||||
<span class="count-editor"
|
||||
*ngIf="activeUser.isAdmin() || activeUser.isBoardAdmin()">
|
||||
*ngIf="activeUser.isAnyAdmin()">
|
||||
<i class="icon icon-hashtag"
|
||||
[title]="strings['boards_editTaskLimit']"
|
||||
(click)="beginLimitEdit()"></i>
|
||||
@ -44,6 +44,21 @@
|
||||
(click)="saveLimitChanges()"></i>
|
||||
</div>
|
||||
</span>
|
||||
<span class="sort-by">
|
||||
{{ strings['sortBy'] }}:
|
||||
<select [(ngModel)]="sortOption"
|
||||
(change)="sortTasks()">
|
||||
<option value="pos">
|
||||
{{ strings['boards_sortByPosition'] }}
|
||||
</option>
|
||||
<option value="due">
|
||||
{{ strings['boards_sortByDueDate'] }}
|
||||
</option>
|
||||
<option value="pnt">
|
||||
{{ strings['boards_sortByPoints'] }}
|
||||
</option>
|
||||
</select>
|
||||
</span>
|
||||
</h3>
|
||||
|
||||
<div class="quick-add">
|
||||
@ -62,6 +77,7 @@
|
||||
[add-task]="getShowModalFunction()"
|
||||
[edit-task]="getShowModalFunction(task.id)"
|
||||
[remove-task]="getRemoveTaskFunction(task.id)"
|
||||
(on-update-boards)="callBoardUpdate();"
|
||||
[collapse]="collapseTasks"></tb-task>
|
||||
</div>
|
||||
|
||||
@ -75,7 +91,7 @@
|
||||
</div>
|
||||
<div class="buttons">
|
||||
<button class="flat"
|
||||
(click)="removeTask()">{{ strings['yes'] }}</button>
|
||||
(click)="modal.close(MODAL_CONFIRM_ID + columnData.id);removeTask()">{{ strings['yes'] }}</button>
|
||||
<button #defaultAction #focusMe
|
||||
(click)="modal.close(MODAL_CONFIRM_ID + columnData.id)">
|
||||
{{ strings['no'] }}
|
||||
|
@ -1,8 +1,10 @@
|
||||
import {
|
||||
Component,
|
||||
Input,
|
||||
ElementRef,
|
||||
OnInit
|
||||
EventEmitter,
|
||||
Input,
|
||||
OnInit,
|
||||
Output
|
||||
} from '@angular/core';
|
||||
|
||||
import {
|
||||
@ -41,6 +43,7 @@ export class ColumnDisplay implements OnInit {
|
||||
private tasks: Array<Task>;
|
||||
|
||||
private contextMenuItems: Array<ContextMenuItem>;
|
||||
private sortOption: string;
|
||||
|
||||
private MODAL_ID: string;
|
||||
private MODAL_CONFIRM_ID: string;
|
||||
@ -53,6 +56,8 @@ export class ColumnDisplay implements OnInit {
|
||||
@Input('column') columnData: Column;
|
||||
@Input('boards') boards: Array<Board>;
|
||||
|
||||
@Output('on-update-boards') onUpdateBoards: EventEmitter<any> = new EventEmitter<any>();
|
||||
|
||||
constructor(private elRef: ElementRef,
|
||||
private auth: AuthService,
|
||||
private notes: NotificationsService,
|
||||
@ -62,6 +67,7 @@ export class ColumnDisplay implements OnInit {
|
||||
this.templateElement = elRef.nativeElement;
|
||||
this.tasks = [];
|
||||
this.collapseTasks = false;
|
||||
this.sortOption = 'pos';
|
||||
|
||||
this.MODAL_ID = 'add-task-form-';
|
||||
this.MODAL_CONFIRM_ID = 'task-remove-confirm';
|
||||
@ -118,6 +124,27 @@ export class ColumnDisplay implements OnInit {
|
||||
this.taskLimit = this.columnData.task_limit;
|
||||
}
|
||||
|
||||
sortTasks() {
|
||||
switch (this.sortOption) {
|
||||
case 'pos':
|
||||
this.columnData.tasks.sort((a, b) => {
|
||||
return b.position - a.position;
|
||||
});
|
||||
break;
|
||||
case 'due':
|
||||
this.columnData.tasks.sort((a, b) => {
|
||||
return new Date(a.due_date).getTime() -
|
||||
new Date(b.due_date).getTime();
|
||||
});
|
||||
break;
|
||||
case 'pnt':
|
||||
this.columnData.tasks.sort((a, b) => {
|
||||
return b.points - a.points;
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
toggleCollapsed() {
|
||||
this.templateElement.classList.toggle('collapsed');
|
||||
|
||||
@ -163,6 +190,7 @@ export class ColumnDisplay implements OnInit {
|
||||
});
|
||||
|
||||
this.boardService.updateActiveBoard(boardData);
|
||||
this.boardService.refreshToken();
|
||||
});
|
||||
}
|
||||
|
||||
@ -192,6 +220,7 @@ export class ColumnDisplay implements OnInit {
|
||||
}
|
||||
|
||||
this.boardService.updateActiveBoard(response.data[1][0]);
|
||||
this.boardService.refreshToken();
|
||||
});
|
||||
}
|
||||
|
||||
@ -240,6 +269,10 @@ export class ColumnDisplay implements OnInit {
|
||||
return true;
|
||||
}
|
||||
|
||||
private callBoardUpdate() {
|
||||
this.onUpdateBoards.emit();
|
||||
}
|
||||
|
||||
private getRemoveTaskFunction(taskId: number): Function {
|
||||
return () => {
|
||||
this.taskToRemove = taskId;
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
<div class="description" *ngIf="!isCollapsed"
|
||||
[innerHTML]="getTaskDescription()"></div>
|
||||
<pre>{{ taskData.position | json }}</pre>
|
||||
|
||||
<div class="stats">
|
||||
<span *ngIf="userOptions.show_assignee">
|
||||
|
@ -1,7 +1,9 @@
|
||||
import {
|
||||
Component,
|
||||
EventEmitter,
|
||||
Input,
|
||||
OnInit
|
||||
OnInit,
|
||||
Output
|
||||
} from '@angular/core';
|
||||
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
|
||||
|
||||
@ -47,6 +49,8 @@ export class TaskDisplay implements OnInit {
|
||||
@Input('remove-task') removeTask: Function;
|
||||
@Input('collapse') isCollapsed: boolean;
|
||||
|
||||
@Output('on-update-boards') onUpdateBoards: EventEmitter<any>;
|
||||
|
||||
@Input('boards')
|
||||
set boards(boards: Array<Board>) {
|
||||
this.boardsList = boards;
|
||||
@ -59,6 +63,7 @@ export class TaskDisplay implements OnInit {
|
||||
private modal: ModalService,
|
||||
private notes: NotificationsService,
|
||||
private stringsService: StringsService) {
|
||||
this.onUpdateBoards = new EventEmitter<any>();
|
||||
this.totalTasks = 0;
|
||||
this.completeTasks = 0;
|
||||
this.percentComplete = 0;
|
||||
@ -97,7 +102,7 @@ export class TaskDisplay implements OnInit {
|
||||
|
||||
getTaskDescription(): SafeHtml {
|
||||
let html = this.sanitizer.bypassSecurityTrustHtml(
|
||||
marked(this.taskData.description));
|
||||
marked(this.taskData.description, this.markedCallback));
|
||||
|
||||
return html;
|
||||
}
|
||||
@ -124,6 +129,36 @@ export class TaskDisplay implements OnInit {
|
||||
return yiq >= 140 ? '#333333' : '#efefef';
|
||||
}
|
||||
|
||||
// Needs anonymous function for proper `this` context.
|
||||
private markedCallback = (error: any, text: string) => {
|
||||
this.activeBoard.issue_trackers.forEach(tracker => {
|
||||
let re = new RegExp(tracker.regex, 'ig');
|
||||
let replacements = new Array<any>();
|
||||
let result = re.exec(text);
|
||||
|
||||
while (result !== null) {
|
||||
let link = '<a href="' +
|
||||
tracker.url.replace(/%BUGID%/g, result[1]) +
|
||||
'" target="tb_external" rel="noreferrer">' +
|
||||
result[0] + '</a>';
|
||||
|
||||
// text = text.replace(result[0], link);
|
||||
replacements.push({
|
||||
str: result[0],
|
||||
link
|
||||
});
|
||||
result = re.exec(text);
|
||||
}
|
||||
|
||||
for (let i = replacements.length - 1; i >= 0; --i) {
|
||||
text = text.replace(replacements[i].str,
|
||||
replacements[i].link);
|
||||
}
|
||||
});
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
private getMoveMenuItem() {
|
||||
let menuText = this.strings.boards_moveTask +
|
||||
': <select id="columnsList' + this.taskData.id + '">';
|
||||
@ -148,11 +183,9 @@ export class TaskDisplay implements OnInit {
|
||||
.subscribe((response: ApiResponse) => {
|
||||
response.alerts.forEach(note => this.notes.add(note));
|
||||
|
||||
if (response.status !== 'success') {
|
||||
return;
|
||||
if (response.status === 'success') {
|
||||
this.boardService.updateActiveBoard(response.data[2][0]);
|
||||
}
|
||||
|
||||
this.boardService.updateActiveBoard(response.data[2][0]);
|
||||
});
|
||||
}
|
||||
|
||||
@ -184,7 +217,7 @@ export class TaskDisplay implements OnInit {
|
||||
new ContextMenuItem(this.strings.boards_addTask, this.addTask)
|
||||
];
|
||||
|
||||
if (this.boardsList.length > 1) {
|
||||
if (this.boardsList && this.boardsList.length > 1) {
|
||||
this.contextMenuItems
|
||||
.splice(3, 0,
|
||||
new ContextMenuItem('', null, true),
|
||||
@ -197,7 +230,7 @@ export class TaskDisplay implements OnInit {
|
||||
let menuText = text + ': ' +
|
||||
'<i class="icon icon-help-circled" ' +
|
||||
'data-help="' + this.strings.boards_copyMoveHelp + '"></i> ' +
|
||||
'<select id="boardsList' + text + '">';
|
||||
'<select id="boardsList' + text.split(' ')[0] + '">';
|
||||
|
||||
this.boardsList.forEach((board: Board) => {
|
||||
if (board.name !== this.activeBoard.name) {
|
||||
@ -207,7 +240,81 @@ export class TaskDisplay implements OnInit {
|
||||
|
||||
menuText += '</select>';
|
||||
|
||||
return new ContextMenuItem(menuText, null, false, false);
|
||||
let action = () => {
|
||||
if (text === this.strings.boards_copyTaskTo) {
|
||||
this.copyTaskToBoard();
|
||||
return;
|
||||
}
|
||||
|
||||
this.moveTaskToBoard();
|
||||
};
|
||||
|
||||
return new ContextMenuItem(menuText, action, false, false);
|
||||
}
|
||||
|
||||
private copyTaskToBoard() {
|
||||
let select = document.getElementById('boardsList' +
|
||||
this.strings.boards_copyTaskTo.split(' ')[0]) as HTMLSelectElement;
|
||||
|
||||
let newBoardId = +select[select.selectedIndex].value;
|
||||
let taskData = { ...this.taskData };
|
||||
let boardData: Board;
|
||||
|
||||
this.boardsList.forEach(board => {
|
||||
if (board.id === newBoardId) {
|
||||
taskData.column_id = board.columns[0].id;
|
||||
boardData = board;
|
||||
}
|
||||
});
|
||||
|
||||
this.boardService.addTask(taskData)
|
||||
.subscribe((response: ApiResponse) => {
|
||||
if (response.status === 'success') {
|
||||
this.notes.add(
|
||||
new Notification('success',
|
||||
this.strings.boards_task +
|
||||
' ' + taskData.title + ' ' +
|
||||
this.strings.boards_taskCopied +
|
||||
' ' + boardData.name));
|
||||
this.onUpdateBoards.emit();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
response.alerts.forEach(note => this.notes.add(note));
|
||||
});
|
||||
}
|
||||
|
||||
private moveTaskToBoard() {
|
||||
let select = document.getElementById('boardsList' +
|
||||
this.strings.boards_moveTaskTo.split(' ')[0]) as HTMLSelectElement;
|
||||
|
||||
let newBoardId = +select[select.selectedIndex].value;
|
||||
let boardData: Board;
|
||||
|
||||
this.boardsList.forEach(board => {
|
||||
if (board.id === newBoardId) {
|
||||
this.taskData.column_id = board.columns[0].id;
|
||||
boardData = board;
|
||||
}
|
||||
});
|
||||
|
||||
this.boardService.updateTask(this.taskData)
|
||||
.subscribe((response: ApiResponse) => {
|
||||
if (response.status === 'success') {
|
||||
this.notes.add(
|
||||
new Notification('success',
|
||||
this.strings.boards_task +
|
||||
' ' + this.taskData.title + ' ' +
|
||||
this.strings.boards_taskMoved +
|
||||
' ' + boardData.name));
|
||||
this.onUpdateBoards.emit();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
response.alerts.forEach(note => this.notes.add(note));
|
||||
});
|
||||
}
|
||||
|
||||
private initMarked() {
|
||||
@ -240,7 +347,7 @@ export class TaskDisplay implements OnInit {
|
||||
out += ' title="' + title + '"';
|
||||
}
|
||||
|
||||
out += ' target="tb_external">' + text + '</a>';
|
||||
out += ' target="tb_external" rel="noreferrer">' + text + '</a>';
|
||||
|
||||
return out;
|
||||
};
|
||||
|
@ -28,7 +28,7 @@
|
||||
</label>
|
||||
|
||||
<label class="inline right">
|
||||
{{ strings['settings_sortBy'] }}:
|
||||
{{ strings['sortBy'] }}:
|
||||
<select class="autosize" [(ngModel)]="sortFilter"
|
||||
(change)="filterBoards()">
|
||||
<option value="name-asc">{{ strings['settings_name'] }} (A-Z)</option>
|
||||
|
@ -3,11 +3,10 @@
|
||||
|
||||
<div class="menu-item" *ngFor="let item of menuItems"
|
||||
[ngClass]="{ 'no-highlight': item.isSeparator || !item.canHighlight }"
|
||||
(click)="callAction(item.action)">
|
||||
(click)="callAction($event, item.action)">
|
||||
<hr *ngIf="item.isSeparator">
|
||||
|
||||
<div *ngIf="!item.isSeparator"[innerHTML]="getText(item)"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -33,10 +33,15 @@ export class ContextMenu {
|
||||
return this.sanitizer.bypassSecurityTrustHtml(item.text);
|
||||
}
|
||||
|
||||
callAction(action: Function) {
|
||||
callAction(event: MouseEvent, action: Function) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
if (action) {
|
||||
action();
|
||||
}
|
||||
|
||||
this.menuService.closeAllMenus();
|
||||
}
|
||||
|
||||
private eventHandler(event: MouseEvent) {
|
||||
|
@ -9,7 +9,7 @@ export class ContextMenuService {
|
||||
constructor() {
|
||||
this.menus = [];
|
||||
|
||||
document.addEventListener('click', () => {
|
||||
document.addEventListener('click', event => {
|
||||
this.closeAllMenus();
|
||||
});
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
"no": "No",
|
||||
"save": "Save",
|
||||
"cancel": "Cancel",
|
||||
"sortBy": "Sort By",
|
||||
|
||||
"dashboard": "Dashboard",
|
||||
"boards": "Boards",
|
||||
@ -65,7 +66,6 @@
|
||||
"settings_active": "Active",
|
||||
"settings_inactive": "Inactive",
|
||||
"settings_anyUser": "Any User",
|
||||
"settings_sortBy": "Sort By",
|
||||
"settings_creationNew": "Creation (New First)",
|
||||
"settings_creationOld": "Creation (Old First)",
|
||||
"settings_name": "Name",
|
||||
@ -86,7 +86,7 @@
|
||||
"settings_defaultTaskColor": "Default Task Color",
|
||||
"settings_addCategory": "Add Category",
|
||||
"settings_issueTrackers": "Issue Trackers",
|
||||
"settings_issueTrackersHelp": "Example URL: https://github.com/kiswa/TaskBoard/issues/%BUGID\\1% Example RegExp: (?:Issue)?#(\\d+)",
|
||||
"settings_issueTrackersHelp": "Example URL: https://github.com/kiswa/TaskBoard/issues/%BUGID% Example RegExp: (?:Issue)?#(\\d+)",
|
||||
"settings_issueTrakcerUrl": "Issue Tracker URL - use %BUGID% as placeholder",
|
||||
"settings_issueTrackerRegExp": "BUGID RegExp",
|
||||
"settings_addIssueTracker": "Add Issue Tracker",
|
||||
@ -186,6 +186,13 @@
|
||||
"boards_taskCategory": "Category",
|
||||
|
||||
"boards_task": "Task",
|
||||
"boards_taskComplete": "Complete"
|
||||
"boards_taskComplete": "Complete",
|
||||
"boards_taskCopied": "copied to board",
|
||||
"boards_taskMoved": "moved to board",
|
||||
|
||||
"boards_sortByPosition": "Position",
|
||||
"boards_sortByDueDate": "Due Date",
|
||||
"boards_sortByLastModified": "Last Modifed",
|
||||
"boards_sortByPoints": "Points"
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
"no": "No",
|
||||
"save": "Guardar",
|
||||
"cancel": "Cancelar",
|
||||
"sortBy": "Ordenar por",
|
||||
|
||||
"dashboard": "Salpicadero",
|
||||
"boards": "Tableros",
|
||||
@ -65,7 +66,6 @@
|
||||
"settings_active": "Activo",
|
||||
"settings_inactive": "Inactiva",
|
||||
"settings_anyUser": "Cualquier Usuario",
|
||||
"settings_sortBy": "Ordenar por",
|
||||
"settings_creationNew": "Creación (Nuevo Primero)",
|
||||
"settings_creationOld": "Creación (Viejo Primero)",
|
||||
"settings_name": "Nombre",
|
||||
@ -86,7 +86,7 @@
|
||||
"settings_defaultTaskColor": "Color de Tarea Predeterminado",
|
||||
"settings_addCategory": "Agregar Categoría",
|
||||
"settings_issueTrackers": "Seguimiento de Incidencias",
|
||||
"settings_issueTrackersHelp": "Ejemplo URL: https://github.com/kiswa/TaskBoard/issues/%BUGID\\1% Ejemplo RegExp: (?:Issue)?#(\\d+)",
|
||||
"settings_issueTrackersHelp": "Ejemplo URL: https://github.com/kiswa/TaskBoard/issues/%BUGID% Ejemplo RegExp: (?:Issue)?#(\\d+)",
|
||||
"settings_issueTrakcerUrl": "URL de Seguimiento de Incidencia: Utilice %BUGID% como marcador de posición",
|
||||
"settings_issueTrackerRegExp": "BUGID RegExp",
|
||||
"settings_addIssueTracker": "Agregar Seguimiento de Incidencia",
|
||||
@ -186,6 +186,13 @@
|
||||
"boards_taskCategory": "Categoría",
|
||||
|
||||
"boards_task": "Tarea",
|
||||
"boards_taskComplete": "Completar"
|
||||
"boards_taskComplete": "Completo",
|
||||
"boards_taskCopied": "copiado a tablero",
|
||||
"boards_taskMoved": "movido a tablero",
|
||||
|
||||
"boards_sortByPosition": "Posición",
|
||||
"boards_sortByDueDate": "Fecha de Vencimiento",
|
||||
"boards_sortByLastModified": "Última Modificación",
|
||||
"boards_sortByPoints": "Puntos"
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,9 @@
|
||||
@include clearfix();
|
||||
|
||||
background-color: #fff;
|
||||
display: flex;
|
||||
flex: 1 0 300px;
|
||||
flex-direction: column;
|
||||
height: calc(100% - 7px);
|
||||
margin-left: 7px;
|
||||
overflow: auto;
|
||||
@ -98,6 +100,18 @@
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.sort-by {
|
||||
cursor: default;
|
||||
float: right;
|
||||
font-size: .6em;
|
||||
}
|
||||
|
||||
select {
|
||||
height: 1.7em;
|
||||
padding: 0;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.icon-cancel,
|
||||
.icon-floppy {
|
||||
margin: 5px;
|
||||
@ -139,11 +153,12 @@
|
||||
|
||||
&.collapsed {
|
||||
background-color: $color-heading-bg;
|
||||
display: block;
|
||||
flex: 0 0 35px;
|
||||
overflow: hidden;
|
||||
|
||||
h3 {
|
||||
border: 0;
|
||||
overflow: unset;
|
||||
transform: rotate(90deg)
|
||||
translateX(-35px)
|
||||
translateY(5px);
|
||||
@ -163,6 +178,7 @@
|
||||
.icon-minus-squared-alt,
|
||||
.icon-plus-squared-alt,
|
||||
.tasks,
|
||||
.sort-by,
|
||||
.quick-add {
|
||||
display: none;
|
||||
}
|
||||
@ -174,14 +190,9 @@
|
||||
}
|
||||
|
||||
.tasks {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
overflow-y: auto;
|
||||
padding: 7px;
|
||||
padding-top: 0;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 5.2em;
|
||||
|
||||
div:last-of-type {
|
||||
margin-bottom: 0;
|
||||
@ -196,6 +207,20 @@
|
||||
.task {
|
||||
@include shadow-low();
|
||||
|
||||
a:link,
|
||||
a:visited {
|
||||
background-image: none;
|
||||
color: inherit;
|
||||
font-weight: bold;
|
||||
text-decoration: underline;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
a:hover,
|
||||
a:active {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
h4 {
|
||||
border-bottom: 1px solid lighten($color-border, 25%);
|
||||
cursor: move;
|
||||
|
@ -92,6 +92,27 @@ class TasksTest extends PHPUnit_Framework_TestCase {
|
||||
$this->assertEquals('success', $actual->status);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group single
|
||||
*/
|
||||
public function testAddTaskTop() {
|
||||
$this->createTask();
|
||||
$data = $this->getTaskData();
|
||||
|
||||
$user = R::load('user', 1);
|
||||
$opts = R::load('useroption', $user->user_option_id);
|
||||
|
||||
$opts->new_tasks_at_bottom = false;
|
||||
R::store($opts);
|
||||
|
||||
$request = new RequestMock();
|
||||
$request->header = [DataMock::GetJwt()];
|
||||
$request->payload = $data;
|
||||
|
||||
$actual = $this->tasks->addTask($request, new ResponseMock(), null);
|
||||
$this->assertEquals('success', $actual->status);
|
||||
}
|
||||
|
||||
public function testAddTaskUnprivileged() {
|
||||
DataMock::CreateUnprivilegedUser();
|
||||
|
||||
|
Reference in New Issue
Block a user