Formatting and minor refactoring

This commit is contained in:
Matthew Ross 2020-05-06 07:38:10 -04:00
parent e4b32cd7ad
commit aea06f94af
7 changed files with 298 additions and 249 deletions

View File

@ -3,14 +3,13 @@
<div class="board-nav">
<label *ngIf="boards && boards.length">
{{ strings['boards_selectBoard'] }}:
<select [(ngModel)]="boardNavId"
(change)="goToBoard()">
<select [(ngModel)]="boardNavId" (change)="goToBoard()">
<option [ngValue]="null">
{{ strings['boards_selectBoard'] }}...
</option>
<option *ngFor="let board of boards"
[ngValue]="board.id">
<option *ngFor="let board of boards" [ngValue]="board.id">
{{ board.name }}
</option>
</select>
@ -19,33 +18,33 @@
<div class="right" *ngIf="activeBoard">
<label>
{{ strings['boards_hideFiltered'] }}:
<input type="checkbox" [(ngModel)]="hideFiltered"
(change)="toggleFiltered()">
(change)="toggleFiltered()">
</label>
<label>
{{ strings['boards_userFilter'] }}:
<select [(ngModel)]="userFilter"
(change)="filterTasks()">
<select [(ngModel)]="userFilter" (change)="filterTasks()">
<option [ngValue]="null">
{{ strings['boards_filterByAny'] }}
</option>
<option [ngValue]="-1">
{{ strings['boards_filterByUnassigned'] }}
{{ strings['boards_filterByUnassigned'] }}
</option>
<option *ngFor="let user of activeBoard.users"
[ngValue]="user.id">
{{ user.username }}
<option *ngFor="let user of activeBoard.users" [ngValue]="user.id">
{{ user.username }}
</option>
</select>
</label>
<label>
{{ strings['boards_categoryFilter'] }}:
<select [(ngModel)]="categoryFilter"
(change)="filterTasks()">
<select [(ngModel)]="categoryFilter" (change)="filterTasks()">
<option [ngValue]="null">
{{ strings['boards_filterByAny'] }}
</option>
@ -55,7 +54,7 @@
</option>
<option *ngFor="let category of activeBoard.categories"
[ngValue]="category.id">
[ngValue]="category.id">
{{ category.name }}
</option>
</select>
@ -72,7 +71,7 @@
<div class="no-boards center"
*ngIf="!loading && !activeBoard && this.boards.length > 0 &&
!activeUser.default_board_id">
!activeUser.default_board_id">
<h1>{{ strings['boards_noDefault'] }}</h1>
<p>{{ strings['boards_noDefaultMessage'] }}
@ -85,10 +84,8 @@
</div>
<div class="board" cdkDropListGroup *ngIf="activeBoard">
<tb-column class="column" [id]="column.id"
*ngFor="let column of activeBoard.columns"
[column]="column"
[boards]="boards"
(on-update-boards)="updateBoards()"></tb-column>
<tb-column class="column" [id]="column.id" [column]="column"
*ngFor="let column of activeBoard.columns"
(on-update-boards)="updateBoards()"></tb-column>
</div>

View File

@ -137,41 +137,24 @@ export class BoardDisplayComponent implements OnInit, OnDestroy {
task.filtered = false;
if (this.userFilter) {
let found = false;
let found = (this.userFilter === -1 && task.assignees.length === 0);
if (this.userFilter === -1 &&
task.assignees.length === 0) {
if (task.assignees.some(user => user.id === this.userFilter)) {
found = true;
}
task.assignees.forEach(user => {
if (user.id === this.userFilter) {
found = true;
}
});
if (!found) {
task.filtered = true;
}
task.filtered = !found;
}
if (this.categoryFilter) {
let found = false;
let found = (this.categoryFilter === -1 &&
task.categories.length === 0);
if (this.categoryFilter === -1 &&
task.categories.length === 0) {
if (task.categories.some(cat => cat.id === this.categoryFilter)) {
found = true;
}
task.categories.forEach(cat => {
if (cat.id === this.categoryFilter) {
found = true;
}
});
if (!found) {
task.filtered = true;
}
task.filtered = !found;
}
});
});
@ -224,13 +207,15 @@ export class BoardDisplayComponent implements OnInit, OnDestroy {
return;
}
this.boards.forEach(board => {
if (board.id === this.boardNavId) {
this.activeBoard = board;
this.boardService.updateActiveBoard(board);
this.pageName = board.name;
}
});
const board = this.boards.find(b => (b.id === this.boardNavId));
if (!board) {
return;
}
this.activeBoard = board;
this.boardService.updateActiveBoard(board);
this.pageName = board.name;
}
private updateActiveUser(activeUser: User) {

View File

@ -50,7 +50,11 @@ export class BoardService {
return retVal;
}
updateActiveBoard(board: Board): void {
updateActiveBoard(board: any): void {
if (!board) {
return;
}
const newBoard = this.convertBoardData(board);
this.activeBoard.next(newBoard);
}
@ -58,7 +62,7 @@ export class BoardService {
getBoards(): Observable<ApiResponse> {
return this.http.get('api/boards')
.pipe(
map((response: ApiResponse) => response),
map((response: ApiResponse) => response),
catchError((err) => of(err.error as ApiResponse))
);
}
@ -66,7 +70,7 @@ export class BoardService {
toggleCollapsed(userId: number, columnId: number): Observable<ApiResponse> {
return this.http.post('api/users/' + userId + '/cols', { id: columnId })
.pipe(
map((response: ApiResponse) => response),
map((response: ApiResponse) => response),
catchError((err) => of(err.error as ApiResponse))
);
}
@ -74,7 +78,7 @@ export class BoardService {
updateBoard(board: Board): Observable<ApiResponse> {
return this.http.post('api/boards/' + board.id, board)
.pipe(
map((response: ApiResponse) => response),
map((response: ApiResponse) => response),
catchError((err) => of(err.error as ApiResponse))
);
}
@ -82,7 +86,7 @@ export class BoardService {
updateColumn(column: Column): Observable<ApiResponse> {
return this.http.post('api/columns/' + column.id, column)
.pipe(
map((response: ApiResponse) => response),
map((response: ApiResponse) => response),
catchError((err) => of(err.error as ApiResponse))
);
}
@ -90,7 +94,7 @@ export class BoardService {
addTask(task: Task): Observable<ApiResponse> {
return this.http.post('api/tasks', task)
.pipe(
map((response: ApiResponse) => response),
map((response: ApiResponse) => response),
catchError((err) => of(err.error as ApiResponse))
);
}
@ -98,7 +102,7 @@ export class BoardService {
updateTask(task: Task): Observable<ApiResponse> {
return this.http.post('api/tasks/' + task.id, task)
.pipe(
map((response: ApiResponse) => response),
map((response: ApiResponse) => response),
catchError((err) => of(err.error as ApiResponse))
);
}
@ -106,7 +110,7 @@ export class BoardService {
removeTask(taskId: number): Observable<ApiResponse> {
return this.http.delete('api/tasks/' + taskId)
.pipe(
map((response: ApiResponse) => response),
map((response: ApiResponse) => response),
catchError((err) => of(err.error as ApiResponse))
);
}
@ -114,7 +118,7 @@ export class BoardService {
getTaskActivity(taskId: number): Observable<ApiResponse> {
return this.http.get('api/activity/task/' + taskId)
.pipe(
map((response: ApiResponse) => response),
map((response: ApiResponse) => response),
catchError((err) => of(err.error as ApiResponse))
);
}
@ -122,7 +126,7 @@ export class BoardService {
updateComment(comment: Comment): Observable<ApiResponse> {
return this.http.post('api/comments/' + comment.id, comment)
.pipe(
map((response: ApiResponse) => response),
map((response: ApiResponse) => response),
catchError((err) => of(err.error as ApiResponse))
);
}
@ -130,7 +134,7 @@ export class BoardService {
removeComment(commentId: number): Observable<ApiResponse> {
return this.http.delete('api/comments/' + commentId)
.pipe(
map((response: ApiResponse) => response),
map((response: ApiResponse) => response),
catchError((err) => of(err.error as ApiResponse))
);
}
@ -139,7 +143,7 @@ export class BoardService {
uploadAttachment(attachment: Attachment): Observable<ApiResponse> {
return this.http.post('api/attachments', attachment)
.pipe(
map((response: ApiResponse) => response),
map((response: ApiResponse) => response),
catchError((err) => of(err.error as ApiResponse))
);
}
@ -147,7 +151,7 @@ export class BoardService {
removeAttachment(id: number): Observable<ApiResponse> {
return this.http.delete('api/attachments/' + id)
.pipe(
map((response: ApiResponse) => response),
map((response: ApiResponse) => response),
catchError((err) => of(err.error as ApiResponse))
)
}

View File

@ -1,15 +1,15 @@
<h3 [class.near-limit]="columnData && columnData.hasTaskLimit() &&
columnData.task_limit - columnData.tasks.length === 0"
[class.limit-reached]="columnData && columnData.hasTaskLimit() &&
columnData.task_limit - columnData.tasks.length < 0">
columnData.task_limit - columnData.tasks.length === 0"
[class.limit-reached]="columnData && columnData.hasTaskLimit() &&
columnData.task_limit - columnData.tasks.length < 0">
<span class="icon icon-minus-squared-alt"
[title]="strings['boards_collapseAllTasks']"
*ngIf="!collapseTasks"
(click)="toggleTaskCollapse()"></span>
[title]="strings['boards_collapseAllTasks']"
*ngIf="!collapseTasks" (click)="toggleTaskCollapse()"></span>
<span class="icon icon-plus-squared-alt"
[title]="strings['boards_expandAllTasks']"
*ngIf="collapseTasks"
(click)="toggleTaskCollapse()"></span>
[title]="strings['boards_expandAllTasks']"
*ngIf="collapseTasks" (click)="toggleTaskCollapse()"></span>
{{ columnData ? columnData.name : '' }}
@ -22,41 +22,43 @@
</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>
[title]="strings['boards_expandColumn']"
(click)="toggleCollapsed()"></span>
<span class="count-editor"
*ngIf="activeUser && activeUser.isAnyAdmin()">
<i class="icon icon-hashtag"
[title]="strings['boards_editTaskLimit']"
(click)="beginLimitEdit()"></i>
<span class="right icon icon-angle-double-down"
[title]="strings['boards_collapseColumn']"
(click)="toggleCollapsed()"></span>
<span class="count-editor" *ngIf="activeUser && activeUser.isAnyAdmin()">
<i class="icon icon-hashtag" [title]="strings['boards_editTaskLimit']"
(click)="beginLimitEdit()"></i>
<div class="limit-editor" *ngIf="showLimitEditor">
<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>
<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>
[title]="strings['boards_limitSave']" (click)="saveLimitChanges()"></i>
</div>
</span>
<span class="sort-by">
{{ strings['sortBy'] }}:
<select [(ngModel)]="sortOption"
(change)="sortTasks()">
<select [(ngModel)]="sortOption" (change)="sortTasks()">
<option value="pos">
{{ strings['boards_sortByPosition'] }}
{{ strings['boards_sortByPosition'] }}
</option>
<option value="due">
{{ strings['boards_sortByDueDate'] }}
{{ strings['boards_sortByDueDate'] }}
</option>
<option value="pnt">
{{ strings['boards_sortByPoints'] }}
{{ strings['boards_sortByPoints'] }}
</option>
</select>
</span>
@ -64,28 +66,27 @@
<div class="quick-add">
<input type="text" [placeholder]="strings['boards_quickAdd']"
[(ngModel)]="quickAdd.title" (keyup.enter)="quickAddClicked($event)">
<button class="flat"
[title] = "strings['boards_addTask']"
(click)="quickAddClicked($event)">
[(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>
<div class="tasks" *ngIf="columnData"
cdkDropList
[cdkDropListData]="columnData.tasks"
(cdkDropListDropped)="drop($event, +columnData.id - 1)">
<div class="tasks" *ngIf="columnData" cdkDropList
[cdkDropListData]="columnData.tasks"
(cdkDropListDropped)="drop($event, +columnData.id - 1)">
<tb-task class="task-container" [id]="task.id" cdkDrag
*ngFor="let task of columnData.tasks"
[task]="task" [boards]="boards"
[add-task]="getShowModalFunction()"
[edit-task]="getShowModalFunction(task.id)"
[view-task]="getShowViewModalFunction(task.id)"
[remove-task]="getRemoveTaskFunction(task.id)"
(on-update-boards)="callBoardUpdate();"
[collapse]="collapseTasks"
(dblclick)="$event.preventDefault();showViewModal(task.id)"></tb-task>
*ngFor="let task of columnData.tasks"
[task]="task" [add-task]="getShowModalFunction()"
[edit-task]="getShowModalFunction(task.id)"
[view-task]="getShowViewModalFunction(task.id)"
[remove-task]="getRemoveTaskFunction(task.id)"
[collapse]="collapseTasks"
(on-update-boards)="callBoardUpdate();"
(dblclick)="$event.preventDefault();showViewModal(task.id)">
</tb-task>
</div>
<tb-context-menu>
@ -94,89 +95,97 @@
</tb-context-menu-item>
</tb-context-menu>
<tb-modal *ngIf="activeBoard && columnData"
modal-title="{{ strings['boards_viewTask'] }} - {{ viewModalProps.title }}"
modal-id="{{ MODAL_VIEW_ID + (columnData ? columnData.id : '') }}"
wide="true"
class="view-modal">
<tb-modal class="view-modal" *ngIf="activeBoard && columnData" wide="true"
modal-title="{{ strings['boards_viewTask'] }} -
{{ viewModalProps.title }}"
modal-id="{{ MODAL_VIEW_ID + (columnData ? columnData.id : '') }}">
<div *ngIf="viewModalProps.points">
<span class="badge">{{ viewModalProps.points }}</span>
</div>
<div class="details"
[style.background-color]="viewModalProps.color">
<div class="details" [style.background-color]="viewModalProps.color">
<div class="date" *ngIf="viewModalProps.due_date"
[class.overdue]="isOverdue"
[class.near-due]="isNearlyDue">
{{ strings['boards_taskDue'] + ' ' + viewModalProps.due_date }}
[class.overdue]="isOverdue" [class.near-due]="isNearlyDue">
{{ strings['boards_taskDue'] }} {{ viewModalProps.due_date | date }}
</div>
<div class="description" *ngIf="viewModalProps.description.length"
[innerHtml]="viewModalProps.html">
[innerHtml]="viewModalProps.html">
</div>
<div class="stats">
<div>
<strong>{{ strings['boards_taskAssignees'] }}</strong>
<span *ngFor="let user of viewModalProps.assignees">
{{ user.username }}
</span>
<span *ngIf="viewModalProps.assignees.length === 0">
{{ strings['boards_filterByUnassigned'] }}
</span>
</div>
<div>
<strong>{{ strings['boards_taskCategories'] }}</strong>
<span *ngFor="let cat of viewModalProps.categories">
{{ cat.name }}
</span>
<span *ngIf="viewModalProps.categories.length === 0">
{{ strings['boards_filterByUncategorized'] }}
</span>
</div>
<div>
<strong>{{ strings['boards_taskCurrentColumn'] }}</strong>
{{ columnData.name }}
</div>
</div>
</div>
<div class="quick-actions">
<button class="flat"
(click)="this.modal.close(MODAL_VIEW_ID + (columnData ? columnData.id : ''));
showModal(viewModalProps.id)">
<button class="flat" (click)="this.modal.close(MODAL_VIEW_ID +
(columnData ? columnData.id : ''));
showModal(viewModalProps.id)">
{{ strings['boards_editTask'] }}
</button>
<button class="flat"
(click)="getRemoveTaskFunction(viewModalProps.id)()">
<button class="flat" (click)="getRemoveTaskFunction(viewModalProps.id)()">
{{ strings['boards_removeTask'] }}
</button>
</div>
<div *ngIf="viewModalProps.attachments.length">
<h3>{{ strings['boards_taskAttachments'] }}</h3>
<div class="list-group">
<div class="list-group-item" *ngFor="let item of viewModalProps.attachments">
<div class="list-group-item"
*ngFor="let item of viewModalProps.attachments">
{{ item.filename }}
<div class="detail small">
{{ strings['boards_taskUploadedBy'] }}: {{ userName(item.user_id) }}
{{ strings['boards_taskUploadedOn'] }} {{ item.timestamp * 1000 | date:'full' }}
{{ strings['boards_taskUploadedBy'] }}:
{{ userName(item.user_id) }}
{{ strings['boards_taskUploadedOn'] }}
{{ item.timestamp * 1000 | date:'medium' }}
</div>
<div class="pull-right">
<i class="icon icon-eye"
[title]="strings['boards_taskView'] + ' ' + item.filename"
(click)="viewFile(item.diskfilename)"></i>
<i class="icon icon-eye" (click)="viewFile(item.diskfilename)"
[title]="strings['boards_taskView'] + ' ' + item.filename"></i>
<i class="icon icon-download"
[title]="strings['boards_taskDownload'] + ' ' + item.filename"
></i>
<i class="icon icon-download" [title]="strings['boards_taskDownload']
+ ' ' + item.filename"></i>
<i class="icon icon-trash-empty"
[title]="strings['settings_remove'] + ' ' + item.filename"
(click)="attachmentToRemove = item;
modal.open(MODAL_CONFIRM_ATTACHMENT_ID +
(columnData ? columnData.id : ''))"></i>
(click)="attachmentToRemove = item;
modal.open(MODAL_CONFIRM_ATTACHMENT_ID +
(columnData ? columnData.id : ''))"></i>
</div>
</div>
</div>
@ -184,140 +193,156 @@
<div>
<h3>{{ strings['boards_taskAddAttachment'] }}</h3>
<input type="file" #fileupload (change)="fileChange(fileupload.files[0])">
<button (click)="uploadFile()" [disabled]="!fileupload.files[0]">
<i class="icon icon-upload"></i>
{{ strings['boards_taskUpload'] }}
</button>
</div>
<div *ngIf="viewModalProps.comments.length">
<h3>{{ strings['boards_taskComments'] }}</h3>
<div class="comment"
*ngFor="let comment of viewModalProps.comments">
<div [innerHTML]="getComment(comment.text)"
*ngIf="!comment.isEdit"></div>
<textarea *ngIf="comment.isEdit"
[(ngModel)]="commentEdit.text"
(keyup.control.enter)="comment.isEdit = false;editComment()"
(keyup.enter)="preventEnter($event)"></textarea>
<div class="comment" *ngFor="let comment of viewModalProps.comments">
<div [innerHTML]="getComment(comment.text)" *ngIf="!comment.isEdit"></div>
<textarea *ngIf="comment.isEdit" [(ngModel)]="commentEdit.text"
(keyup.control.enter)="comment.isEdit = false;editComment()"
(keyup.enter)="preventEnter($event)"></textarea>
<div class="byline">
{{ comment.is_edited ? strings['boards_editedBy']
: strings['boards_postedBy'] }}
: strings['boards_postedBy'] }}
{{ getUserName(comment.user_id) }} &mdash;
{{ comment.timestamp | date:'medium' }}
</div>
<div class="actions" *ngIf="canAdminComment(comment)">
<i class="icon icon-cancel"
[title]="strings['cancel']"
*ngIf="comment.isEdit"
(click)="comment.isEdit = false"></i>
<i class="icon icon-floppy color-primary"
[title]="strings['save']"
*ngIf="comment.isEdit"
(click)="comment.isEdit = false;editComment()"></i>
<i class="icon icon-cancel" [title]="strings['cancel']"
*ngIf="comment.isEdit" (click)="comment.isEdit = false"></i>
<i class="icon icon-floppy color-primary" [title]="strings['save']"
*ngIf="comment.isEdit" (click)="comment.isEdit = false;editComment()"
></i>
<i class="icon icon-edit color-primary"
[title]="strings['boards_taskEditComment']"
*ngIf="!comment.isEdit"
(click)="comment.isEdit = true;beginEditComment(comment)"></i>
[title]="strings['boards_taskEditComment']" *ngIf="!comment.isEdit"
(click)="comment.isEdit = true;beginEditComment(comment)"></i>
<i class="icon icon-trash-empty color-secondary"
[title]="strings['boards_taskRemoveComment']"
(click)="commentToRemove=comment;
modal.open(MODAL_CONFIRM_COMMENT_ID +
(columnData ? columnData.id : ''))"></i>
[title]="strings['boards_taskRemoveComment']"
(click)="commentToRemove=comment;
modal.open(MODAL_CONFIRM_COMMENT_ID +
(columnData ? columnData.id : ''))"></i>
</div>
</div>
</div>
<div class="clearfix">
<h3>{{ strings['boards_taskAddComment'] }}</h3>
<textarea rows="5" [(ngModel)]="newComment"
(keyup.control.enter)="addComment()"
(keyup.enter)="preventEnter($event)"></textarea>
<button class="right" (click)="addComment()" [disabled]="newComment?.length === 0">
(keyup.control.enter)="addComment()"
(keyup.enter)="preventEnter($event)"></textarea>
<button class="right" (click)="addComment()"
[disabled]="newComment?.length === 0">
<i class="icon icon-comment-empty"></i>
{{ strings['boards_taskAddComment'] }}
</button>
</div>
<div class="activity"
[class.collapsed]="collapseActivity"
*ngIf="showActivity">
<div class="activity" [class.collapsed]="collapseActivity"
*ngIf="showActivity">
<div class="title">
<h2>
{{ strings['boards_taskActivity'] }}
<span class="right">
<i class="icon icon-angle-double-down"
*ngIf="!collapseActivity"
(click)="collapseActivity = true"></i>
*ngIf="!collapseActivity"
(click)="collapseActivity = true"></i>
<i class="icon icon-angle-double-up"
*ngIf="collapseActivity"
(click)="collapseActivity = false"></i>
*ngIf="collapseActivity"
(click)="collapseActivity = false"></i>
</span>
</h2>
</div>
<div class="log-items" *ngIf="!collapseActivity">
<div *ngFor="let item of viewTaskActivities" class="log-item">
{{ item.text }}
<span>{{ item.timestamp * 1000 | date:'medium' }}</span>
</div>
</div>
</div>
</tb-modal>
<tb-modal *ngIf="activeBoard && columnData"
modal-title="{{ modalProps.id === 0
? strings['boards_addTask']
: strings['boards_editTask'] }}"
modal-id="{{ MODAL_ID + (columnData ? columnData.id : '') }}">
modal-title="{{ modalProps.id === 0 ? strings['boards_addTask']
: strings['boards_editTask'] }}"
modal-id="{{ MODAL_ID + (columnData ? columnData.id : '') }}">
<label>
{{ strings['boards_taskTitle'] }}
<input #focusMe type="text" name="title"
[placeholder]="strings['boards_taskTitlePlaceholder']"
[(ngModel)]="modalProps.title">
<input type="text" name="title" #focusMe [(ngModel)]="modalProps.title"
[placeholder]="strings['boards_taskTitlePlaceholder']">
</label>
<label>
{{ strings['boards_taskDescription'] }}
<textarea name="description" rows="5"
[placeholder]="strings['boards_taskDescriptionPlaceholder']"
(keyup.control.enter)="modalProps.id === 0 ? addTask() : updateTask()"
(keyup.enter)="preventEnter($event)"
[(ngModel)]="modalProps.description"></textarea>
<textarea name="description" rows="5" [(ngModel)]="modalProps.description"
[placeholder]="strings['boards_taskDescriptionPlaceholder']"
(keyup.control.enter)="modalProps.id === 0 ? addTask()
: updateTask()"
(keyup.enter)="preventEnter($event)"></textarea>
</label>
<label>
{{ strings['boards_taskAssignees'] }}
<select name="assignees" multiple [(ngModel)]="modalProps.assignees">
<option *ngFor="let user of activeBoard.users"
[ngValue]="user">{{ user.username }}</option>
<option *ngFor="let user of activeBoard.users" [ngValue]="user">
{{ user.username }}
</option>
</select>
</label>
<label>
{{ strings['boards_taskCategories'] }}
<select name="categories" multiple [ngModel]="modalProps.categories"
(ngModelChange)="updateTaskColorByCategory($event)">
(ngModelChange)="updateTaskColorByCategory($event)">
<option *ngFor="let category of activeBoard.categories"
[ngValue]="category">{{ category.name }}</option>
[ngValue]="category">
{{ category.name }}
</option>
</select>
</label>
<div class="half">
<label>
{{ strings['boards_taskColumn'] }}
<select name="column" [(ngModel)]="modalProps.column_id">
<option *ngFor="let column of activeBoard.columns"
[ngValue]="column.id">{{ column.name }}</option>
[ngValue]="column.id">
{{ column.name }}
</option>
</select>
</label>
<label>
{{ strings['boards_taskColor'] }}
<input type="color" [(ngModel)]="modalProps.color">
</label>
</div>
@ -325,83 +350,107 @@
<div class="half">
<label>
{{ strings['boards_taskDateDue'] }}
<input type="date" [(ngModel)]="modalProps.due_date">
</label>
<label>
{{ strings['boards_taskPoints'] }}
<input type="number" [(ngModel)]="modalProps.points">
</label>
</div>
<div class="buttons">
<button #defaultAction *ngIf="modalProps.id === 0"
(click)="addTask()" [disabled]="saving">
<button #defaultAction *ngIf="modalProps.id === 0" (click)="addTask()"
[disabled]="saving">
<i class="icon icon-plus"></i>
{{ strings['boards_addTask'] }}
</button>
<button #defaultAction *ngIf="modalProps.id !== 0"
(click)="updateTask()" [disabled]="saving">
<button #defaultAction *ngIf="modalProps.id !== 0" (click)="updateTask()"
[disabled]="saving">
<i class="icon icon-floppy"></i>
{{ strings['boards_saveTask'] }}
</button>
<button class="flat" (click)="modal.close(MODAL_ID + (columnData ? columnData.id : ''))">
<button class="flat" (click)="modal.close(MODAL_ID + (columnData
? columnData.id : ''))">
{{ strings['cancel'] }}
</button>
</div>
</tb-modal>
<tb-modal modal-title="{{ strings['boards_confirmRemoveTask'] }}" blocking="true"
modal-id="{{ MODAL_CONFIRM_ID + (columnData ? columnData.id : '') }}">
<tb-modal modal-title="{{ strings['boards_confirmRemoveTask'] }}"
blocking="true"
modal-id="{{ MODAL_CONFIRM_ID + (columnData ? columnData.id : '') }}">
<div class="center">
{{ strings['boards_confirmWarning'] }}<br>
{{ strings['boards_confirmContinue'] }}
</div>
<div class="buttons">
<button class="flat"
(click)="modal.close(MODAL_CONFIRM_ID + (columnData ? columnData.id : ''));removeTask()">
<button class="flat" (click)="modal.close(MODAL_CONFIRM_ID +(columnData
? columnData.id : ''));removeTask()">
{{ strings['yes'] }}
</button>
<button #defaultAction #focusMe
(click)="modal.close(MODAL_CONFIRM_ID + (columnData ? columnData.id : ''))">
(click)="modal.close(MODAL_CONFIRM_ID + (columnData
? columnData.id : ''))">
{{ strings['no'] }}
</button>
</div>
</tb-modal>
<tb-modal modal-title="{{ strings['boards_confirmRemoveAttachment'] }}" blocking="true"
modal-id="{{ MODAL_CONFIRM_ATTACHMENT_ID + (columnData ? columnData.id : '') }}">
<tb-modal modal-title="{{ strings['boards_confirmRemoveAttachment'] }}"
blocking="true"
modal-id="{{ MODAL_CONFIRM_ATTACHMENT_ID + (columnData
? columnData.id : '') }}">
<div class="center">
{{ strings['boards_confirmWarningAttachment'] }}<br>
{{ strings['boards_confirmContinue'] }}
</div>
<div class="buttons">
<button class="flat"
(click)="modal.close(MODAL_CONFIRM_ATTACHMENT_ID
+ (columnData ? columnData.id : '')); removeAttachment()">
<button class="flat" (click)="modal.close(MODAL_CONFIRM_ATTACHMENT_ID +
(columnData ? columnData.id : ''));
removeAttachment()">
{{ strings['yes'] }}
</button>
<button #defaultAction #focusMe
(click)="modal.close(MODAL_CONFIRM_ATTACHMENT_ID + (columnData ? columnData.id : ''))">
(click)="modal.close(MODAL_CONFIRM_ATTACHMENT_ID + (columnData
? columnData.id : ''))">
{{ strings['no'] }}
</button>
</div>
</tb-modal>
<tb-modal modal-title="{{ strings['boards_confirmRemoveComment'] }}" blocking="true"
modal-id="{{ MODAL_CONFIRM_COMMENT_ID + (columnData ? columnData.id : '') }}">
<tb-modal modal-title="{{ strings['boards_confirmRemoveComment'] }}"
blocking="true"
modal-id="{{ MODAL_CONFIRM_COMMENT_ID + (columnData
? columnData.id : '') }}">
<div class="center">
{{ strings['boards_confirmWarningComment'] }}<br>
{{ strings['boards_confirmContinue'] }}
</div>
<div class="buttons">
<button class="flat"
(click)="modal.close(MODAL_CONFIRM_COMMENT_ID
+ (columnData ? columnData.id : ''));removeComment()">
<button class="flat" (click)="modal.close(MODAL_CONFIRM_COMMENT_ID +
(columnData ? columnData.id : ''));
removeComment()">
{{ strings['yes'] }}
</button>
<button #defaultAction #focusMe
(click)="modal.close(MODAL_CONFIRM_COMMENT_ID + (columnData ? columnData.id : ''))">
(click)="modal.close(MODAL_CONFIRM_COMMENT_ID + (columnData
? columnData.id : ''))">
{{ strings['no'] }}
</button>
</div>

View File

@ -81,8 +81,6 @@ export class ColumnDisplayComponent implements OnInit, OnDestroy {
// tslint:disable-next-line
@Input('column') columnData: Column;
// tslint:disable-next-line
@Input('boards') boards: Array<Board>;
// tslint:disable-next-line
@Output('on-update-boards')
@ -247,6 +245,8 @@ export class ColumnDisplayComponent implements OnInit, OnDestroy {
this.boardService.updateActiveBoard(boardData);
this.boardService.refreshToken();
this.saving = false;
}, err => {
this.notes.add({ type: 'error', text: err.toString() });
});
}
@ -337,6 +337,9 @@ export class ColumnDisplayComponent implements OnInit, OnDestroy {
response.alerts.forEach(note => this.notes.add(note));
if (response.status === 'success') {
attachment.id = response.data[1].id;
attachment.diskfilename = response.data[1].diskfilename;
this.viewModalProps.attachments.push(attachment);
}
});

View File

@ -1,67 +1,72 @@
<div class="task"
[ngClass]="{ 'filtered': taskData.filtered,
'hide': taskData.hideFiltered }"
[style.backgroundColor]="taskData.color"
[style.color]="getTextColor(taskData.color)">
[ngClass]="{ 'filtered': taskData.filtered,
'hide': taskData.hideFiltered }"
[style.backgroundColor]="taskData.color"
[style.color]="getTextColor(taskData.color)">
<h4 class="drag-handle">
<span class="icon"
[style.color]="getTextColor(taskData.color)"
[ngClass]="{ 'icon-minus-squared-alt': !isCollapsed,
'icon-plus-squared-alt': isCollapsed }"
[title]="isCollapsed
? strings['boards_expandTask']
: strings['boards_collapseTask']"
(click)="isCollapsed = !isCollapsed"></span>
[style.color]="getTextColor(taskData.color)"
[ngClass]="{ 'icon-minus-squared-alt': !isCollapsed,
'icon-plus-squared-alt': isCollapsed }"
[title]="isCollapsed ? strings['boards_expandTask']
: strings['boards_collapseTask']"
(click)="isCollapsed = !isCollapsed"></span>
{{ taskData.title }}
<span *ngIf="taskData.points > 0" class="badge right"
[title]="strings['boards_taskPoints'] ">
{{ taskData.points }}</span>
[title]="strings['boards_taskPoints'] ">{{ taskData.points }}</span>
</h4>
<div class="description" *ngIf="!isCollapsed"
[innerHtml]="taskData.html">
<div class="description" *ngIf="!isCollapsed" [innerHtml]="taskData.html">
</div>
<div class="stats">
<span *ngIf="userOptions.show_assignee">
{{ strings['boards_taskAssignedTo'] }}:
<span *ngFor="let assignee of taskData.assignees">
{{ assignee.username }}
</span>
<span *ngIf="!taskData.assignees || !taskData.assignees.length">
{{ strings['boards_taskUnassigned'] }}
</span>
</span>
<span class="right">
<span *ngIf="taskData.due_date"
[class.overdue]="isOverdue"
[class.near-due]="isNearlyDue">
<span *ngIf="taskData.due_date" [class.overdue]="isOverdue"
[class.near-due]="isNearlyDue">
{{ strings['boards_taskDue'] }}: {{ taskData.due_date | date }}
</span>
<span *ngIf="taskData.comments.length" class="icon icon-chat-empty"
[title]="taskData.comments.length + ' ' +
strings['boards_taskComments']"></span>
[title]="taskData.comments.length + ' ' +
strings['boards_taskComments']"></span>
<span *ngIf="taskData.attachments.length" class="icon icon-attach"
[title]="taskData.attachments.length + ' ' +
strings['boards_taskAttachments']"></span>
[title]="taskData.attachments.length + ' ' +
strings['boards_taskAttachments']"></span>
<span *ngFor="let category of taskData.categories" class="category"
[title]="strings['boards_taskCategory']">
[title]="strings['boards_taskCategory']">
{{ category.name }}
</span>
</span>
<div *ngIf="percentComplete"
[style]="getPercentStyle()"
[title]="getPercentTitle()"></div>
<div *ngIf="percentComplete" [style]="getPercentStyle()"
[title]="getPercentTitle()"></div>
</div>
<tb-context-menu>
<tb-context-menu-item (click)="viewTask()">
{{ strings['boards_viewTask'] }}
</tb-context-menu-item>
<tb-context-menu-item (click)="editTask()">
{{ strings['boards_editTask'] }}
</tb-context-menu-item>
<tb-context-menu-item (click)="removeTask()">
{{ strings['boards_removeTask'] }}
</tb-context-menu-item>
@ -71,32 +76,41 @@
<tb-context-menu-item isCustomEvent="true">
{{ strings['boards_copyTaskTo'] }}:
<i class="icon icon-help-circled"
attr.data-help="{{ strings['boards_copyMoveHelp'] }}"></i>
<select id="boardsList{{ taskData.id }}{{ strings['boards_copyTaskTo'].split(' ')[0] }}"
(change)="copyTaskToBoard($event)">
<select id="boardsList{{ taskData.id }}{{
strings['boards_copyTaskTo'].split(' ')[0] }}"
(change)="copyTaskToBoard($event)">
<option value="0">{{ strings['boards_selectBoard'] }}</option>
<ng-container *ngFor="let board of boardsList">
<option *ngIf="board.id !== activeBoard.id" [value]="board.id">
{{ board.name }}
</option>
</ng-container>
</select>
</tb-context-menu-item>
<tb-context-menu-item isCustomEvent="true">
{{ strings['boards_moveTaskTo'] }}:
<i class="icon icon-help-circled"
attr.data-help="{{ strings['boards_copyMoveHelp'] }}"></i>
<select id="boardsList{{ taskData.id }}{{
strings['boards_moveTaskTo'].split(' ')[0] }}"
(change)="moveTaskToBoard($event)">
strings['boards_moveTaskTo'].split(' ')[0] }}"
(change)="moveTaskToBoard($event)">
<option value="0">{{ strings['boards_selectBoard'] }}</option>
<ng-container *ngFor="let board of boardsList">
<option *ngIf="board.id !== activeBoard.id" [value]="board.id">
{{ board.name }}
</option>
</ng-container>
</select>
</tb-context-menu-item>
</div>
@ -106,8 +120,10 @@
<tb-context-menu-item isCustomEvent="true">
{{ strings['boards_moveTask'] }}:
<select id="columnsList{{ taskData.id }}" (change)="changeTaskColumn($event)">
<option value="0">{{ strings['boards_selectColumn'] }}</option>
<option *ngFor="let col of activeBoard.columns" [value]="col.id">
{{ col.name }}
</option>

View File

@ -51,11 +51,6 @@ export class TaskDisplayComponent implements OnInit {
// tslint:disable-next-line
@Output('on-update-boards') onUpdateBoards: EventEmitter<any>;
@Input('boards')
set boards(boards: Array<Board>) {
this.boardsList = boards;
}
constructor(public auth: AuthService,
private sanitizer: DomSanitizer,
public boardService: BoardService,