More for attachments, and cleanup

This commit is contained in:
Matthew Ross 2020-04-27 13:59:39 -04:00
parent fbddac7302
commit babbf81610
6 changed files with 134 additions and 51 deletions

View File

@ -8,18 +8,21 @@
<option [ngValue]="null">
{{ strings['boards_selectBoard'] }}...
</option>
<option *ngFor="let board of boards"
[ngValue]="board.id">
{{ board.name }}
</option>
</select>
</label>
<div class="right" *ngIf="activeBoard">
<label>
{{ strings['boards_hideFiltered'] }}:
<input type="checkbox" [(ngModel)]="hideFiltered"
(change)="toggleFiltered()">
</label>
<label>
{{ strings['boards_userFilter'] }}:
<select [(ngModel)]="userFilter"
@ -27,15 +30,18 @@
<option [ngValue]="null">
{{ strings['boards_filterByAny'] }}
</option>
<option [ngValue]="-1">
{{ strings['boards_filterByUnassigned'] }}
</option>
<option *ngFor="let user of activeBoard.users"
[ngValue]="user.id">
{{ user.username }}
</option>
</select>
</label>
<label>
{{ strings['boards_categoryFilter'] }}:
<select [(ngModel)]="categoryFilter"
@ -43,15 +49,18 @@
<option [ngValue]="null">
{{ strings['boards_filterByAny'] }}
</option>
<option [ngValue]="-1">
{{ strings['boards_filterByUncategorized'] }}
</option>
<option *ngFor="let category of activeBoard.categories"
[ngValue]="category.id">
{{ category.name }}
</option>
</select>
</label>
</div>
</div>
@ -62,7 +71,8 @@
</div>
<div class="no-boards center"
*ngIf="!loading && !activeBoard && this.boards.length > 0 && !activeUser.default_board_id">
*ngIf="!loading && !activeBoard && this.boards.length > 0 &&
!activeUser.default_board_id">
<h1>{{ strings['boards_noDefault'] }}</h1>
<p>{{ strings['boards_noDefaultMessage'] }}
@ -70,6 +80,7 @@
{{ strings['settings'] }}
</a>.
</p>
<p></p>
</div>

View File

@ -25,7 +25,7 @@ export class BoardDisplayComponent implements OnInit, OnDestroy {
public categoryFilter: number;
public userFilter: number;
public boardNavId: number;
public boardNavId: number | null;
public activeUser: User;
public activeBoard: Board;

View File

@ -1,5 +1,5 @@
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
import { HttpClient } from '@angular/common/http';
import * as marked from 'marked';
import * as hljs from 'highlight.js';
@ -59,7 +59,7 @@ export class BoardService {
return this.http.get('api/boards')
.pipe(
map((response: ApiResponse) => response),
catchError((err) => of(err.error as ApiResponse))
catchError((err) => of(err.error as ApiResponse))
);
}
@ -67,7 +67,7 @@ export class BoardService {
return this.http.post('api/users/' + userId + '/cols', { id: columnId })
.pipe(
map((response: ApiResponse) => response),
catchError((err) => of(err.error as ApiResponse))
catchError((err) => of(err.error as ApiResponse))
);
}
@ -75,7 +75,7 @@ export class BoardService {
return this.http.post('api/boards/' + board.id, board)
.pipe(
map((response: ApiResponse) => response),
catchError((err) => of(err.error as ApiResponse))
catchError((err) => of(err.error as ApiResponse))
);
}
@ -83,7 +83,7 @@ export class BoardService {
return this.http.post('api/columns/' + column.id, column)
.pipe(
map((response: ApiResponse) => response),
catchError((err) => of(err.error as ApiResponse))
catchError((err) => of(err.error as ApiResponse))
);
}
@ -91,7 +91,7 @@ export class BoardService {
return this.http.post('api/tasks', task)
.pipe(
map((response: ApiResponse) => response),
catchError((err) => of(err.error as ApiResponse))
catchError((err) => of(err.error as ApiResponse))
);
}
@ -99,7 +99,7 @@ export class BoardService {
return this.http.post('api/tasks/' + task.id, task)
.pipe(
map((response: ApiResponse) => response),
catchError((err) => of(err.error as ApiResponse))
catchError((err) => of(err.error as ApiResponse))
);
}
@ -107,7 +107,7 @@ export class BoardService {
return this.http.delete('api/tasks/' + taskId)
.pipe(
map((response: ApiResponse) => response),
catchError((err) => of(err.error as ApiResponse))
catchError((err) => of(err.error as ApiResponse))
);
}
@ -115,7 +115,7 @@ export class BoardService {
return this.http.get('api/activity/task/' + taskId)
.pipe(
map((response: ApiResponse) => response),
catchError((err) => of(err.error as ApiResponse))
catchError((err) => of(err.error as ApiResponse))
);
}
@ -123,7 +123,7 @@ export class BoardService {
return this.http.post('api/comments/' + comment.id, comment)
.pipe(
map((response: ApiResponse) => response),
catchError((err) => of(err.error as ApiResponse))
catchError((err) => of(err.error as ApiResponse))
);
}
@ -131,35 +131,31 @@ export class BoardService {
return this.http.delete('api/comments/' + commentId)
.pipe(
map((response: ApiResponse) => response),
catchError((err) => of(err.error as ApiResponse))
catchError((err) => of(err.error as ApiResponse))
);
}
/* istanbul ignore next */
uploadAttachment(attachment: Attachment, data: FormData): Observable<ApiResponse> {
const headers = new HttpHeaders();
const options = { headers, params: new HttpParams() };
options.params.set('attachment', JSON.stringify(attachment));
return this.http.post('api/attachments', data, options)
uploadAttachment(attachment: Attachment): Observable<ApiResponse> {
return this.http.post('api/attachments', attachment)
.pipe(
map((response: ApiResponse) => response),
catchError((err) => of(err.error as ApiResponse))
catchError((err) => of(err.error as ApiResponse))
);
}
removeAttachment(id: number): Observable<ApiResponse> {
return this.http.delete('api/attachments/' + id)
.pipe(
map((response: ApiResponse) => response),
catchError((err) => of(err.error as ApiResponse))
)
}
refreshToken(): void {
this.http.post('api/refresh', {}).subscribe();
}
private defaultCallback = (err: any, text: string) => {
if (err) {
return '';
}
return text;
}
private convertBoardData(boardData: any): Board {
if (boardData instanceof Board) {
return boardData;
@ -174,6 +170,14 @@ export class BoardService {
boardData.sharedUser);
}
private defaultCallback = (err: any, text: string) => {
if (err) {
return '';
}
return text;
}
private initMarked(): void {
const renderer = new marked.Renderer();

View File

@ -155,6 +155,31 @@
<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">
{{ item.filename }}
<div class="detail small">
{{ strings['boards_taskUploadedBy'] }}: {{ userName(item.user_id) }}
{{ strings['boards_taskUploadedOn'] }} {{ item.timestamp * 1000 | date:'full' }}
</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-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>
</div>
</div>
</div>
</div>
<div>
@ -344,6 +369,25 @@
</div>
</tb-modal>
<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()">
{{ strings['yes'] }}
</button>
<button #defaultAction #focusMe
(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 : '') }}">
<div class="center">

View File

@ -65,6 +65,7 @@ export class ColumnDisplayComponent implements OnInit, OnDestroy {
public commentEdit: Comment;
public commentToRemove: Comment;
public attachmentToRemove: Attachment;
public viewModalProps: Task;
public modalProps: Task;
public userOptions: UserOptions;
@ -75,6 +76,7 @@ export class ColumnDisplayComponent implements OnInit, OnDestroy {
public MODAL_ID: string;
public MODAL_VIEW_ID: string;
public MODAL_CONFIRM_ID: string;
public MODAL_CONFIRM_ATTACHMENT_ID: string;
public MODAL_CONFIRM_COMMENT_ID: string;
// tslint:disable-next-line
@ -100,6 +102,7 @@ export class ColumnDisplayComponent implements OnInit, OnDestroy {
this.MODAL_ID = 'add-task-form-';
this.MODAL_VIEW_ID = 'view-task-form-';
this.MODAL_CONFIRM_ID = 'task-remove-confirm';
this.MODAL_CONFIRM_ATTACHMENT_ID = 'attachment-remove-confirm';
this.MODAL_CONFIRM_COMMENT_ID = 'comment-remove-confirm';
this.quickAdd = new Task();
@ -167,6 +170,10 @@ export class ColumnDisplayComponent implements OnInit, OnDestroy {
this.subs.forEach(sub => (sub.unsubscribe()));
}
userName(id: number) {
return this.activeBoard.users.find(u => u.id === id).username;
}
sortTasks() {
switch (this.sortOption) {
case 'pos':
@ -204,7 +211,7 @@ export class ColumnDisplayComponent implements OnInit, OnDestroy {
this.collapseTasks = !this.collapseTasks;
}
updateTaskColorByCategory(event: Array<Category>) {
updateTaskColorByCategory(event: Category[]) {
this.modalProps.categories = event;
this.modalProps.color = event[event.length - 1].default_task_color;
}
@ -314,22 +321,45 @@ export class ColumnDisplayComponent implements OnInit, OnDestroy {
return;
}
const formData = new FormData();
formData.append('file', this.fileUpload);
const fileReader = new FileReader();
fileReader.onload = () => {
const attachment = new Attachment();
const attachment = new Attachment();
attachment.filename = this.fileUpload.name;
attachment.name = attachment.filename.split('.')[0];
attachment.type = this.fileUpload.type;
attachment.user_id = this.activeUser.id;
attachment.task_id = this.viewModalProps.id;
attachment.filename = this.fileUpload.name;
attachment.name = attachment.filename.split('.').slice(0, -1).join('.');
attachment.type = this.fileUpload.type;
attachment.user_id = this.activeUser.id;
attachment.task_id = this.viewModalProps.id;
attachment.data = fileReader.result;
this.boardService.uploadAttachment(attachment, formData)
.subscribe(response => {
response.alerts.forEach(note => this.notes.add(note));
this.boardService.uploadAttachment(attachment)
.subscribe(response => {
response.alerts.forEach(note => this.notes.add(note));
console.log(response);
});
if (response.status === 'success') {
this.viewModalProps.attachments.push(attachment);
}
});
}
fileReader.readAsBinaryString(this.fileUpload);
}
viewFile(hash: string) {
window.open(`./files/${hash}`, 'tb-file-view');
}
removeAttachment() {
this.boardService.removeAttachment(this.attachmentToRemove.id).subscribe(res => {
res.alerts.forEach(note => this.notes.add(note));
if (res.status === 'success') {
const index = this.viewModalProps.attachments
.findIndex(x => x.id === this.attachmentToRemove.id);
this.viewModalProps.attachments.splice(index, 1);
}
});
}
addComment() {
@ -630,7 +660,7 @@ export class ColumnDisplayComponent implements OnInit, OnDestroy {
});
}
private updateTaskComments(task: Task, newComments: Array<any>) {
private updateTaskComments(task: Task, newComments: any[]) {
task.comments = [];
if (!newComments) {

View File

@ -6,7 +6,6 @@ import {
Output
} from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
import { CdkDragDrop, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop';
import {
ApiResponse,
@ -143,14 +142,9 @@ export class TaskDisplayComponent implements OnInit {
const newBoardId = +(select[select.selectedIndex] as HTMLOptionElement).value;
const taskData = { ...this.taskData };
let boardData: Board;
const boardData = this.boardsList.find(board => board.id === newBoardId);
this.boardsList.forEach(board => {
if (board.id === newBoardId) {
taskData.column_id = board.columns[0].id;
boardData = board;
}
});
taskData.column_id = boardData.columns[0].id;
this.boardService.addTask(taskData)
.subscribe((response: ApiResponse) => {