Redesign project list view

This commit is contained in:
Frederic Guillot 2017-02-19 18:27:57 -05:00
parent b5c56d4239
commit a43f71dda9
20 changed files with 217 additions and 156 deletions

View File

@ -10,7 +10,7 @@ New features:
Improvements:
* Redesign task list view
* Redesign task list view and project list view
* Allow people to remove missing automatic actions (installed from a removed plugins)
* Improve task view tables
* Simplify automatic actions table

View File

@ -18,24 +18,21 @@ class ProjectListController extends BaseController
public function show()
{
if ($this->userSession->isAdmin()) {
$project_ids = $this->projectModel->getAllIds();
$projectIds = $this->projectModel->getAllIds();
} else {
$project_ids = $this->projectPermissionModel->getProjectIds($this->userSession->getId());
$projectIds = $this->projectPermissionModel->getProjectIds($this->userSession->getId());
}
$nb_projects = count($project_ids);
$paginator = $this->paginator
->setUrl('ProjectListController', 'show')
->setMax(20)
->setOrder('name')
->setQuery($this->projectModel->getQueryColumnStats($project_ids))
->setQuery($this->projectModel->getQueryByProjectIds($projectIds))
->calculate();
$this->response->html($this->helper->layout->app('project_list/show', array(
'paginator' => $paginator,
'nb_projects' => $nb_projects,
'title' => t('Projects').' ('.$nb_projects.')'
$this->response->html($this->helper->layout->app('project_list/listing', array(
'paginator' => $paginator,
'title' => t('Projects') . ' (' . $paginator->getTotal() . ')',
)));
}
}

View File

@ -223,7 +223,7 @@ class ColorModel extends Base
$buffer .= 'border-color: '.$values['border'];
$buffer .= '}';
$buffer .= 'td.color-'.$color.' { background-color: '.$values['background'].'}';
$buffer .= '.task-list-row.color-'.$color.' {border-left: 5px solid '.$values['border'].'}';
$buffer .= '.table-list-row.color-'.$color.' {border-left: 5px solid '.$values['border'].'}';
}
return $buffer;

View File

@ -317,6 +317,26 @@ class ProjectModel extends Base
->callback(array($this, 'applyColumnStats'));
}
/**
* Get query for list of project without column statistics
*
* @access public
* @param array $projectIds
* @return \PicoDb\Table
*/
public function getQueryByProjectIds(array $projectIds)
{
if (empty($projectIds)) {
return $this->db->table(ProjectModel::TABLE)->eq(ProjectModel::TABLE.'.id', 0);
}
return $this->db
->table(ProjectModel::TABLE)
->columns(self::TABLE.'.*', UserModel::TABLE.'.username AS owner_username', UserModel::TABLE.'.name AS owner_name')
->join(UserModel::TABLE, 'id', 'owner_id')
->in(self::TABLE.'.id', $projectIds);
}
/**
* Create a project
*

View File

@ -0,0 +1,12 @@
<div class="table-list-header">
<div class="table-list-header-count">
<?php if ($paginator->getTotal() > 1): ?>
<?= t('%d projects', $paginator->getTotal()) ?>
<?php else: ?>
<?= t('%d project', $paginator->getTotal()) ?>
<?php endif ?>
</div>
<div class="table-list-header-menu">
<?= $this->render('project_list/sort_menu', array('paginator' => $paginator)) ?>
</div>
</div>

View File

@ -0,0 +1,47 @@
<div class="page-header">
<ul>
<?= $this->hook->render('template:project-list:menu:before') ?>
<?php if ($this->user->hasAccess('ProjectCreationController', 'create')): ?>
<li>
<?= $this->modal->medium('plus', t('New project'), 'ProjectCreationController', 'create') ?>
</li>
<?php endif ?>
<?php if ($this->app->config('disable_private_project', 0) == 0): ?>
<li>
<?= $this->modal->medium('lock', t('New private project'), 'ProjectCreationController', 'createPrivate') ?>
</li>
<?php endif ?>
<?php if ($this->user->hasAccess('ProjectUserOverviewController', 'managers')): ?>
<li><?= $this->url->icon('user', t('Users overview'), 'ProjectUserOverviewController', 'managers') ?></li>
<?php endif ?>
<?php if ($this->user->hasAccess('ProjectGanttController', 'show')): ?>
<li><?= $this->url->icon('sliders', t('Projects Gantt chart'), 'ProjectGanttController', 'show') ?></li>
<?php endif ?>
<?= $this->hook->render('template:project-list:menu:after') ?>
</ul>
</div>
<?php if ($paginator->isEmpty()): ?>
<p class="alert"><?= t('There is no project.') ?></p>
<?php else: ?>
<div class="table-list">
<?= $this->render('project_list/header', array('paginator' => $paginator)) ?>
<?php foreach ($paginator->getCollection() as $project): ?>
<div class="table-list-row table-border-left">
<?= $this->render('project_list/project_title', array(
'project' => $project,
)) ?>
<?= $this->render('project_list/project_details', array(
'project' => $project,
)) ?>
</div>
<?php endforeach ?>
</div>
<?= $paginator ?>
<?php endif ?>

View File

@ -0,0 +1,15 @@
<div class="table-list-details">
<ul>
<?php if ($project['owner_id'] > 0): ?>
<li><?= $this->text->e($project['owner_name'] ?: $project['owner_username']) ?></li>
<?php endif ?>
<?php if ($project['start_date']): ?>
<li><?= t('Start Date: %s', $this->dt->date($project['start_date'])) ?></li>
<?php endif ?>
<?php if ($project['end_date']): ?>
<li><?= t('End Date: %s', $this->dt->date($project['end_date'])) ?></li>
<?php endif ?>
</ul>
</div>

View File

@ -0,0 +1,33 @@
<div>
<?php if ($this->user->hasProjectAccess('ProjectViewController', 'show', $project['id'])): ?>
<?= $this->render('project/dropdown', array('project' => $project)) ?>
<?php else: ?>
<strong><?= '#'.$project['id'] ?></strong>
<?php endif ?>
<span class="table-list-title <?= $project['is_active'] == 0 ? 'status-closed' : '' ?>">
<?= $this->url->link($this->text->e($project['name']), 'BoardViewController', 'show', array('project_id' => $project['id'])) ?>
</span>
<?php if ($project['is_public']): ?>
<i class="fa fa-share-alt fa-fw" title="<?= t('Shared project') ?>"></i>
<?php endif ?>
<?php if ($project['is_private']): ?>
<i class="fa fa-lock fa-fw" title="<?= t('Private project') ?>"></i>
<?php endif ?>
<?php if ($this->user->hasAccess('ProjectUserOverviewController', 'managers')): ?>
<span class="tooltip" title="<?= t('Members') ?>" data-href="<?= $this->url->href('ProjectUserOverviewController', 'users', array('project_id' => $project['id'])) ?>"><i class="fa fa-users"></i></span>&nbsp;
<?php endif ?>
<?php if (! empty($project['description'])): ?>
<span class="tooltip" title="<?= $this->text->markdownAttribute($project['description']) ?>">
<i class="fa fa-info-circle"></i>
</span>
<?php endif ?>
<?php if ($project['is_active'] == 0): ?>
<i class="fa fa-ban fa-fw" aria-hidden="true" title="<?= t('Closed') ?>"></i><?= t('Closed') ?>
<?php endif ?>
</div>

View File

@ -1,101 +0,0 @@
<section id="main">
<div class="page-header">
<ul>
<?= $this->hook->render('template:project-list:menu:before') ?>
<?php if ($this->user->hasAccess('ProjectCreationController', 'create')): ?>
<li>
<?= $this->modal->medium('plus', t('New project'), 'ProjectCreationController', 'create') ?>
</li>
<?php endif ?>
<?php if ($this->app->config('disable_private_project', 0) == 0): ?>
<li>
<?= $this->modal->medium('lock', t('New private project'), 'ProjectCreationController', 'createPrivate') ?>
</li>
<?php endif ?>
<?php if ($this->user->hasAccess('ProjectUserOverviewController', 'managers')): ?>
<li><?= $this->url->icon('user', t('Users overview'), 'ProjectUserOverviewController', 'managers') ?></li>
<?php endif ?>
<?php if ($this->user->hasAccess('ProjectGanttController', 'show')): ?>
<li><?= $this->url->icon('sliders', t('Projects Gantt chart'), 'ProjectGanttController', 'show') ?></li>
<?php endif ?>
<?= $this->hook->render('template:project-list:menu:after') ?>
</ul>
</div>
<?php if ($paginator->isEmpty()): ?>
<p class="alert"><?= t('No project') ?></p>
<?php else: ?>
<table class="table-striped table-scrolling">
<tr>
<th class="column-5"><?= $paginator->order(t('Id'), 'id') ?></th>
<th class="column-8"><?= $paginator->order(t('Status'), 'is_active') ?></th>
<th class="column-15"><?= $paginator->order(t('Project'), 'name') ?></th>
<th class="column-10"><?= $paginator->order(t('Start date'), 'start_date') ?></th>
<th class="column-10"><?= $paginator->order(t('End date'), 'end_date') ?></th>
<th class="column-15"><?= $paginator->order(t('Owner'), 'owner_id') ?></th>
<?php if ($this->user->hasAccess('ProjectUserOverviewController', 'managers')): ?>
<th class="column-10"><?= t('Users') ?></th>
<?php endif ?>
<th><?= t('Columns') ?></th>
</tr>
<?php foreach ($paginator->getCollection() as $project): ?>
<tr>
<td>
<?= $this->render('project/dropdown', array('project' => $project)) ?>
</td>
<td>
<?php if ($project['is_active']): ?>
<?= t('Open') ?>
<?php else: ?>
<?= t('Closed') ?>
<?php endif ?>
</td>
<td>
<?= $this->url->link($this->text->e($project['name']), 'BoardViewController', 'show', array('project_id' => $project['id'])) ?>
<?php if ($project['is_public']): ?>
<i class="fa fa-share-alt fa-fw" title="<?= t('Shared project') ?>"></i>
<?php endif ?>
<?php if ($project['is_private']): ?>
<i class="fa fa-lock fa-fw" title="<?= t('Private project') ?>"></i>
<?php endif ?>
<?php if (! empty($project['description'])): ?>
<span class="tooltip" title="<?= $this->text->markdownAttribute($project['description']) ?>">
<i class="fa fa-info-circle"></i>
</span>
<?php endif ?>
</td>
<td>
<?= $this->dt->date($project['start_date']) ?>
</td>
<td>
<?= $this->dt->date($project['end_date']) ?>
</td>
<td>
<?php if ($project['owner_id'] > 0): ?>
<?= $this->text->e($project['owner_name'] ?: $project['owner_username']) ?>
<?php endif ?>
</td>
<?php if ($this->user->hasAccess('ProjectUserOverviewController', 'managers')): ?>
<td>
<i class="fa fa-users fa-fw"></i>
<span class="tooltip" title="<?= t('Members') ?>" data-href="<?= $this->url->href('ProjectUserOverviewController', 'users', array('project_id' => $project['id'])) ?>"><?= t('Members') ?></span>
</td>
<?php endif ?>
<td class="dashboard-project-stats">
<?php foreach ($project['columns'] as $column): ?>
<strong title="<?= t('Task count') ?>"><?= $column['nb_open_tasks'] ?></strong>
<small><?= $this->text->e($column['title']) ?></small>
<?php endforeach ?>
</td>
</tr>
<?php endforeach ?>
</table>
<?= $paginator ?>
<?php endif ?>
</section>

View File

@ -0,0 +1,26 @@
<div class="dropdown">
<a href="#" class="dropdown-menu dropdown-menu-link-icon"><strong><?= t('Sort') ?> <i class="fa fa-caret-down"></i></strong></a>
<ul>
<li>
<?= $paginator->order(t('Project ID'), \Kanboard\Model\ProjectModel::TABLE.'.id') ?>
</li>
<li>
<?= $paginator->order(t('Project Name'), \Kanboard\Model\ProjectModel::TABLE.'.name') ?>
</li>
<li>
<?= $paginator->order(t('Status'), \Kanboard\Model\ProjectModel::TABLE.'.is_active') ?>
</li>
<li>
<?= $paginator->order(t('Start Date'), \Kanboard\Model\ProjectModel::TABLE.'.start_date') ?>
</li>
<li>
<?= $paginator->order(t('End Date'), \Kanboard\Model\ProjectModel::TABLE.'.end_date') ?>
</li>
<li>
<?= $paginator->order(t('Public'), \Kanboard\Model\ProjectModel::TABLE.'.is_public') ?>
</li>
<li>
<?= $paginator->order(t('Private'), \Kanboard\Model\ProjectModel::TABLE.'.is_private') ?>
</li>
</ul>
</div>

View File

@ -1,12 +1,12 @@
<div class="task-list-header">
<div class="task-list-header-count">
<div class="table-list-header">
<div class="table-list-header-count">
<?php if ($paginator->getTotal() > 1): ?>
<?= t('%d tasks', $paginator->getTotal()) ?>
<?php else: ?>
<?= t('%d task', $paginator->getTotal()) ?>
<?php endif ?>
</div>
<div class="task-list-header-menu">
<div class="table-list-header-menu">
<?= $this->render('task_list/sort_menu', array('paginator' => $paginator)) ?>
</div>
</div>

View File

@ -4,10 +4,10 @@
<?php if ($paginator->isEmpty()): ?>
<p class="alert"><?= t('No tasks found.') ?></p>
<?php elseif (! $paginator->isEmpty()): ?>
<div class="task-list">
<div class="table-list">
<?= $this->render('task_list/header', array('paginator' => $paginator)) ?>
<?php foreach ($paginator->getCollection() as $task): ?>
<div class="task-list-row color-<?= $task['color_id'] ?>">
<div class="table-list-row color-<?= $task['color_id'] ?>">
<?= $this->render('task_list/task_title', array(
'task' => $task,
)) ?>

View File

@ -17,4 +17,4 @@
) ?><span class="task-avatar-assignee"><?= $this->text->e($task['assignee_name'] ?: $task['assignee_username']) ?></span>
</span>
</div>
<?php endif ?>
<?php endif ?>

View File

@ -1,4 +1,4 @@
<div class="task-list-details">
<div class="table-list-details">
<?= $this->text->e($task['project_name']) ?> &gt;
<?= $this->text->e($task['swimlane_name']) ?> &gt;
<?= $this->text->e($task['column_name']) ?>
@ -20,4 +20,4 @@
<?php endif ?>
</span>
<?php endif ?>
</div>
</div>

View File

@ -5,7 +5,7 @@
<strong><?= '#'.$task['id'] ?></strong>
<?php endif ?>
<span class="task-list-title <?= $task['is_active'] == 0 ? 'task-closed' : '' ?>">
<span class="table-list-title <?= $task['is_active'] == 0 ? 'status-closed' : '' ?>">
<?= $this->url->link($this->text->e($task['title']), 'TaskViewController', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id'])) ?>
</span>
</div>

File diff suppressed because one or more lines are too long

View File

@ -1,28 +1,32 @@
@import variables
.task-list
.table-list
font-size: size('compact')
margin-bottom: 20px
.task-list-header
.table-list-header
background: bg-color('primary')
border: 1px solid #e5e5e5
border-radius: 5px 5px 0 0
line-height: 35px
padding-left: 3px
padding-right: 3px
.task-list-header-count
.table-list-header-count
color: #767676
display: inline-block
float: left
.task-list-header-menu
.table-list-header-menu
text-align: right
.task-list-row
.table-list-row
padding-left: 3px
padding-right: 3px
border-bottom: 1px solid #e5e5e5
border-right: 1px solid #e5e5e5
&.table-border-left
border-left: 1px solid #e5e5e5
&:nth-child(odd)
background: bg-color('lighter')
@ -34,10 +38,11 @@
border-bottom: 1px solid map-get($highlight-colors, 'border')
border-right: 1px solid map-get($highlight-colors, 'border')
.task-list-title
.table-list-title
font-weight: 500
&.task-closed
&.status-closed
text-decoration: line-through
margin-right: 10px
a
font-style: italic
a
@ -46,21 +51,14 @@
&:hover, &:focus
text-decoration: underline
.task-list-details
.table-list-details
color: color('light')
font-weight: 300
line-height: 30px
.task-list-avatars
display: inline-block
float: left
@include sm-device
float: none
display: block
.task-avatar-assignee
font-weight: 300
color: color('light')
&:hover
.task-avatar-assignee
font-weight: 400
color: color('dark')
li
display: inline
list-style-type: none
&:after
content: ', '
&:last-child:after
content: ''

View File

@ -0,0 +1,24 @@
@import variables
.task-board-avatars
text-align: right
float: right
.task-board-change-assignee
&:hover
opacity: 0.6
cursor: pointer
.task-list-avatars
display: inline-block
float: left
@include sm-device
float: none
display: block
.task-avatar-assignee
font-weight: 300
color: color('light')
&:hover
.task-avatar-assignee
font-weight: 400
color: color('dark')

View File

@ -1,10 +0,0 @@
@import variables
.task-board-avatars
text-align: right
float: right
.task-board-change-assignee
&:hover
opacity: 0.6
cursor: pointer

View File

@ -4,6 +4,7 @@
@import title
@import table
@import table_drag_and_drop
@import table_list
@import form
@import input_addon
@import icon
@ -33,12 +34,11 @@
@import board
@import task_board
@import task_board_saving_state
@import task_board_avatar
@import task_avatars
@import task_icons
@import task_icon_age
@import task_category
@import task_date
@import task_list
@import task_tags
@import task_summary
@import task_form