Initial dashboard work
This commit is contained in:
parent
61ab341e33
commit
2bc585f205
166
src/api/controllers/Dashboard.php
Normal file
166
src/api/controllers/Dashboard.php
Normal file
@ -0,0 +1,166 @@
|
||||
<?php
|
||||
use RedBeanPHP\R;
|
||||
|
||||
class Dashboard extends BaseController {
|
||||
|
||||
public function getMyBoardInfo($request, $response) {
|
||||
$status = $this->secureRoute($request, $response, SecurityLevel::USER);
|
||||
if ($status !== 200) {
|
||||
return $this->jsonResponse($response, $status);
|
||||
}
|
||||
|
||||
$boards = $this->loadAllBoards($request);
|
||||
|
||||
if (!count($boards)) {
|
||||
$this->apiJson->addAlert('info', $this->strings->api_noBoards);
|
||||
|
||||
return $this->jsonResponse($response);
|
||||
}
|
||||
|
||||
$this->apiJson->setSuccess();
|
||||
$this->apiJson->addData($this->convertBoardData($boards));
|
||||
|
||||
return $this->jsonResponse($response);
|
||||
}
|
||||
|
||||
public function getMyTaskInfo($request, $response) {
|
||||
$status = $this->secureRoute($request, $response, SecurityLevel::USER);
|
||||
if ($status !== 200) {
|
||||
return $this->jsonResponse($response, $status);
|
||||
}
|
||||
|
||||
$boards = $this->loadAllBoards($request);
|
||||
|
||||
if (!count($boards)) {
|
||||
$this->apiJson->addAlert('info', $this->strings->api_noBoards);
|
||||
|
||||
return $this->jsonResponse($response);
|
||||
}
|
||||
|
||||
$this->apiJson->setSuccess();
|
||||
$userId = Auth::GetUserId($request);
|
||||
$this->apiJson->addData($this->convertTaskData($boards, $userId));
|
||||
|
||||
return $this->jsonResponse($response);
|
||||
}
|
||||
|
||||
private function convertBoardData($boards) {
|
||||
$retVal = [];
|
||||
|
||||
foreach($boards as $board) {
|
||||
if ($board["is_active"] !== '1') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$retVal[] = (object)array(
|
||||
"id" => $board["id"],
|
||||
"name" => $board["name"],
|
||||
"columns" => [],
|
||||
"categories" => []
|
||||
);
|
||||
|
||||
$index = count($retVal) - 1;
|
||||
|
||||
foreach($board["ownColumn"] as $column) {
|
||||
$retVal[$index]->columns[] = (object)array(
|
||||
"name" => $column["name"],
|
||||
"tasks" => count($column["ownTask"])
|
||||
);
|
||||
}
|
||||
|
||||
foreach($board["ownCategory"] as $category) {
|
||||
$retVal[$index]->categories[] = (object)array(
|
||||
"name" => $category["name"],
|
||||
"tasks" => count($category["sharedTask"])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $retVal;
|
||||
}
|
||||
|
||||
private function convertTaskData($boards, $userId) {
|
||||
$retVal = [];
|
||||
|
||||
foreach($boards as $board) {
|
||||
foreach($board["ownColumn"] as $column) {
|
||||
foreach($column["ownTask"] as $task) {
|
||||
$isMine = false;
|
||||
|
||||
foreach($task["sharedUser"] as $assignee) {
|
||||
if ($assignee["id"] === (string)$userId) {
|
||||
$isMine = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$isMine) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$attachments = R::exec(
|
||||
"SELECT COUNT(id) AS num FROM attachment WHERE task_id = ?",
|
||||
[ $task["id"] ]
|
||||
);
|
||||
|
||||
$comments = R::exec(
|
||||
"SELECT COUNT(id) AS num FROM comment WHERE task_id = ?",
|
||||
[ $task["id"] ]
|
||||
);
|
||||
|
||||
$retVal[] = (object)array(
|
||||
"board" => $board["name"],
|
||||
"board_id" => $board["id"],
|
||||
"title" => $task["title"],
|
||||
"color" => $task["color"],
|
||||
"column" => $column["name"],
|
||||
"date_due" => $task["due_date"],
|
||||
"points" => $task["points"],
|
||||
"attachments" => $attachments,
|
||||
"comments" => $comments
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $retVal;
|
||||
}
|
||||
|
||||
private function loadAllBoards($request) {
|
||||
$boards = [];
|
||||
$boardBeans = R::findAll('board');
|
||||
|
||||
if (count($boardBeans)) {
|
||||
foreach ($boardBeans as $bean) {
|
||||
if (Auth::HasBoardAccess($request, $bean->id)) {
|
||||
$this->cleanBoard($bean);
|
||||
$boards[] = $bean;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return R::exportAll($boards);
|
||||
}
|
||||
|
||||
private function cleanBoard(&$board) {
|
||||
foreach ($board->sharedUserList as $user) {
|
||||
$user = $this->cleanUser($user);
|
||||
}
|
||||
|
||||
foreach ($board->xownColumnList as $column) {
|
||||
foreach ($column->xownTaskList as $task) {
|
||||
foreach ($task->sharedUserList as $user) {
|
||||
$user = $this->cleanUser($user);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function cleanUser($user) {
|
||||
unset($user->password_hash);
|
||||
unset($user->active_token);
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -106,6 +106,9 @@ $app->post('/logout', 'Auth:logout'); // Unsecured (clears JWT)
|
||||
$app->post('/authenticate', 'Auth:authenticate'); // Unsecured (checks JWT)
|
||||
$app->post('/refresh', 'Auth:refreshToken'); // Unsecured (checks and updates JWT)
|
||||
|
||||
$app->get('/dashboard/boards', 'Dashboard:getMyBoardInfo'); // User (by board access)
|
||||
$app->get('/dashboard/tasks', 'Dashboard:getMyTaskInfo'); // User (by board access)
|
||||
|
||||
$app->run();
|
||||
R::close();
|
||||
|
||||
|
@ -1,134 +1,72 @@
|
||||
<tb-top-nav page-name="Dashboard"></tb-top-nav>
|
||||
<tb-top-nav page-name="{{ pageName }}"></tb-top-nav>
|
||||
|
||||
<div class="dashboard">
|
||||
<section>
|
||||
<h2>Boards and Tasks</h2>
|
||||
|
||||
<div class="row">
|
||||
<h3>My Boards</h3>
|
||||
|
||||
<table class="alternating">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Board</th>
|
||||
<th>Columns</th>
|
||||
<th>Categories</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><a href="#">Personal Projects</a></td>
|
||||
<td>
|
||||
To Do <span class="badge" title="Tasks in Column">8</span>
|
||||
Doing <span class="badge" title="Tasks in Column">3</span>
|
||||
Done <span class="badge" title="Tasks in Column">0</span>
|
||||
</td>
|
||||
<td>
|
||||
List <span class="badge" title="Tasks in Category">3</span>
|
||||
Thing 1 <span class="badge" title="Tasks in Category">4</span>
|
||||
Thing 2 <span class="badge" title="Tasks in Category">4</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="#">TaskBoard</a></td>
|
||||
<td>
|
||||
Backlog <span class="badge" title="Tasks in Column">23</span>
|
||||
Ready <span class="badge" title="Tasks in Column">5</span>
|
||||
In Work <span class="badge" title="Tasks in Column">3</span>
|
||||
Test <span class="badge" title="Tasks in Column">2</span>
|
||||
Done <span class="badge" title="Tasks in Column">18</span>
|
||||
</td>
|
||||
<td>
|
||||
Front-End <span class="badge" title="Tasks in Category">19</span>
|
||||
Back-End <span class="badge" title="Tasks in Category">28</span>
|
||||
Test <span class="badge" title="Tasks in Category">2</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<h3>My Tasks</h3>
|
||||
|
||||
<table class="alternating">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Board</th>
|
||||
<th>Task</th>
|
||||
<th>Details</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><a href="#">TaskBoard</a></td>
|
||||
<td>
|
||||
<a href="#">An Important Task</a>
|
||||
<span class="badge" title="Task Color"
|
||||
style="background-color:#debee8"> </span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="details">Column: <em>In Work</em></span>
|
||||
<span class="details">Due: <em>12/31/2016</em></span>
|
||||
<span class="details">Points: <em>8</em></span>
|
||||
<span class="details">Attachments: <em>2</em></span>
|
||||
<span class="details">Comments: <em>5</em></span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="#">Personal Projects</a></td>
|
||||
<td>
|
||||
<a href="#">Make a List</a>
|
||||
<span class="badge" title="Task Color"
|
||||
style="background-color:#bee7f4"> </span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="details">Column: <em>To Do</em></span>
|
||||
<span class="details">Comments: <em>2</em></span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
<tb-my-items [boardsLoading]="boardsLoading"
|
||||
[boards]="boards" [boardsMessage]="boardsMessage"
|
||||
[tasksLoading]="tasksLoading" [tasks]="tasks"
|
||||
[tasksMessage]="tasksMessage"
|
||||
[strings]="strings"></tb-my-items>
|
||||
|
||||
<section>
|
||||
<h2>Analytics</h2>
|
||||
<h2>{{ strings['dashboard_analytics'] }}</h2>
|
||||
|
||||
<div class="row">
|
||||
<select>
|
||||
<option>Select Board...</option>
|
||||
<select [(ngModel)]="analyticsBoardId" (change)="updateAnalytics()">
|
||||
<option [ngValue]="null">
|
||||
{{ strings['boards_selectBoard'] }}...
|
||||
</option>
|
||||
|
||||
<option *ngFor="let board of boards">
|
||||
{{ board.name }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="row" *ngIf="analyticsBoardId">
|
||||
<h3>Task Burndown</h3>
|
||||
|
||||
<label class="inline">Start Date: <input type="date"></label>
|
||||
<label class="inline">End Date: <input type="date"></label>
|
||||
<label class="inline">
|
||||
Start Date:
|
||||
<input type="date" [(ngModel)]="burndownDates.start"
|
||||
(change)="validateDates()">
|
||||
</label>
|
||||
|
||||
<tb-charts chart-name="chartBurndown" chart-type="line"
|
||||
series="29,26,21,18,13,8,3"
|
||||
labels="12/31/2015,1/1/2016,1/2/2016,1/3/2016,1/4/2016,1/5/2016,1/6/2016"
|
||||
table-head="Date"></tb-charts>
|
||||
<label class="inline">
|
||||
End Date:
|
||||
<input type="date" [(ngModel)]="burndownDates.end"
|
||||
(change)="validateDates()">
|
||||
</label>
|
||||
|
||||
<div *ngIf="datesError.length" class="error">{{ datesError }}</div>
|
||||
|
||||
<div *ngIf="!showBurndown">Select dates to display burndown chart.</div>
|
||||
|
||||
<tb-charts *ngIf="showBurndown"
|
||||
chart-name="chartBurndown" chart-type="line"
|
||||
series="29,26,21,18,13,8,3"
|
||||
labels="12/31/2015,1/1/2016,1/2/2016,1/3/2016,1/4/2016,1/5/2016,1/6/2016"
|
||||
table-head="Date"></tb-charts>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="row" *ngIf="analyticsBoardId">
|
||||
<div class="half-page">
|
||||
<h3>Task Distribution by User</h3>
|
||||
|
||||
<tb-charts chart-name="chartByUser" series="7,13,8,5"
|
||||
labels="admin,tester,user,another"
|
||||
table-head="User"></tb-charts>
|
||||
labels="admin,tester,user,another"
|
||||
table-head="User"></tb-charts>
|
||||
</div>
|
||||
|
||||
<div class="half-page">
|
||||
<h3>Task Distribution by Column</h3>
|
||||
|
||||
<tb-charts chart-name="chartByColumn" series="18,3,7"
|
||||
labels="To Do,Doing,Done"
|
||||
table-head="Column"></tb-charts>
|
||||
labels="To Do,Doing,Done"
|
||||
table-head="Column"></tb-charts>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="row" *ngIf="analyticsBoardId">
|
||||
<tb-calendar board-id="1"></tb-calendar>
|
||||
</div>
|
||||
</section>
|
||||
|
@ -1,17 +1,123 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
|
||||
// import { Charts } from './charts/charts.component';
|
||||
// import { Calendar } from './calendar/calendar.component';
|
||||
import { DashboardService } from './dashboard.service';
|
||||
import { StringsService } from '../shared/services';
|
||||
|
||||
interface BurndownDates {
|
||||
start: string;
|
||||
end: string;
|
||||
|
||||
startDate: Date;
|
||||
endDate: Date;
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
@Component({
|
||||
selector: 'tb-dashboard',
|
||||
templateUrl: './dashboard.component.html'
|
||||
})
|
||||
export class DashboardComponent {
|
||||
constructor(public title: Title) {
|
||||
title.setTitle('TaskBoard - Dashboard');
|
||||
export class DashboardComponent implements OnInit, OnDestroy {
|
||||
private subs: any[];
|
||||
|
||||
public boards: any;
|
||||
public boardsLoading: boolean;
|
||||
public boardsMessage: string;
|
||||
|
||||
public tasks: any;
|
||||
public tasksLoading: boolean;
|
||||
public tasksMessage: string;
|
||||
|
||||
public strings: any;
|
||||
public pageName: string;
|
||||
|
||||
public analyticsBoardId: number;
|
||||
public burndownDates: BurndownDates;
|
||||
public datesError: string;
|
||||
|
||||
get showBurndown() {
|
||||
return this.burndownDates.start &&
|
||||
this.burndownDates.end && !this.datesError.length;
|
||||
}
|
||||
|
||||
constructor(public title: Title,
|
||||
private service: DashboardService,
|
||||
public stringsService: StringsService) {
|
||||
this.subs = [];
|
||||
this.boardsLoading = true;
|
||||
this.tasksLoading = true;
|
||||
|
||||
this.burndownDates = {
|
||||
start: null,
|
||||
end: null,
|
||||
startDate: null,
|
||||
endDate: null
|
||||
};
|
||||
this.datesError = '';
|
||||
|
||||
this.subs.push(
|
||||
stringsService.stringsChanged.subscribe(newStrings => {
|
||||
this.strings = newStrings;
|
||||
|
||||
title.setTitle('TaskBoard - ' + this.strings.dashboard);
|
||||
this.pageName = this.strings.dashboard;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.service.getBoardInfo().subscribe(res => {
|
||||
this.boards = res.data[1];
|
||||
|
||||
if (res.status === 'failure') {
|
||||
this.boardsMessage = res.alerts[0].text;
|
||||
}
|
||||
|
||||
this.boardsLoading = false;
|
||||
});
|
||||
|
||||
this.service.getTaskInfo().subscribe(res => {
|
||||
this.tasks = res.data[1];
|
||||
|
||||
if (res.status === 'failure') {
|
||||
this.tasksMessage = res.alerts[0].text;
|
||||
}
|
||||
|
||||
this.tasksLoading = false;
|
||||
})
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.subs.forEach(sub => sub.unsubscribe());
|
||||
}
|
||||
|
||||
validateDates() {
|
||||
if (this.burndownDates.start === null || this.burndownDates.end === null) {
|
||||
return;
|
||||
}
|
||||
this.datesError = '';
|
||||
|
||||
this.burndownDates.startDate = new Date(this.burndownDates.start);
|
||||
this.burndownDates.endDate = new Date(this.burndownDates.end);
|
||||
|
||||
const start = this.burndownDates.startDate.valueOf();
|
||||
const end = this.burndownDates.endDate.valueOf();
|
||||
const now = new Date().valueOf();
|
||||
|
||||
if (start > end) {
|
||||
this.datesError = 'End date must be after start date.';
|
||||
}
|
||||
|
||||
if (start > now) {
|
||||
this.datesError += ' Start date must be today or earlier.';
|
||||
}
|
||||
|
||||
if (end > now) {
|
||||
this.datesError += ' End date must be today or earlier.';
|
||||
}
|
||||
}
|
||||
|
||||
updateAnalytics() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,26 +1,35 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
|
||||
import { SharedModule } from '../shared/shared.module';
|
||||
|
||||
import { DashboardComponent } from './dashboard.component';
|
||||
import { CalendarComponent } from './calendar/calendar.component';
|
||||
import { ChartsComponent } from './charts/charts.component';
|
||||
import { DashboardComponent } from './dashboard.component';
|
||||
import { DashboardService } from './dashboard.service';
|
||||
import { MyItemsComponent } from './my-items/my-items.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
SharedModule
|
||||
],
|
||||
declarations: [
|
||||
DashboardComponent,
|
||||
CalendarComponent,
|
||||
ChartsComponent
|
||||
ChartsComponent,
|
||||
DashboardComponent,
|
||||
MyItemsComponent
|
||||
],
|
||||
providers: [
|
||||
DashboardService
|
||||
],
|
||||
exports: [
|
||||
DashboardComponent,
|
||||
CalendarComponent,
|
||||
ChartsComponent
|
||||
ChartsComponent,
|
||||
DashboardComponent,
|
||||
MyItemsComponent
|
||||
]
|
||||
})
|
||||
export class DashboardModule { }
|
||||
|
33
src/app/dashboard/dashboard.service.ts
Normal file
33
src/app/dashboard/dashboard.service.ts
Normal file
@ -0,0 +1,33 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { LocationStrategy } from '@angular/common';
|
||||
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { map, catchError } from 'rxjs/operators';
|
||||
|
||||
import { ApiResponse } from '../shared/models';
|
||||
import { ApiService } from '../shared/services';
|
||||
|
||||
@Injectable()
|
||||
export class DashboardService extends ApiService {
|
||||
|
||||
constructor(private http: HttpClient, strat: LocationStrategy) {
|
||||
super(strat);
|
||||
}
|
||||
|
||||
getBoardInfo(): Observable<ApiResponse> {
|
||||
return this.http.get(this.apiBase + 'dashboard/boards')
|
||||
.pipe(
|
||||
map((response: ApiResponse) => response),
|
||||
catchError((err) => of(err.error as ApiResponse))
|
||||
);
|
||||
}
|
||||
|
||||
getTaskInfo(): Observable<ApiResponse> {
|
||||
return this.http.get(this.apiBase + 'dashboard/tasks')
|
||||
.pipe(
|
||||
map((response: ApiResponse) => response),
|
||||
catchError((err) => of(err.error as ApiResponse))
|
||||
);
|
||||
}
|
||||
}
|
112
src/app/dashboard/my-items/my-items.component.html
Normal file
112
src/app/dashboard/my-items/my-items.component.html
Normal file
@ -0,0 +1,112 @@
|
||||
<section class="boards-and-tasks">
|
||||
<h2>{{ strings['dashboard_boardsAndTasks'] }}</h2>
|
||||
|
||||
<div class="row">
|
||||
<h3>{{ strings['dashboard_myBoards'] }}</h3>
|
||||
|
||||
<table class="alternating scrollable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ strings['settings_board'] }}</th>
|
||||
<th>{{ strings['settings_columns'] }}</th>
|
||||
<th>{{ strings['settings_categories'] }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody *ngIf="boardsLoading">
|
||||
<tr>
|
||||
<td colspan="3">
|
||||
Loading ...
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<tbody *ngIf="!boardsLoading && !boards">
|
||||
<tr>
|
||||
<td colspan="3">
|
||||
{{ boardsMessage }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<tbody *ngIf="boards && !boardsLoading">
|
||||
<tr *ngFor="let board of boards">
|
||||
<td><a href="./boards/{{ board.id }}">{{ board.name }}</a></td>
|
||||
|
||||
<td>
|
||||
<span *ngFor="let col of board.columns">
|
||||
{{ col.name }}
|
||||
<span class="badge" title="{{ strings['boards_tasksInColumn'] }}">
|
||||
{{ col.tasks }}</span>
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<!-- Ugly here, so it looks good in the browser -->
|
||||
<span *ngFor="let cat of board.categories">{{ cat.name }}
|
||||
<span class="badge"
|
||||
title="{{ strings['dashboard_tasksInCategory'] }}">{{ cat.tasks }}</span></span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<h3>{{ strings['dashboard_myTasks'] }}</h3>
|
||||
|
||||
<table class="alternating scrollable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ strings['settings_board'] }}</th>
|
||||
<th>{{ strings['boards_task'] }}</th>
|
||||
<th>{{ strings['dashboard_details'] }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody *ngIf="tasksLoading">
|
||||
<tr>
|
||||
<td colspan="3">
|
||||
Loading ...
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<tbody *ngIf="!tasksLoading && !tasks">
|
||||
<tr>
|
||||
<td colspan="3">
|
||||
{{ tasksMessage }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<tbody *ngIf="tasks && !tasksLoading">
|
||||
<tr *ngFor="let task of tasks">
|
||||
<td><a href="./boards/{{ task.board_id }}">{{ task.board }}</a></td>
|
||||
|
||||
<td>
|
||||
<!-- <a href="#">An Important Task</a> -->
|
||||
{{ task.title }}
|
||||
<span class="badge" title="Task Color"
|
||||
style="background-color:{{ task.color }}"> </span>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<span class="details">{{ strings['boards_taskColumn'] }}:
|
||||
<em>{{ task.column }}</em></span>
|
||||
<span class="details" *ngIf="task.date_due">{{ strings['boards_taskDateDue'] }}:
|
||||
<em>{{ task.date_due | date }}</em></span>
|
||||
<span class="details" *ngIf="task.points">{{ strings['boards_taskPoints'] }}:
|
||||
<em>{{ task.points }}</em></span>
|
||||
<span class="details" *ngIf="task.attachments.length">{{ strings['boards_taskAttachments'] }}:
|
||||
<em>{{ task.attachments }}</em></span>
|
||||
<span class="details" *ngIf="task.comments.length">{{ strings['boards_taskComments'] }}:
|
||||
<em>{{ task.comments }}</em></span>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</section>
|
35
src/app/dashboard/my-items/my-items.component.ts
Normal file
35
src/app/dashboard/my-items/my-items.component.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import { Component, Input } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'tb-my-items',
|
||||
templateUrl: './my-items.component.html'
|
||||
})
|
||||
export class MyItemsComponent {
|
||||
@Input()
|
||||
boards: any;
|
||||
|
||||
@Input()
|
||||
boardsLoading: boolean;
|
||||
|
||||
@Input()
|
||||
boardsMessage: string;
|
||||
|
||||
@Input()
|
||||
tasks: any;
|
||||
|
||||
@Input()
|
||||
tasksLoading: boolean;
|
||||
|
||||
@Input()
|
||||
tasksMessage: string;
|
||||
|
||||
@Input()
|
||||
strings: any[];
|
||||
|
||||
constructor() {
|
||||
this.boardsLoading = true;
|
||||
this.tasksLoading = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -94,7 +94,7 @@
|
||||
"settings_issueTrackerRegExp": "BUGID RegExp",
|
||||
"settings_addIssueTracker": "Add Issue Tracker",
|
||||
"settings_selectUsers": "Select Users",
|
||||
"settings_boardAdminMessage": "Including a Board Admin, makes them an admin of this board.",
|
||||
"settings_boardAdminMessage": "Including a Board Admin makes them an admin of this board.",
|
||||
"settings_adminAccessMessage": "Administrators have access to all boards and are not listed here.",
|
||||
"settings_saveBoard": "Save Board",
|
||||
"settings_noBoards": "You are not assigned to any boards. Contact an admin user to be added to a board.",
|
||||
@ -223,6 +223,13 @@
|
||||
"boards_sortByPosition": "Position",
|
||||
"boards_sortByDueDate": "Due Date",
|
||||
"boards_sortByLastModified": "Last Modifed",
|
||||
"boards_sortByPoints": "Points"
|
||||
"boards_sortByPoints": "Points",
|
||||
|
||||
"dashboard_boardsAndTasks": "Boards and Tasks",
|
||||
"dashboard_myBoards": "My Boards",
|
||||
"dashboard_myTasks": "My Tasks",
|
||||
"dashboard_tasksInCategory": "Tasks In Category",
|
||||
"dashboard_details": "Details",
|
||||
"dashboard_analytics": "Analytics"
|
||||
}
|
||||
|
||||
|
@ -223,6 +223,12 @@
|
||||
"boards_sortByPosition": "Posición",
|
||||
"boards_sortByDueDate": "Fecha de Vencimiento",
|
||||
"boards_sortByLastModified": "Última Modificación",
|
||||
"boards_sortByPoints": "Puntos"
|
||||
"boards_sortByPoints": "Puntos",
|
||||
|
||||
"dashboard_boardsAndTasks": "Tableros y Tareas",
|
||||
"dashboard_myBoards": "Mis Tableros",
|
||||
"dashboard_myTasks": "Mis Tareas",
|
||||
"dashboard_tasksInCategory": "Tareas En Categoría",
|
||||
"dashboard_details": "Detalles"
|
||||
}
|
||||
|
||||
|
@ -223,5 +223,11 @@
|
||||
"boards_sortByPosition": "position",
|
||||
"boards_sortByDueDate": "date d'échéance",
|
||||
"boards_sortByLastModified": "dernière modification",
|
||||
"boards_sortByPoints": "points"
|
||||
"boards_sortByPoints": "points",
|
||||
|
||||
"dashboard_boardsAndTasks": "Tableaux et Tâches",
|
||||
"dashboard_myBoards": "Mes Tableaux",
|
||||
"dashboard_myTasks": "Mes Tâches",
|
||||
"dashboard_tasksInCategory": "Tâches dans la Catégorie",
|
||||
"dashboard_details": "Détails"
|
||||
}
|
||||
|
@ -3,6 +3,22 @@
|
||||
|
||||
margin: 7px 1em;
|
||||
|
||||
.boards-and-tasks {
|
||||
.scrollable {
|
||||
tbody {
|
||||
display: block;
|
||||
max-height: 26vh;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
thead, tbody tr, tfoot {
|
||||
display: table;
|
||||
table-layout: fixed;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.details {
|
||||
margin-right: 1em;
|
||||
}
|
||||
@ -11,6 +27,11 @@
|
||||
@include grid-column(9 of 18);
|
||||
}
|
||||
|
||||
.error {
|
||||
color: $color-secondary;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.calendar {
|
||||
td {
|
||||
width: 100px;
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
// chartist
|
||||
@import 'chartist-settings';
|
||||
@import '../../node_modules/chartist/dist/chartist.css';
|
||||
@import '../../node_modules/chartist/dist/scss/chartist.scss';
|
||||
|
||||
// highlight.js
|
||||
@import '../../node_modules/highlight.js/styles/tomorrow-night-eighties.css';
|
||||
|
Reference in New Issue
Block a user