summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/Controller/Search.php18
-rw-r--r--app/Filter/BaseDateFilter.php103
-rw-r--r--app/Filter/BaseFilter.php44
-rw-r--r--app/Filter/ProjectActivityCreationDateFilter.php38
-rw-r--r--app/Filter/ProjectActivityCreatorFilter.php65
-rw-r--r--app/Filter/ProjectActivityProjectIdsFilter.php2
-rw-r--r--app/Filter/ProjectActivityProjectNameFilter.php38
-rw-r--r--app/Filter/ProjectActivityTaskStatusFilter.php43
-rw-r--r--app/Filter/ProjectActivityTaskTitleFilter.php15
-rw-r--r--app/Filter/TaskCompletionDateFilter.php2
-rw-r--r--app/Filter/TaskCreationDateFilter.php2
-rw-r--r--app/Filter/TaskDueDateFilter.php2
-rw-r--r--app/Filter/TaskModificationDateFilter.php2
-rw-r--r--app/Filter/TaskProjectsFilter.php7
-rw-r--r--app/Filter/TaskStartDateFilter.php2
-rw-r--r--app/Helper/ProjectActivityHelper.php27
-rw-r--r--app/Locale/bs_BA/translations.php10
-rw-r--r--app/Locale/cs_CZ/translations.php10
-rw-r--r--app/Locale/da_DK/translations.php10
-rw-r--r--app/Locale/de_DE/translations.php10
-rw-r--r--app/Locale/el_GR/translations.php10
-rw-r--r--app/Locale/es_ES/translations.php10
-rw-r--r--app/Locale/fi_FI/translations.php10
-rw-r--r--app/Locale/fr_FR/translations.php10
-rw-r--r--app/Locale/hu_HU/translations.php10
-rw-r--r--app/Locale/id_ID/translations.php10
-rw-r--r--app/Locale/it_IT/translations.php10
-rw-r--r--app/Locale/ja_JP/translations.php10
-rw-r--r--app/Locale/ko_KR/translations.php10
-rw-r--r--app/Locale/my_MY/translations.php10
-rw-r--r--app/Locale/nb_NO/translations.php10
-rw-r--r--app/Locale/nl_NL/translations.php10
-rw-r--r--app/Locale/pl_PL/translations.php10
-rw-r--r--app/Locale/pt_BR/translations.php10
-rw-r--r--app/Locale/pt_PT/translations.php10
-rw-r--r--app/Locale/ru_RU/translations.php12
-rw-r--r--app/Locale/sr_Latn_RS/translations.php10
-rw-r--r--app/Locale/sv_SE/translations.php10
-rw-r--r--app/Locale/th_TH/translations.php10
-rw-r--r--app/Locale/tr_TR/translations.php10
-rw-r--r--app/Locale/zh_CN/translations.php10
-rw-r--r--app/Model/ProjectActivity.php1
-rw-r--r--app/ServiceProvider/FilterProvider.php30
-rw-r--r--app/ServiceProvider/RouteProvider.php3
-rw-r--r--app/Template/activity/filter_dropdown.php14
-rw-r--r--app/Template/search/activity.php39
-rw-r--r--app/Template/search/index.php4
47 files changed, 679 insertions, 74 deletions
diff --git a/app/Controller/Search.php b/app/Controller/Search.php
index 840a90c8..a42e9d3d 100644
--- a/app/Controller/Search.php
+++ b/app/Controller/Search.php
@@ -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,
+ )));
+ }
}
diff --git a/app/Filter/BaseDateFilter.php b/app/Filter/BaseDateFilter.php
new file mode 100644
index 00000000..56fb2d78
--- /dev/null
+++ b/app/Filter/BaseDateFilter.php
@@ -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;
+ }
+}
diff --git a/app/Filter/BaseFilter.php b/app/Filter/BaseFilter.php
index a7e6a61a..79a664be 100644
--- a/app/Filter/BaseFilter.php
+++ b/app/Filter/BaseFilter.php
@@ -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);
- }
- }
}
diff --git a/app/Filter/ProjectActivityCreationDateFilter.php b/app/Filter/ProjectActivityCreationDateFilter.php
new file mode 100644
index 00000000..d0b7f754
--- /dev/null
+++ b/app/Filter/ProjectActivityCreationDateFilter.php
@@ -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;
+ }
+}
diff --git a/app/Filter/ProjectActivityCreatorFilter.php b/app/Filter/ProjectActivityCreatorFilter.php
new file mode 100644
index 00000000..c95569d6
--- /dev/null
+++ b/app/Filter/ProjectActivityCreatorFilter.php
@@ -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();
+ }
+ }
+}
diff --git a/app/Filter/ProjectActivityProjectIdsFilter.php b/app/Filter/ProjectActivityProjectIdsFilter.php
index 4d7c9028..47cf0c25 100644
--- a/app/Filter/ProjectActivityProjectIdsFilter.php
+++ b/app/Filter/ProjectActivityProjectIdsFilter.php
@@ -21,7 +21,7 @@ class ProjectActivityProjectIdsFilter extends BaseFilter implements FilterInterf
*/
public function getAttributes()
{
- return array('project_ids');
+ return array('projects');
}
/**
diff --git a/app/Filter/ProjectActivityProjectNameFilter.php b/app/Filter/ProjectActivityProjectNameFilter.php
new file mode 100644
index 00000000..0cf73657
--- /dev/null
+++ b/app/Filter/ProjectActivityProjectNameFilter.php
@@ -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;
+ }
+}
diff --git a/app/Filter/ProjectActivityTaskStatusFilter.php b/app/Filter/ProjectActivityTaskStatusFilter.php
new file mode 100644
index 00000000..69e2c52d
--- /dev/null
+++ b/app/Filter/ProjectActivityTaskStatusFilter.php
@@ -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;
+ }
+}
diff --git a/app/Filter/ProjectActivityTaskTitleFilter.php b/app/Filter/ProjectActivityTaskTitleFilter.php
index ed3f36d6..bf2afa30 100644
--- a/app/Filter/ProjectActivityTaskTitleFilter.php
+++ b/app/Filter/ProjectActivityTaskTitleFilter.php
@@ -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;
- }
}
diff --git a/app/Filter/TaskCompletionDateFilter.php b/app/Filter/TaskCompletionDateFilter.php
index 5166bebf..f206a3e2 100644
--- a/app/Filter/TaskCompletionDateFilter.php
+++ b/app/Filter/TaskCompletionDateFilter.php
@@ -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
diff --git a/app/Filter/TaskCreationDateFilter.php b/app/Filter/TaskCreationDateFilter.php
index 26318b3e..bb6efad6 100644
--- a/app/Filter/TaskCreationDateFilter.php
+++ b/app/Filter/TaskCreationDateFilter.php
@@ -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
diff --git a/app/Filter/TaskDueDateFilter.php b/app/Filter/TaskDueDateFilter.php
index 6ba55eb9..e36efdd0 100644
--- a/app/Filter/TaskDueDateFilter.php
+++ b/app/Filter/TaskDueDateFilter.php
@@ -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
diff --git a/app/Filter/TaskModificationDateFilter.php b/app/Filter/TaskModificationDateFilter.php
index d8838bce..5036e9c1 100644
--- a/app/Filter/TaskModificationDateFilter.php
+++ b/app/Filter/TaskModificationDateFilter.php
@@ -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
diff --git a/app/Filter/TaskProjectsFilter.php b/app/Filter/TaskProjectsFilter.php
index e0fc09cf..47636b1d 100644
--- a/app/Filter/TaskProjectsFilter.php
+++ b/app/Filter/TaskProjectsFilter.php
@@ -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;
}
}
diff --git a/app/Filter/TaskStartDateFilter.php b/app/Filter/TaskStartDateFilter.php
index d45bc0d4..dd30762b 100644
--- a/app/Filter/TaskStartDateFilter.php
+++ b/app/Filter/TaskStartDateFilter.php
@@ -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
diff --git a/app/Helper/ProjectActivityHelper.php b/app/Helper/ProjectActivityHelper.php
index 738fec66..0638a978 100644
--- a/app/Helper/ProjectActivityHelper.php
+++ b/app/Helper/ProjectActivityHelper.php
@@ -18,6 +18,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
*
* @access public
diff --git a/app/Locale/bs_BA/translations.php b/app/Locale/bs_BA/translations.php
index 7ca864f4..e384f923 100644
--- a/app/Locale/bs_BA/translations.php
+++ b/app/Locale/bs_BA/translations.php
@@ -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' => '',
);
diff --git a/app/Locale/cs_CZ/translations.php b/app/Locale/cs_CZ/translations.php
index b2921de9..3c8de1ad 100644
--- a/app/Locale/cs_CZ/translations.php
+++ b/app/Locale/cs_CZ/translations.php
@@ -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' => '',
);
diff --git a/app/Locale/da_DK/translations.php b/app/Locale/da_DK/translations.php
index c4743922..747fa2d1 100644
--- a/app/Locale/da_DK/translations.php
+++ b/app/Locale/da_DK/translations.php
@@ -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' => '',
);
diff --git a/app/Locale/de_DE/translations.php b/app/Locale/de_DE/translations.php
index 999bf048..fa447e62 100644
--- a/app/Locale/de_DE/translations.php
+++ b/app/Locale/de_DE/translations.php
@@ -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' => '',
);
diff --git a/app/Locale/el_GR/translations.php b/app/Locale/el_GR/translations.php
index 9a31e485..84cf8462 100644
--- a/app/Locale/el_GR/translations.php
+++ b/app/Locale/el_GR/translations.php
@@ -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' => '',
);
diff --git a/app/Locale/es_ES/translations.php b/app/Locale/es_ES/translations.php
index c3623369..e52c959b 100644
--- a/app/Locale/es_ES/translations.php
+++ b/app/Locale/es_ES/translations.php
@@ -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' => '',
);
diff --git a/app/Locale/fi_FI/translations.php b/app/Locale/fi_FI/translations.php
index 8e5dd81f..f47852b0 100644
--- a/app/Locale/fi_FI/translations.php
+++ b/app/Locale/fi_FI/translations.php
@@ -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' => '',
);
diff --git a/app/Locale/fr_FR/translations.php b/app/Locale/fr_FR/translations.php
index cedd6039..0c2e4955 100644
--- a/app/Locale/fr_FR/translations.php
+++ b/app/Locale/fr_FR/translations.php
@@ -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é',
);
diff --git a/app/Locale/hu_HU/translations.php b/app/Locale/hu_HU/translations.php
index f642a6c1..9a2d666a 100644
--- a/app/Locale/hu_HU/translations.php
+++ b/app/Locale/hu_HU/translations.php
@@ -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' => '',
);
diff --git a/app/Locale/id_ID/translations.php b/app/Locale/id_ID/translations.php
index 3f105054..9cbca60e 100644
--- a/app/Locale/id_ID/translations.php
+++ b/app/Locale/id_ID/translations.php
@@ -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' => '',
);
diff --git a/app/Locale/it_IT/translations.php b/app/Locale/it_IT/translations.php
index 93ceb03f..d0209b3a 100644
--- a/app/Locale/it_IT/translations.php
+++ b/app/Locale/it_IT/translations.php
@@ -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' => '',
);
diff --git a/app/Locale/ja_JP/translations.php b/app/Locale/ja_JP/translations.php
index b48eabd8..69ab5f17 100644
--- a/app/Locale/ja_JP/translations.php
+++ b/app/Locale/ja_JP/translations.php
@@ -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' => '',
);
diff --git a/app/Locale/ko_KR/translations.php b/app/Locale/ko_KR/translations.php
index 8379761f..f4320c55 100644
--- a/app/Locale/ko_KR/translations.php
+++ b/app/Locale/ko_KR/translations.php
@@ -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' => '',
);
diff --git a/app/Locale/my_MY/translations.php b/app/Locale/my_MY/translations.php
index 36b3db0b..f6f15937 100644
--- a/app/Locale/my_MY/translations.php
+++ b/app/Locale/my_MY/translations.php
@@ -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' => '',
);
diff --git a/app/Locale/nb_NO/translations.php b/app/Locale/nb_NO/translations.php
index 465efb53..f3d3047a 100644
--- a/app/Locale/nb_NO/translations.php
+++ b/app/Locale/nb_NO/translations.php
@@ -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' => '',
);
diff --git a/app/Locale/nl_NL/translations.php b/app/Locale/nl_NL/translations.php
index 3c3fa1ee..f08f5eff 100644
--- a/app/Locale/nl_NL/translations.php
+++ b/app/Locale/nl_NL/translations.php
@@ -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' => '',
);
diff --git a/app/Locale/pl_PL/translations.php b/app/Locale/pl_PL/translations.php
index d06e347f..8222f9e1 100644
--- a/app/Locale/pl_PL/translations.php
+++ b/app/Locale/pl_PL/translations.php
@@ -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' => '',
);
diff --git a/app/Locale/pt_BR/translations.php b/app/Locale/pt_BR/translations.php
index cdb06dea..60242d95 100644
--- a/app/Locale/pt_BR/translations.php
+++ b/app/Locale/pt_BR/translations.php
@@ -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' => '',
);
diff --git a/app/Locale/pt_PT/translations.php b/app/Locale/pt_PT/translations.php
index e38344f8..956d1259 100644
--- a/app/Locale/pt_PT/translations.php
+++ b/app/Locale/pt_PT/translations.php
@@ -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' => '',
);
diff --git a/app/Locale/ru_RU/translations.php b/app/Locale/ru_RU/translations.php
index b3503e52..1e548e0d 100644
--- a/app/Locale/ru_RU/translations.php
+++ b/app/Locale/ru_RU/translations.php
@@ -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' => '',
);
diff --git a/app/Locale/sr_Latn_RS/translations.php b/app/Locale/sr_Latn_RS/translations.php
index c7070a8d..b69e6cf4 100644
--- a/app/Locale/sr_Latn_RS/translations.php
+++ b/app/Locale/sr_Latn_RS/translations.php
@@ -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' => '',
);
diff --git a/app/Locale/sv_SE/translations.php b/app/Locale/sv_SE/translations.php
index e4728d2d..634b87d0 100644
--- a/app/Locale/sv_SE/translations.php
+++ b/app/Locale/sv_SE/translations.php
@@ -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' => '',
);
diff --git a/app/Locale/th_TH/translations.php b/app/Locale/th_TH/translations.php
index 1e2fb98a..1e913f28 100644
--- a/app/Locale/th_TH/translations.php
+++ b/app/Locale/th_TH/translations.php
@@ -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' => '',
);
diff --git a/app/Locale/tr_TR/translations.php b/app/Locale/tr_TR/translations.php
index 6e8fae2f..95bcc8a8 100644
--- a/app/Locale/tr_TR/translations.php
+++ b/app/Locale/tr_TR/translations.php
@@ -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' => '',
);
diff --git a/app/Locale/zh_CN/translations.php b/app/Locale/zh_CN/translations.php
index decd49d8..7b0c3139 100644
--- a/app/Locale/zh_CN/translations.php
+++ b/app/Locale/zh_CN/translations.php
@@ -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' => '',
);
diff --git a/app/Model/ProjectActivity.php b/app/Model/ProjectActivity.php
index 31cee113..d993015b 100644
--- a/app/Model/ProjectActivity.php
+++ b/app/Model/ProjectActivity.php
@@ -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');
}
diff --git a/app/ServiceProvider/FilterProvider.php b/app/ServiceProvider/FilterProvider.php
index 4b4dbd2d..f3918d77 100644
--- a/app/ServiceProvider/FilterProvider.php
+++ b/app/ServiceProvider/FilterProvider.php
@@ -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())
diff --git a/app/ServiceProvider/RouteProvider.php b/app/ServiceProvider/RouteProvider.php
index 0e7548d4..30d23a51 100644
--- a/app/ServiceProvider/RouteProvider.php
+++ b/app/ServiceProvider/RouteProvider.php
@@ -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');
diff --git a/app/Template/activity/filter_dropdown.php b/app/Template/activity/filter_dropdown.php
new file mode 100644
index 00000000..8d7a7de3
--- /dev/null
+++ b/app/Template/activity/filter_dropdown.php
@@ -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> \ No newline at end of file
diff --git a/app/Template/search/activity.php b/app/Template/search/activity.php
new file mode 100644
index 00000000..60362215
--- /dev/null
+++ b/app/Template/search/activity.php
@@ -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> \ No newline at end of file
diff --git a/app/Template/search/index.php b/app/Template/search/index.php
index 9231a6f3..d5d07ed6 100644
--- a/app/Template/search/index.php
+++ b/app/Template/search/index.php
@@ -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>