Added search in activity stream
This commit is contained in:
@@ -46,4 +46,22 @@ class Search extends Base
|
||||
'title' => t('Search tasks').($nb_tasks > 0 ? ' ('.$nb_tasks.')' : '')
|
||||
)));
|
||||
}
|
||||
|
||||
public function activity()
|
||||
{
|
||||
$search = urldecode($this->request->getStringParam('search'));
|
||||
$events = $this->helper->projectActivity->searchEvents($search);
|
||||
$nb_events = count($events);
|
||||
|
||||
$this->response->html($this->helper->layout->app('search/activity', array(
|
||||
'values' => array(
|
||||
'search' => $search,
|
||||
'controller' => 'search',
|
||||
'action' => 'activity',
|
||||
),
|
||||
'title' => t('Search in activity stream').($nb_events > 0 ? ' ('.$nb_events.')' : ''),
|
||||
'nb_events' => $nb_events,
|
||||
'events' => $events,
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
103
app/Filter/BaseDateFilter.php
Normal file
103
app/Filter/BaseDateFilter.php
Normal file
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
namespace Kanboard\Filter;
|
||||
|
||||
use Kanboard\Core\DateParser;
|
||||
|
||||
/**
|
||||
* Base date filter class
|
||||
*
|
||||
* @package filter
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
abstract class BaseDateFilter extends BaseFilter
|
||||
{
|
||||
/**
|
||||
* DateParser object
|
||||
*
|
||||
* @access protected
|
||||
* @var DateParser
|
||||
*/
|
||||
protected $dateParser;
|
||||
|
||||
/**
|
||||
* Set DateParser object
|
||||
*
|
||||
* @access public
|
||||
* @param DateParser $dateParser
|
||||
* @return $this
|
||||
*/
|
||||
public function setDateParser(DateParser $dateParser)
|
||||
{
|
||||
$this->dateParser = $dateParser;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse operator in the input string
|
||||
*
|
||||
* @access protected
|
||||
* @return string
|
||||
*/
|
||||
protected function parseOperator()
|
||||
{
|
||||
$operators = array(
|
||||
'<=' => 'lte',
|
||||
'>=' => 'gte',
|
||||
'<' => 'lt',
|
||||
'>' => 'gt',
|
||||
);
|
||||
|
||||
foreach ($operators as $operator => $method) {
|
||||
if (strpos($this->value, $operator) === 0) {
|
||||
$this->value = substr($this->value, strlen($operator));
|
||||
return $method;
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a date filter
|
||||
*
|
||||
* @access protected
|
||||
* @param string $field
|
||||
*/
|
||||
protected function applyDateFilter($field)
|
||||
{
|
||||
$method = $this->parseOperator();
|
||||
$timestamp = $this->dateParser->getTimestampFromIsoFormat($this->value);
|
||||
|
||||
if ($method !== '') {
|
||||
$this->query->$method($field, $this->getTimestampFromOperator($method, $timestamp));
|
||||
} else {
|
||||
$this->query->gte($field, $timestamp);
|
||||
$this->query->lte($field, $timestamp + 86399);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get timestamp from the operator
|
||||
*
|
||||
* @access public
|
||||
* @param string $method
|
||||
* @param integer $timestamp
|
||||
* @return integer
|
||||
*/
|
||||
protected function getTimestampFromOperator($method, $timestamp)
|
||||
{
|
||||
switch ($method) {
|
||||
case 'lte':
|
||||
return $timestamp + 86399;
|
||||
case 'lt':
|
||||
return $timestamp;
|
||||
case 'gte':
|
||||
return $timestamp;
|
||||
case 'gt':
|
||||
return $timestamp + 86400;
|
||||
}
|
||||
|
||||
return $timestamp;
|
||||
}
|
||||
}
|
||||
@@ -72,48 +72,4 @@ abstract class BaseFilter
|
||||
$this->value = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse operator in the input string
|
||||
*
|
||||
* @access protected
|
||||
* @return string
|
||||
*/
|
||||
protected function parseOperator()
|
||||
{
|
||||
$operators = array(
|
||||
'<=' => 'lte',
|
||||
'>=' => 'gte',
|
||||
'<' => 'lt',
|
||||
'>' => 'gt',
|
||||
);
|
||||
|
||||
foreach ($operators as $operator => $method) {
|
||||
if (strpos($this->value, $operator) === 0) {
|
||||
$this->value = substr($this->value, strlen($operator));
|
||||
return $method;
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a date filter
|
||||
*
|
||||
* @access protected
|
||||
* @param string $field
|
||||
*/
|
||||
protected function applyDateFilter($field)
|
||||
{
|
||||
$timestamp = strtotime($this->value);
|
||||
$method = $this->parseOperator();
|
||||
|
||||
if ($method !== '') {
|
||||
$this->query->$method($field, $timestamp);
|
||||
} else {
|
||||
$this->query->gte($field, $timestamp);
|
||||
$this->query->lte($field, $timestamp + 86399);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
38
app/Filter/ProjectActivityCreationDateFilter.php
Normal file
38
app/Filter/ProjectActivityCreationDateFilter.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace Kanboard\Filter;
|
||||
|
||||
use Kanboard\Core\Filter\FilterInterface;
|
||||
use Kanboard\Model\ProjectActivity;
|
||||
|
||||
/**
|
||||
* Filter activity events by creation date
|
||||
*
|
||||
* @package filter
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class ProjectActivityCreationDateFilter extends BaseDateFilter implements FilterInterface
|
||||
{
|
||||
/**
|
||||
* Get search attribute
|
||||
*
|
||||
* @access public
|
||||
* @return string[]
|
||||
*/
|
||||
public function getAttributes()
|
||||
{
|
||||
return array('created');
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply filter
|
||||
*
|
||||
* @access public
|
||||
* @return FilterInterface
|
||||
*/
|
||||
public function apply()
|
||||
{
|
||||
$this->applyDateFilter(ProjectActivity::TABLE.'.date_creation');
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
65
app/Filter/ProjectActivityCreatorFilter.php
Normal file
65
app/Filter/ProjectActivityCreatorFilter.php
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Kanboard\Filter;
|
||||
|
||||
use Kanboard\Core\Filter\FilterInterface;
|
||||
use Kanboard\Model\ProjectActivity;
|
||||
|
||||
/**
|
||||
* Filter activity events by creator
|
||||
*
|
||||
* @package filter
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class ProjectActivityCreatorFilter extends BaseFilter implements FilterInterface
|
||||
{
|
||||
/**
|
||||
* Current user id
|
||||
*
|
||||
* @access private
|
||||
* @var int
|
||||
*/
|
||||
private $currentUserId = 0;
|
||||
|
||||
/**
|
||||
* Set current user id
|
||||
*
|
||||
* @access public
|
||||
* @param integer $userId
|
||||
* @return TaskAssigneeFilter
|
||||
*/
|
||||
public function setCurrentUserId($userId)
|
||||
{
|
||||
$this->currentUserId = $userId;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get search attribute
|
||||
*
|
||||
* @access public
|
||||
* @return string[]
|
||||
*/
|
||||
public function getAttributes()
|
||||
{
|
||||
return array('creator');
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply filter
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function apply()
|
||||
{
|
||||
if ($this->value === 'me') {
|
||||
$this->query->eq(ProjectActivity::TABLE . '.creator_id', $this->currentUserId);
|
||||
} else {
|
||||
$this->query->beginOr();
|
||||
$this->query->ilike('uc.username', '%'.$this->value.'%');
|
||||
$this->query->ilike('uc.name', '%'.$this->value.'%');
|
||||
$this->query->closeOr();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,7 @@ class ProjectActivityProjectIdsFilter extends BaseFilter implements FilterInterf
|
||||
*/
|
||||
public function getAttributes()
|
||||
{
|
||||
return array('project_ids');
|
||||
return array('projects');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
38
app/Filter/ProjectActivityProjectNameFilter.php
Normal file
38
app/Filter/ProjectActivityProjectNameFilter.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace Kanboard\Filter;
|
||||
|
||||
use Kanboard\Core\Filter\FilterInterface;
|
||||
use Kanboard\Model\Project;
|
||||
|
||||
/**
|
||||
* Filter activity events by project name
|
||||
*
|
||||
* @package filter
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class ProjectActivityProjectNameFilter extends BaseFilter implements FilterInterface
|
||||
{
|
||||
/**
|
||||
* Get search attribute
|
||||
*
|
||||
* @access public
|
||||
* @return string[]
|
||||
*/
|
||||
public function getAttributes()
|
||||
{
|
||||
return array('project');
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply filter
|
||||
*
|
||||
* @access public
|
||||
* @return FilterInterface
|
||||
*/
|
||||
public function apply()
|
||||
{
|
||||
$this->query->ilike(Project::TABLE.'.name', '%'.$this->value.'%');
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
43
app/Filter/ProjectActivityTaskStatusFilter.php
Normal file
43
app/Filter/ProjectActivityTaskStatusFilter.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace Kanboard\Filter;
|
||||
|
||||
use Kanboard\Core\Filter\FilterInterface;
|
||||
use Kanboard\Model\Task;
|
||||
|
||||
/**
|
||||
* Filter activity events by task status
|
||||
*
|
||||
* @package filter
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class ProjectActivityTaskStatusFilter extends BaseFilter implements FilterInterface
|
||||
{
|
||||
/**
|
||||
* Get search attribute
|
||||
*
|
||||
* @access public
|
||||
* @return string[]
|
||||
*/
|
||||
public function getAttributes()
|
||||
{
|
||||
return array('status');
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply filter
|
||||
*
|
||||
* @access public
|
||||
* @return FilterInterface
|
||||
*/
|
||||
public function apply()
|
||||
{
|
||||
if ($this->value === 'open') {
|
||||
$this->query->eq(Task::TABLE.'.is_active', Task::STATUS_OPEN);
|
||||
} elseif ($this->value === 'closed') {
|
||||
$this->query->eq(Task::TABLE.'.is_active', Task::STATUS_CLOSED);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@
|
||||
namespace Kanboard\Filter;
|
||||
|
||||
use Kanboard\Core\Filter\FilterInterface;
|
||||
use Kanboard\Model\Task;
|
||||
|
||||
/**
|
||||
* Filter activity events by task title
|
||||
@@ -11,7 +10,7 @@ use Kanboard\Model\Task;
|
||||
* @package filter
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class ProjectActivityTaskTitleFilter extends BaseFilter implements FilterInterface
|
||||
class ProjectActivityTaskTitleFilter extends TaskTitleFilter implements FilterInterface
|
||||
{
|
||||
/**
|
||||
* Get search attribute
|
||||
@@ -23,16 +22,4 @@ class ProjectActivityTaskTitleFilter extends BaseFilter implements FilterInterfa
|
||||
{
|
||||
return array('title');
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply filter
|
||||
*
|
||||
* @access public
|
||||
* @return FilterInterface
|
||||
*/
|
||||
public function apply()
|
||||
{
|
||||
$this->query->ilike(Task::TABLE.'.title', '%'.$this->value.'%');
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ use Kanboard\Model\Task;
|
||||
* @package filter
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class TaskCompletionDateFilter extends BaseFilter implements FilterInterface
|
||||
class TaskCompletionDateFilter extends BaseDateFilter implements FilterInterface
|
||||
{
|
||||
/**
|
||||
* Get search attribute
|
||||
|
||||
@@ -11,7 +11,7 @@ use Kanboard\Model\Task;
|
||||
* @package filter
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class TaskCreationDateFilter extends BaseFilter implements FilterInterface
|
||||
class TaskCreationDateFilter extends BaseDateFilter implements FilterInterface
|
||||
{
|
||||
/**
|
||||
* Get search attribute
|
||||
|
||||
@@ -11,7 +11,7 @@ use Kanboard\Model\Task;
|
||||
* @package filter
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class TaskDueDateFilter extends BaseFilter implements FilterInterface
|
||||
class TaskDueDateFilter extends BaseDateFilter implements FilterInterface
|
||||
{
|
||||
/**
|
||||
* Get search attribute
|
||||
|
||||
@@ -11,7 +11,7 @@ use Kanboard\Model\Task;
|
||||
* @package filter
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class TaskModificationDateFilter extends BaseFilter implements FilterInterface
|
||||
class TaskModificationDateFilter extends BaseDateFilter implements FilterInterface
|
||||
{
|
||||
/**
|
||||
* Get search attribute
|
||||
|
||||
@@ -32,7 +32,12 @@ class TaskProjectsFilter extends BaseFilter implements FilterInterface
|
||||
*/
|
||||
public function apply()
|
||||
{
|
||||
$this->query->in(Task::TABLE.'.project_id', $this->value);
|
||||
if (empty($this->value)) {
|
||||
$this->query->eq(Task::TABLE.'.project_id', 0);
|
||||
} else {
|
||||
$this->query->in(Task::TABLE.'.project_id', $this->value);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ use Kanboard\Model\Task;
|
||||
* @package filter
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class TaskStartDateFilter extends BaseFilter implements FilterInterface
|
||||
class TaskStartDateFilter extends BaseDateFilter implements FilterInterface
|
||||
{
|
||||
/**
|
||||
* Get search attribute
|
||||
|
||||
@@ -17,6 +17,33 @@ use Kanboard\Model\ProjectActivity;
|
||||
*/
|
||||
class ProjectActivityHelper extends Base
|
||||
{
|
||||
/**
|
||||
* Search events
|
||||
*
|
||||
* @access public
|
||||
* @param string $search
|
||||
* @return array
|
||||
*/
|
||||
public function searchEvents($search)
|
||||
{
|
||||
$projects = $this->projectUserRole->getProjectsByUser($this->userSession->getId());
|
||||
$events = array();
|
||||
|
||||
if ($search !== '') {
|
||||
$queryBuilder = $this->projectActivityLexer->build($search);
|
||||
$queryBuilder
|
||||
->withFilter(new ProjectActivityProjectIdsFilter(array_keys($projects)))
|
||||
->getQuery()
|
||||
->desc(ProjectActivity::TABLE.'.id')
|
||||
->limit(500)
|
||||
;
|
||||
|
||||
$events = $queryBuilder->format(new ProjectActivityEventFormatter($this->container));
|
||||
}
|
||||
|
||||
return $events;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get project activity events
|
||||
*
|
||||
|
||||
@@ -1153,4 +1153,14 @@ return array(
|
||||
// 'Upload my avatar image' => '',
|
||||
// 'Remove my image' => '',
|
||||
// 'The OAuth2 state parameter is invalid' => '',
|
||||
// 'User not found.' => '',
|
||||
// 'Search in activity stream' => '',
|
||||
// 'My activities' => '',
|
||||
// 'Activity until yesterday' => '',
|
||||
// 'Activity until today' => '',
|
||||
// 'Search by creator: ' => '',
|
||||
// 'Search by creation date: ' => '',
|
||||
// 'Search by task status: ' => '',
|
||||
// 'Search by task title: ' => '',
|
||||
// 'Activity stream search' => '',
|
||||
);
|
||||
|
||||
@@ -1153,4 +1153,14 @@ return array(
|
||||
// 'Upload my avatar image' => '',
|
||||
// 'Remove my image' => '',
|
||||
// 'The OAuth2 state parameter is invalid' => '',
|
||||
// 'User not found.' => '',
|
||||
// 'Search in activity stream' => '',
|
||||
// 'My activities' => '',
|
||||
// 'Activity until yesterday' => '',
|
||||
// 'Activity until today' => '',
|
||||
// 'Search by creator: ' => '',
|
||||
// 'Search by creation date: ' => '',
|
||||
// 'Search by task status: ' => '',
|
||||
// 'Search by task title: ' => '',
|
||||
// 'Activity stream search' => '',
|
||||
);
|
||||
|
||||
@@ -1153,4 +1153,14 @@ return array(
|
||||
// 'Upload my avatar image' => '',
|
||||
// 'Remove my image' => '',
|
||||
// 'The OAuth2 state parameter is invalid' => '',
|
||||
// 'User not found.' => '',
|
||||
// 'Search in activity stream' => '',
|
||||
// 'My activities' => '',
|
||||
// 'Activity until yesterday' => '',
|
||||
// 'Activity until today' => '',
|
||||
// 'Search by creator: ' => '',
|
||||
// 'Search by creation date: ' => '',
|
||||
// 'Search by task status: ' => '',
|
||||
// 'Search by task title: ' => '',
|
||||
// 'Activity stream search' => '',
|
||||
);
|
||||
|
||||
@@ -1153,4 +1153,14 @@ return array(
|
||||
'Upload my avatar image' => 'Mein Avatar Bild hochladen',
|
||||
'Remove my image' => 'Mein Bild entfernen',
|
||||
'The OAuth2 state parameter is invalid' => 'Der OAuth2 Statusparameter ist ungültig',
|
||||
// 'User not found.' => '',
|
||||
// 'Search in activity stream' => '',
|
||||
// 'My activities' => '',
|
||||
// 'Activity until yesterday' => '',
|
||||
// 'Activity until today' => '',
|
||||
// 'Search by creator: ' => '',
|
||||
// 'Search by creation date: ' => '',
|
||||
// 'Search by task status: ' => '',
|
||||
// 'Search by task title: ' => '',
|
||||
// 'Activity stream search' => '',
|
||||
);
|
||||
|
||||
@@ -1153,4 +1153,14 @@ return array(
|
||||
// 'Upload my avatar image' => '',
|
||||
// 'Remove my image' => '',
|
||||
// 'The OAuth2 state parameter is invalid' => '',
|
||||
// 'User not found.' => '',
|
||||
// 'Search in activity stream' => '',
|
||||
// 'My activities' => '',
|
||||
// 'Activity until yesterday' => '',
|
||||
// 'Activity until today' => '',
|
||||
// 'Search by creator: ' => '',
|
||||
// 'Search by creation date: ' => '',
|
||||
// 'Search by task status: ' => '',
|
||||
// 'Search by task title: ' => '',
|
||||
// 'Activity stream search' => '',
|
||||
);
|
||||
|
||||
@@ -1153,4 +1153,14 @@ return array(
|
||||
// 'Upload my avatar image' => '',
|
||||
// 'Remove my image' => '',
|
||||
// 'The OAuth2 state parameter is invalid' => '',
|
||||
// 'User not found.' => '',
|
||||
// 'Search in activity stream' => '',
|
||||
// 'My activities' => '',
|
||||
// 'Activity until yesterday' => '',
|
||||
// 'Activity until today' => '',
|
||||
// 'Search by creator: ' => '',
|
||||
// 'Search by creation date: ' => '',
|
||||
// 'Search by task status: ' => '',
|
||||
// 'Search by task title: ' => '',
|
||||
// 'Activity stream search' => '',
|
||||
);
|
||||
|
||||
@@ -1153,4 +1153,14 @@ return array(
|
||||
// 'Upload my avatar image' => '',
|
||||
// 'Remove my image' => '',
|
||||
// 'The OAuth2 state parameter is invalid' => '',
|
||||
// 'User not found.' => '',
|
||||
// 'Search in activity stream' => '',
|
||||
// 'My activities' => '',
|
||||
// 'Activity until yesterday' => '',
|
||||
// 'Activity until today' => '',
|
||||
// 'Search by creator: ' => '',
|
||||
// 'Search by creation date: ' => '',
|
||||
// 'Search by task status: ' => '',
|
||||
// 'Search by task title: ' => '',
|
||||
// 'Activity stream search' => '',
|
||||
);
|
||||
|
||||
@@ -1153,4 +1153,14 @@ return array(
|
||||
'Upload my avatar image' => 'Uploader mon image d\'avatar',
|
||||
'Remove my image' => 'Supprimer mon image',
|
||||
'The OAuth2 state parameter is invalid' => 'Le paramètre "state" de OAuth2 est invalide',
|
||||
'User not found.' => 'Utilisateur introuvable.',
|
||||
'Search in activity stream' => 'Chercher dans le flux d\'activité',
|
||||
'My activities' => 'Mes activités',
|
||||
'Activity until yesterday' => 'Activités jusqu\'à hier',
|
||||
'Activity until today' => 'Activités jusqu\'à aujourd\'hui',
|
||||
'Search by creator: ' => 'Rechercher par créateur : ',
|
||||
'Search by creation date: ' => 'Rechercher par date de création : ',
|
||||
'Search by task status: ' => 'Rechercher par le statut des tâches : ',
|
||||
'Search by task title: ' => 'Rechercher par le titre des tâches : ',
|
||||
'Activity stream search' => 'Recherche dans le flux d\'activité',
|
||||
);
|
||||
|
||||
@@ -1153,4 +1153,14 @@ return array(
|
||||
// 'Upload my avatar image' => '',
|
||||
// 'Remove my image' => '',
|
||||
// 'The OAuth2 state parameter is invalid' => '',
|
||||
// 'User not found.' => '',
|
||||
// 'Search in activity stream' => '',
|
||||
// 'My activities' => '',
|
||||
// 'Activity until yesterday' => '',
|
||||
// 'Activity until today' => '',
|
||||
// 'Search by creator: ' => '',
|
||||
// 'Search by creation date: ' => '',
|
||||
// 'Search by task status: ' => '',
|
||||
// 'Search by task title: ' => '',
|
||||
// 'Activity stream search' => '',
|
||||
);
|
||||
|
||||
@@ -1153,4 +1153,14 @@ return array(
|
||||
// 'Upload my avatar image' => '',
|
||||
// 'Remove my image' => '',
|
||||
// 'The OAuth2 state parameter is invalid' => '',
|
||||
// 'User not found.' => '',
|
||||
// 'Search in activity stream' => '',
|
||||
// 'My activities' => '',
|
||||
// 'Activity until yesterday' => '',
|
||||
// 'Activity until today' => '',
|
||||
// 'Search by creator: ' => '',
|
||||
// 'Search by creation date: ' => '',
|
||||
// 'Search by task status: ' => '',
|
||||
// 'Search by task title: ' => '',
|
||||
// 'Activity stream search' => '',
|
||||
);
|
||||
|
||||
@@ -1153,4 +1153,14 @@ return array(
|
||||
// 'Upload my avatar image' => '',
|
||||
// 'Remove my image' => '',
|
||||
// 'The OAuth2 state parameter is invalid' => '',
|
||||
// 'User not found.' => '',
|
||||
// 'Search in activity stream' => '',
|
||||
// 'My activities' => '',
|
||||
// 'Activity until yesterday' => '',
|
||||
// 'Activity until today' => '',
|
||||
// 'Search by creator: ' => '',
|
||||
// 'Search by creation date: ' => '',
|
||||
// 'Search by task status: ' => '',
|
||||
// 'Search by task title: ' => '',
|
||||
// 'Activity stream search' => '',
|
||||
);
|
||||
|
||||
@@ -1153,4 +1153,14 @@ return array(
|
||||
// 'Upload my avatar image' => '',
|
||||
// 'Remove my image' => '',
|
||||
// 'The OAuth2 state parameter is invalid' => '',
|
||||
// 'User not found.' => '',
|
||||
// 'Search in activity stream' => '',
|
||||
// 'My activities' => '',
|
||||
// 'Activity until yesterday' => '',
|
||||
// 'Activity until today' => '',
|
||||
// 'Search by creator: ' => '',
|
||||
// 'Search by creation date: ' => '',
|
||||
// 'Search by task status: ' => '',
|
||||
// 'Search by task title: ' => '',
|
||||
// 'Activity stream search' => '',
|
||||
);
|
||||
|
||||
@@ -1153,4 +1153,14 @@ return array(
|
||||
// 'Upload my avatar image' => '',
|
||||
// 'Remove my image' => '',
|
||||
// 'The OAuth2 state parameter is invalid' => '',
|
||||
// 'User not found.' => '',
|
||||
// 'Search in activity stream' => '',
|
||||
// 'My activities' => '',
|
||||
// 'Activity until yesterday' => '',
|
||||
// 'Activity until today' => '',
|
||||
// 'Search by creator: ' => '',
|
||||
// 'Search by creation date: ' => '',
|
||||
// 'Search by task status: ' => '',
|
||||
// 'Search by task title: ' => '',
|
||||
// 'Activity stream search' => '',
|
||||
);
|
||||
|
||||
@@ -1153,4 +1153,14 @@ return array(
|
||||
// 'Upload my avatar image' => '',
|
||||
// 'Remove my image' => '',
|
||||
// 'The OAuth2 state parameter is invalid' => '',
|
||||
// 'User not found.' => '',
|
||||
// 'Search in activity stream' => '',
|
||||
// 'My activities' => '',
|
||||
// 'Activity until yesterday' => '',
|
||||
// 'Activity until today' => '',
|
||||
// 'Search by creator: ' => '',
|
||||
// 'Search by creation date: ' => '',
|
||||
// 'Search by task status: ' => '',
|
||||
// 'Search by task title: ' => '',
|
||||
// 'Activity stream search' => '',
|
||||
);
|
||||
|
||||
@@ -1153,4 +1153,14 @@ return array(
|
||||
// 'Upload my avatar image' => '',
|
||||
// 'Remove my image' => '',
|
||||
// 'The OAuth2 state parameter is invalid' => '',
|
||||
// 'User not found.' => '',
|
||||
// 'Search in activity stream' => '',
|
||||
// 'My activities' => '',
|
||||
// 'Activity until yesterday' => '',
|
||||
// 'Activity until today' => '',
|
||||
// 'Search by creator: ' => '',
|
||||
// 'Search by creation date: ' => '',
|
||||
// 'Search by task status: ' => '',
|
||||
// 'Search by task title: ' => '',
|
||||
// 'Activity stream search' => '',
|
||||
);
|
||||
|
||||
@@ -1153,4 +1153,14 @@ return array(
|
||||
// 'Upload my avatar image' => '',
|
||||
// 'Remove my image' => '',
|
||||
// 'The OAuth2 state parameter is invalid' => '',
|
||||
// 'User not found.' => '',
|
||||
// 'Search in activity stream' => '',
|
||||
// 'My activities' => '',
|
||||
// 'Activity until yesterday' => '',
|
||||
// 'Activity until today' => '',
|
||||
// 'Search by creator: ' => '',
|
||||
// 'Search by creation date: ' => '',
|
||||
// 'Search by task status: ' => '',
|
||||
// 'Search by task title: ' => '',
|
||||
// 'Activity stream search' => '',
|
||||
);
|
||||
|
||||
@@ -1153,4 +1153,14 @@ return array(
|
||||
// 'Upload my avatar image' => '',
|
||||
// 'Remove my image' => '',
|
||||
// 'The OAuth2 state parameter is invalid' => '',
|
||||
// 'User not found.' => '',
|
||||
// 'Search in activity stream' => '',
|
||||
// 'My activities' => '',
|
||||
// 'Activity until yesterday' => '',
|
||||
// 'Activity until today' => '',
|
||||
// 'Search by creator: ' => '',
|
||||
// 'Search by creation date: ' => '',
|
||||
// 'Search by task status: ' => '',
|
||||
// 'Search by task title: ' => '',
|
||||
// 'Activity stream search' => '',
|
||||
);
|
||||
|
||||
@@ -1153,4 +1153,14 @@ return array(
|
||||
'Upload my avatar image' => 'Enviar a minha imagem de avatar',
|
||||
'Remove my image' => 'Remover a minha imagem',
|
||||
'The OAuth2 state parameter is invalid' => 'O parâmetro "state" de OAuth2 não é válido',
|
||||
// 'User not found.' => '',
|
||||
// 'Search in activity stream' => '',
|
||||
// 'My activities' => '',
|
||||
// 'Activity until yesterday' => '',
|
||||
// 'Activity until today' => '',
|
||||
// 'Search by creator: ' => '',
|
||||
// 'Search by creation date: ' => '',
|
||||
// 'Search by task status: ' => '',
|
||||
// 'Search by task title: ' => '',
|
||||
// 'Activity stream search' => '',
|
||||
);
|
||||
|
||||
@@ -1153,4 +1153,14 @@ return array(
|
||||
'Upload my avatar image' => 'Enviar a minha imagem de avatar',
|
||||
'Remove my image' => 'Remover a minha imagem',
|
||||
'The OAuth2 state parameter is invalid' => 'O parametro de estado do OAuth2 é inválido',
|
||||
// 'User not found.' => '',
|
||||
// 'Search in activity stream' => '',
|
||||
// 'My activities' => '',
|
||||
// 'Activity until yesterday' => '',
|
||||
// 'Activity until today' => '',
|
||||
// 'Search by creator: ' => '',
|
||||
// 'Search by creation date: ' => '',
|
||||
// 'Search by task status: ' => '',
|
||||
// 'Search by task title: ' => '',
|
||||
// 'Activity stream search' => '',
|
||||
);
|
||||
|
||||
@@ -1152,5 +1152,15 @@ return array(
|
||||
'Avatar' => 'Аватар',
|
||||
'Upload my avatar image' => 'Загрузить моё изображение для аватара',
|
||||
'Remove my image' => 'Удалить моё изображение',
|
||||
'The OAuth2 state parameter is invalid' => 'Параметр состояние OAuth2 неправильный'
|
||||
'The OAuth2 state parameter is invalid' => 'Параметр состояние OAuth2 неправильный',
|
||||
// 'User not found.' => '',
|
||||
// 'Search in activity stream' => '',
|
||||
// 'My activities' => '',
|
||||
// 'Activity until yesterday' => '',
|
||||
// 'Activity until today' => '',
|
||||
// 'Search by creator: ' => '',
|
||||
// 'Search by creation date: ' => '',
|
||||
// 'Search by task status: ' => '',
|
||||
// 'Search by task title: ' => '',
|
||||
// 'Activity stream search' => '',
|
||||
);
|
||||
|
||||
@@ -1153,4 +1153,14 @@ return array(
|
||||
// 'Upload my avatar image' => '',
|
||||
// 'Remove my image' => '',
|
||||
// 'The OAuth2 state parameter is invalid' => '',
|
||||
// 'User not found.' => '',
|
||||
// 'Search in activity stream' => '',
|
||||
// 'My activities' => '',
|
||||
// 'Activity until yesterday' => '',
|
||||
// 'Activity until today' => '',
|
||||
// 'Search by creator: ' => '',
|
||||
// 'Search by creation date: ' => '',
|
||||
// 'Search by task status: ' => '',
|
||||
// 'Search by task title: ' => '',
|
||||
// 'Activity stream search' => '',
|
||||
);
|
||||
|
||||
@@ -1153,4 +1153,14 @@ return array(
|
||||
// 'Upload my avatar image' => '',
|
||||
// 'Remove my image' => '',
|
||||
// 'The OAuth2 state parameter is invalid' => '',
|
||||
// 'User not found.' => '',
|
||||
// 'Search in activity stream' => '',
|
||||
// 'My activities' => '',
|
||||
// 'Activity until yesterday' => '',
|
||||
// 'Activity until today' => '',
|
||||
// 'Search by creator: ' => '',
|
||||
// 'Search by creation date: ' => '',
|
||||
// 'Search by task status: ' => '',
|
||||
// 'Search by task title: ' => '',
|
||||
// 'Activity stream search' => '',
|
||||
);
|
||||
|
||||
@@ -1153,4 +1153,14 @@ return array(
|
||||
// 'Upload my avatar image' => '',
|
||||
// 'Remove my image' => '',
|
||||
// 'The OAuth2 state parameter is invalid' => '',
|
||||
// 'User not found.' => '',
|
||||
// 'Search in activity stream' => '',
|
||||
// 'My activities' => '',
|
||||
// 'Activity until yesterday' => '',
|
||||
// 'Activity until today' => '',
|
||||
// 'Search by creator: ' => '',
|
||||
// 'Search by creation date: ' => '',
|
||||
// 'Search by task status: ' => '',
|
||||
// 'Search by task title: ' => '',
|
||||
// 'Activity stream search' => '',
|
||||
);
|
||||
|
||||
@@ -1153,4 +1153,14 @@ return array(
|
||||
// 'Upload my avatar image' => '',
|
||||
// 'Remove my image' => '',
|
||||
// 'The OAuth2 state parameter is invalid' => '',
|
||||
// 'User not found.' => '',
|
||||
// 'Search in activity stream' => '',
|
||||
// 'My activities' => '',
|
||||
// 'Activity until yesterday' => '',
|
||||
// 'Activity until today' => '',
|
||||
// 'Search by creator: ' => '',
|
||||
// 'Search by creation date: ' => '',
|
||||
// 'Search by task status: ' => '',
|
||||
// 'Search by task title: ' => '',
|
||||
// 'Activity stream search' => '',
|
||||
);
|
||||
|
||||
@@ -1153,4 +1153,14 @@ return array(
|
||||
// 'Upload my avatar image' => '',
|
||||
// 'Remove my image' => '',
|
||||
// 'The OAuth2 state parameter is invalid' => '',
|
||||
// 'User not found.' => '',
|
||||
// 'Search in activity stream' => '',
|
||||
// 'My activities' => '',
|
||||
// 'Activity until yesterday' => '',
|
||||
// 'Activity until today' => '',
|
||||
// 'Search by creator: ' => '',
|
||||
// 'Search by creation date: ' => '',
|
||||
// 'Search by task status: ' => '',
|
||||
// 'Search by task title: ' => '',
|
||||
// 'Activity stream search' => '',
|
||||
);
|
||||
|
||||
@@ -71,6 +71,7 @@ class ProjectActivity extends Base
|
||||
'uc.avatar_path'
|
||||
)
|
||||
->join(Task::TABLE, 'id', 'task_id')
|
||||
->join(Project::TABLE, 'id', 'project_id')
|
||||
->left(User::TABLE, 'uc', 'id', ProjectActivity::TABLE, 'creator_id');
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,10 @@ namespace Kanboard\ServiceProvider;
|
||||
|
||||
use Kanboard\Core\Filter\LexerBuilder;
|
||||
use Kanboard\Core\Filter\QueryBuilder;
|
||||
use Kanboard\Filter\ProjectActivityCreationDateFilter;
|
||||
use Kanboard\Filter\ProjectActivityCreatorFilter;
|
||||
use Kanboard\Filter\ProjectActivityProjectNameFilter;
|
||||
use Kanboard\Filter\ProjectActivityTaskStatusFilter;
|
||||
use Kanboard\Filter\ProjectActivityTaskTitleFilter;
|
||||
use Kanboard\Filter\TaskAssigneeFilter;
|
||||
use Kanboard\Filter\TaskCategoryFilter;
|
||||
@@ -86,8 +90,18 @@ class FilterProvider implements ServiceProviderInterface
|
||||
|
||||
$container['projectActivityLexer'] = $container->factory(function ($c) {
|
||||
$builder = new LexerBuilder();
|
||||
$builder->withQuery($c['projectActivity']->getQuery());
|
||||
$builder->withFilter(new ProjectActivityTaskTitleFilter());
|
||||
$builder
|
||||
->withQuery($c['projectActivity']->getQuery())
|
||||
->withFilter(new ProjectActivityTaskTitleFilter(), true)
|
||||
->withFilter(new ProjectActivityTaskStatusFilter())
|
||||
->withFilter(new ProjectActivityProjectNameFilter())
|
||||
->withFilter(ProjectActivityCreationDateFilter::getInstance()
|
||||
->setDateParser($c['dateParser'])
|
||||
)
|
||||
->withFilter(ProjectActivityCreatorFilter::getInstance()
|
||||
->setCurrentUserId($c['userSession']->getId())
|
||||
)
|
||||
;
|
||||
|
||||
return $builder;
|
||||
});
|
||||
@@ -124,17 +138,23 @@ class FilterProvider implements ServiceProviderInterface
|
||||
)
|
||||
->withFilter(new TaskColumnFilter())
|
||||
->withFilter(new TaskCommentFilter())
|
||||
->withFilter(new TaskCreationDateFilter())
|
||||
->withFilter(TaskCreationDateFilter::getInstance()
|
||||
->setDateParser($c['dateParser'])
|
||||
)
|
||||
->withFilter(TaskCreatorFilter::getInstance()
|
||||
->setCurrentUserId($c['userSession']->getId())
|
||||
)
|
||||
->withFilter(new TaskDescriptionFilter())
|
||||
->withFilter(new TaskDueDateFilter())
|
||||
->withFilter(TaskDueDateFilter::getInstance()
|
||||
->setDateParser($c['dateParser'])
|
||||
)
|
||||
->withFilter(new TaskIdFilter())
|
||||
->withFilter(TaskLinkFilter::getInstance()
|
||||
->setDatabase($c['db'])
|
||||
)
|
||||
->withFilter(new TaskModificationDateFilter())
|
||||
->withFilter(TaskModificationDateFilter::getInstance()
|
||||
->setDateParser($c['dateParser'])
|
||||
)
|
||||
->withFilter(new TaskProjectFilter())
|
||||
->withFilter(new TaskReferenceFilter())
|
||||
->withFilter(new TaskStatusFilter())
|
||||
|
||||
@@ -42,7 +42,7 @@ class RouteProvider implements ServiceProviderInterface
|
||||
|
||||
// Search routes
|
||||
$container['route']->addRoute('search', 'search', 'index');
|
||||
$container['route']->addRoute('search/:search', 'search', 'index');
|
||||
$container['route']->addRoute('search/activity', 'search', 'activity');
|
||||
|
||||
// ProjectCreation routes
|
||||
$container['route']->addRoute('project/create', 'ProjectCreation', 'create');
|
||||
@@ -62,6 +62,7 @@ class RouteProvider implements ServiceProviderInterface
|
||||
$container['route']->addRoute('project/:project_id/enable', 'project', 'enable');
|
||||
$container['route']->addRoute('project/:project_id/permissions', 'ProjectPermission', 'index');
|
||||
$container['route']->addRoute('project/:project_id/import', 'taskImport', 'step1');
|
||||
$container['route']->addRoute('project/:project_id/activity', 'activity', 'project');
|
||||
|
||||
// Project Overview
|
||||
$container['route']->addRoute('project/:project_id/overview', 'ProjectOverview', 'show');
|
||||
|
||||
14
app/Template/activity/filter_dropdown.php
Normal file
14
app/Template/activity/filter_dropdown.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<div class="dropdown">
|
||||
<a href="#" class="dropdown-menu dropdown-menu-link-icon" title="<?= t('Default filters') ?>"><i class="fa fa-filter fa-fw"></i><i class="fa fa-caret-down"></i></a>
|
||||
<ul>
|
||||
<li><a href="#" class="filter-helper filter-reset" data-filter="" title="<?= t('Keyboard shortcut: "%s"', 'r') ?>"><?= t('Reset filters') ?></a></li>
|
||||
<li><a href="#" class="filter-helper" data-filter="creator:me"><?= t('My activities') ?></a></li>
|
||||
<li><a href="#" class="filter-helper" data-filter="created:<=<?= date('Y-m-d', strtotime('yesterday')) ?>"><?= t('Activity until yesterday') ?></a></li>
|
||||
<li><a href="#" class="filter-helper" data-filter="created:<=<?= date('Y-m-d')?>"><?= t('Activity until today') ?></a></li>
|
||||
<li><a href="#" class="filter-helper" data-filter="status:closed"><?= t('Closed tasks') ?></a></li>
|
||||
<li><a href="#" class="filter-helper" data-filter="status:open"><?= t('Open tasks') ?></a></li>
|
||||
<li>
|
||||
<?= $this->url->doc(t('View advanced search syntax'), 'search') ?>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
39
app/Template/search/activity.php
Normal file
39
app/Template/search/activity.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<section id="main">
|
||||
<div class="page-header">
|
||||
<ul>
|
||||
<li>
|
||||
<i class="fa fa-search fa-fw"></i>
|
||||
<?= $this->url->link(t('Search tasks'), 'search', 'index') ?>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="filter-box">
|
||||
<form method="get" action="<?= $this->url->dir() ?>" class="search">
|
||||
<?= $this->form->hidden('controller', $values) ?>
|
||||
<?= $this->form->hidden('action', $values) ?>
|
||||
<?= $this->form->text('search', $values, array(), array(empty($values['search']) ? 'autofocus' : '', 'placeholder="'.t('Search').'"'), 'form-input-large') ?>
|
||||
<?= $this->render('activity/filter_dropdown') ?>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<?php if (empty($values['search'])): ?>
|
||||
<div class="listing">
|
||||
<h3><?= t('Advanced search') ?></h3>
|
||||
<p><?= t('Example of query: ') ?><strong>project:"My project" creator:me</strong></p>
|
||||
<ul>
|
||||
<li><?= t('Search by project: ') ?><strong>project:"My project"</strong></li>
|
||||
<li><?= t('Search by creator: ') ?><strong>creator:admin</strong></li>
|
||||
<li><?= t('Search by creation date: ') ?><strong>created:today</strong></li>
|
||||
<li><?= t('Search by task status: ') ?><strong>status:open</strong></li>
|
||||
<li><?= t('Search by task title: ') ?><strong>title:"My task"</strong></li>
|
||||
</ul>
|
||||
<p><i class="fa fa-external-link fa-fw"></i><?= $this->url->doc(t('View advanced search syntax'), 'search') ?></p>
|
||||
</div>
|
||||
<?php elseif (! empty($values['search']) && $nb_events === 0): ?>
|
||||
<p class="alert"><?= t('Nothing found.') ?></p>
|
||||
<?php else: ?>
|
||||
<?= $this->render('event/events', array('events' => $events)) ?>
|
||||
<?php endif ?>
|
||||
|
||||
</section>
|
||||
@@ -2,8 +2,8 @@
|
||||
<div class="page-header">
|
||||
<ul>
|
||||
<li>
|
||||
<i class="fa fa-folder fa-fw"></i>
|
||||
<?= $this->url->link(t('All projects'), 'project', 'index') ?>
|
||||
<i class="fa fa-search fa-fw"></i>
|
||||
<?= $this->url->link(t('Activity stream search'), 'search', 'activity') ?>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user