diff --git a/src/applications/maniphest/query/ManiphestTaskSearchEngine.php b/src/applications/maniphest/query/ManiphestTaskSearchEngine.php index ce51d55820..9e88e4c87b 100644 --- a/src/applications/maniphest/query/ManiphestTaskSearchEngine.php +++ b/src/applications/maniphest/query/ManiphestTaskSearchEngine.php @@ -1,470 +1,476 @@ setParameter( 'assignedPHIDs', $this->readUsersFromRequest($request, 'assigned')); $saved->setParameter('withUnassigned', $request->getBool('withUnassigned')); $saved->setParameter( 'authorPHIDs', $this->readUsersFromRequest($request, 'authors')); $saved->setParameter( 'subscriberPHIDs', $this->readPHIDsFromRequest($request, 'subscribers')); - $saved->setParameter('statuses', $request->getArr('statuses')); - $saved->setParameter('priorities', $request->getArr('priorities')); + $saved->setParameter( + 'statuses', + $this->readListFromRequest($request, 'statuses')); + + $saved->setParameter( + 'priorities', + $this->readListFromRequest($request, 'priorities')); + $saved->setParameter('group', $request->getStr('group')); $saved->setParameter('order', $request->getStr('order')); $ids = $request->getStrList('ids'); foreach ($ids as $key => $id) { $id = trim($id, ' Tt'); if (!$id || !is_numeric($id)) { unset($ids[$key]); } else { $ids[$key] = $id; } } $saved->setParameter('ids', $ids); $saved->setParameter('fulltext', $request->getStr('fulltext')); $saved->setParameter( 'allProjectPHIDs', $request->getArr('allProjects')); $saved->setParameter( 'withNoProject', $request->getBool('withNoProject')); $saved->setParameter( 'anyProjectPHIDs', $request->getArr('anyProjects')); $saved->setParameter( 'excludeProjectPHIDs', $request->getArr('excludeProjects')); $saved->setParameter( 'userProjectPHIDs', $this->readUsersFromRequest($request, 'userProjects')); $saved->setParameter('createdStart', $request->getStr('createdStart')); $saved->setParameter('createdEnd', $request->getStr('createdEnd')); $saved->setParameter('modifiedStart', $request->getStr('modifiedStart')); $saved->setParameter('modifiedEnd', $request->getStr('modifiedEnd')); $limit = $request->getInt('limit'); if ($limit > 0) { $saved->setParameter('limit', $limit); } $this->readCustomFieldsFromRequest($request, $saved); return $saved; } public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) { $query = id(new ManiphestTaskQuery()); $author_phids = $saved->getParameter('authorPHIDs'); if ($author_phids) { $query->withAuthors($author_phids); } $subscriber_phids = $saved->getParameter('subscriberPHIDs'); if ($subscriber_phids) { $query->withSubscribers($subscriber_phids); } $with_unassigned = $saved->getParameter('withUnassigned'); if ($with_unassigned) { $query->withOwners(array(null)); } else { $assigned_phids = $saved->getParameter('assignedPHIDs', array()); if ($assigned_phids) { $query->withOwners($assigned_phids); } } $statuses = $saved->getParameter('statuses'); if ($statuses) { $query->withStatuses($statuses); } $priorities = $saved->getParameter('priorities'); if ($priorities) { $query->withPriorities($priorities); } $order = $saved->getParameter('order'); $order = idx($this->getOrderValues(), $order); if ($order) { $query->setOrderBy($order); } else { $query->setOrderBy(head($this->getOrderValues())); } $group = $saved->getParameter('group'); $group = idx($this->getGroupValues(), $group); if ($group) { $query->setGroupBy($group); } else { $query->setGroupBy(head($this->getGroupValues())); } $ids = $saved->getParameter('ids'); if ($ids) { $query->withIDs($ids); } $fulltext = $saved->getParameter('fulltext'); if (strlen($fulltext)) { $query->withFullTextSearch($fulltext); } $with_no_project = $saved->getParameter('withNoProject'); if ($with_no_project) { $query->withAllProjects(array(ManiphestTaskOwner::PROJECT_NO_PROJECT)); } else { $project_phids = $saved->getParameter('allProjectPHIDs'); if ($project_phids) { $query->withAllProjects($project_phids); } } $any_project_phids = $saved->getParameter('anyProjectPHIDs'); if ($any_project_phids) { $query->withAnyProjects($any_project_phids); } $exclude_project_phids = $saved->getParameter('excludeProjectPHIDs'); if ($exclude_project_phids) { $query->withoutProjects($exclude_project_phids); } $user_project_phids = $saved->getParameter('userProjectPHIDs'); if ($user_project_phids) { $query->withAnyUserProjects($user_project_phids); } $start = $this->parseDateTime($saved->getParameter('createdStart')); $end = $this->parseDateTime($saved->getParameter('createdEnd')); if ($start) { $query->withDateCreatedAfter($start); } if ($end) { $query->withDateCreatedBefore($end); } $mod_start = $this->parseDateTime($saved->getParameter('modifiedStart')); $mod_end = $this->parseDateTime($saved->getParameter('modifiedEnd')); if ($mod_start) { $query->withDateModifiedAfter($mod_start); } if ($mod_end) { $query->withDateModifiedBefore($mod_end); } $this->applyCustomFieldsToQuery($query, $saved); return $query; } public function buildSearchForm( AphrontFormView $form, PhabricatorSavedQuery $saved) { $assigned_phids = $saved->getParameter('assignedPHIDs', array()); $author_phids = $saved->getParameter('authorPHIDs', array()); $all_project_phids = $saved->getParameter( 'allProjectPHIDs', array()); $any_project_phids = $saved->getParameter( 'anyProjectPHIDs', array()); $exclude_project_phids = $saved->getParameter( 'excludeProjectPHIDs', array()); $user_project_phids = $saved->getParameter( 'userProjectPHIDs', array()); $subscriber_phids = $saved->getParameter('subscriberPHIDs', array()); $all_phids = array_merge( $assigned_phids, $author_phids, $all_project_phids, $any_project_phids, $exclude_project_phids, $user_project_phids, $subscriber_phids); if ($all_phids) { $handles = id(new PhabricatorHandleQuery()) ->setViewer($this->requireViewer()) ->withPHIDs($all_phids) ->execute(); } else { $handles = array(); } $assigned_handles = array_select_keys($handles, $assigned_phids); $author_handles = array_select_keys($handles, $author_phids); $all_project_handles = array_select_keys($handles, $all_project_phids); $any_project_handles = array_select_keys($handles, $any_project_phids); $exclude_project_handles = array_select_keys( $handles, $exclude_project_phids); $user_project_handles = array_select_keys($handles, $user_project_phids); $subscriber_handles = array_select_keys($handles, $subscriber_phids); $with_unassigned = $saved->getParameter('withUnassigned'); $with_no_projects = $saved->getParameter('withNoProject'); $statuses = $saved->getParameter('statuses', array()); $statuses = array_fuse($statuses); $status_control = id(new AphrontFormCheckboxControl()) ->setLabel(pht('Status')); foreach (ManiphestTaskStatus::getTaskStatusMap() as $status => $name) { $status_control->addCheckbox( 'statuses[]', $status, $name, isset($statuses[$status])); } $priorities = $saved->getParameter('priorities', array()); $priorities = array_fuse($priorities); $priority_control = id(new AphrontFormCheckboxControl()) ->setLabel(pht('Priority')); foreach (ManiphestTaskPriority::getTaskPriorityMap() as $pri => $name) { $priority_control->addCheckbox( 'priorities[]', $pri, $name, isset($priorities[$pri])); } $ids = $saved->getParameter('ids', array()); $form ->appendChild( id(new AphrontFormTokenizerControl()) ->setDatasource('/typeahead/common/accounts/') ->setName('assigned') ->setLabel(pht('Assigned To')) ->setValue($assigned_handles)) ->appendChild( id(new AphrontFormCheckboxControl()) ->addCheckbox( 'withUnassigned', 1, pht('Show only unassigned tasks.'), $with_unassigned)) ->appendChild( id(new AphrontFormTokenizerControl()) ->setDatasource('/typeahead/common/projects/') ->setName('allProjects') ->setLabel(pht('In All Projects')) ->setValue($all_project_handles)) ->appendChild( id(new AphrontFormCheckboxControl()) ->addCheckbox( 'withNoProject', 1, pht('Show only tasks with no projects.'), $with_no_projects)) ->appendChild( id(new AphrontFormTokenizerControl()) ->setDatasource('/typeahead/common/projects/') ->setName('anyProjects') ->setLabel(pht('In Any Project')) ->setValue($any_project_handles)) ->appendChild( id(new AphrontFormTokenizerControl()) ->setDatasource('/typeahead/common/projects/') ->setName('excludeProjects') ->setLabel(pht('Not In Projects')) ->setValue($exclude_project_handles)) ->appendChild( id(new AphrontFormTokenizerControl()) ->setDatasource('/typeahead/common/accounts/') ->setName('userProjects') ->setLabel(pht('In Users\' Projects')) ->setValue($user_project_handles)) ->appendChild( id(new AphrontFormTokenizerControl()) ->setDatasource('/typeahead/common/accounts/') ->setName('authors') ->setLabel(pht('Authors')) ->setValue($author_handles)) ->appendChild( id(new AphrontFormTokenizerControl()) ->setDatasource('/typeahead/common/mailable/') ->setName('subscribers') ->setLabel(pht('Subscribers')) ->setValue($subscriber_handles)) ->appendChild($status_control) ->appendChild($priority_control) ->appendChild( id(new AphrontFormSelectControl()) ->setName('group') ->setLabel(pht('Group By')) ->setValue($saved->getParameter('group')) ->setOptions($this->getGroupOptions())) ->appendChild( id(new AphrontFormSelectControl()) ->setName('order') ->setLabel(pht('Order By')) ->setValue($saved->getParameter('order')) ->setOptions($this->getOrderOptions())) ->appendChild( id(new AphrontFormTextControl()) ->setName('fulltext') ->setLabel(pht('Contains Text')) ->setValue($saved->getParameter('fulltext'))) ->appendChild( id(new AphrontFormTextControl()) ->setName('ids') ->setLabel(pht('Task IDs')) ->setValue(implode(', ', $ids))); $this->appendCustomFieldsToForm($form, $saved); $this->buildDateRange( $form, $saved, 'createdStart', pht('Created After'), 'createdEnd', pht('Created Before')); $this->buildDateRange( $form, $saved, 'modifiedStart', pht('Updated After'), 'modifiedEnd', pht('Updated Before')); $form ->appendChild( id(new AphrontFormTextControl()) ->setName('limit') ->setLabel(pht('Page Size')) ->setValue($saved->getParameter('limit', 100))); } protected function getURI($path) { return '/maniphest/'.$path; } public function getBuiltinQueryNames() { $names = array(); if ($this->requireViewer()->isLoggedIn()) { $names['assigned'] = pht('Assigned'); $names['authored'] = pht('Authored'); $names['subscribed'] = pht('Subscribed'); } $names['open'] = pht('Open Tasks'); $names['all'] = pht('All Tasks'); return $names; } public function buildSavedQueryFromBuiltin($query_key) { $query = $this->newSavedQuery(); $query->setQueryKey($query_key); $viewer_phid = $this->requireViewer()->getPHID(); switch ($query_key) { case 'all': return $query; case 'assigned': return $query ->setParameter('assignedPHIDs', array($viewer_phid)) ->setParameter( 'statuses', ManiphestTaskStatus::getOpenStatusConstants()); case 'subscribed': return $query ->setParameter('subscriberPHIDs', array($viewer_phid)) ->setParameter( 'statuses', ManiphestTaskStatus::getOpenStatusConstants()); case 'open': return $query ->setParameter( 'statuses', ManiphestTaskStatus::getOpenStatusConstants()); case 'authored': return $query ->setParameter('authorPHIDs', array($viewer_phid)) ->setParameter('order', 'created') ->setParameter('group', 'none'); } return parent::buildSavedQueryFromBuiltin($query_key); } private function getOrderOptions() { return array( 'priority' => pht('Priority'), 'updated' => pht('Date Updated'), 'created' => pht('Date Created'), 'title' => pht('Title'), ); } private function getOrderValues() { return array( 'priority' => ManiphestTaskQuery::ORDER_PRIORITY, 'updated' => ManiphestTaskQuery::ORDER_MODIFIED, 'created' => ManiphestTaskQuery::ORDER_CREATED, 'title' => ManiphestTaskQuery::ORDER_TITLE, ); } private function getGroupOptions() { return array( 'priority' => pht('Priority'), 'assigned' => pht('Assigned'), 'status' => pht('Status'), 'project' => pht('Project'), 'none' => pht('None'), ); } private function getGroupValues() { return array( 'priority' => ManiphestTaskQuery::GROUP_PRIORITY, 'assigned' => ManiphestTaskQuery::GROUP_OWNER, 'status' => ManiphestTaskQuery::GROUP_STATUS, 'project' => ManiphestTaskQuery::GROUP_PROJECT, 'none' => ManiphestTaskQuery::GROUP_NONE, ); } } diff --git a/src/applications/project/controller/PhabricatorProjectProfileController.php b/src/applications/project/controller/PhabricatorProjectProfileController.php index dc4f5528b4..7a09ca0d77 100644 --- a/src/applications/project/controller/PhabricatorProjectProfileController.php +++ b/src/applications/project/controller/PhabricatorProjectProfileController.php @@ -1,268 +1,268 @@ id = idx($data, 'id'); } public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $project = id(new PhabricatorProjectQuery()) ->setViewer($user) ->withIDs(array($this->id)) ->needMembers(true) ->needImages(true) ->executeOne(); if (!$project) { return new Aphront404Response(); } $picture = $project->getProfileImageURI(); require_celerity_resource('phabricator-profile-css'); $tasks = $this->renderTasksPage($project); $query = new PhabricatorFeedQuery(); $query->setFilterPHIDs( array( $project->getPHID(), )); $query->setLimit(50); $query->setViewer($this->getRequest()->getUser()); $stories = $query->execute(); $feed = $this->renderStories($stories); $content = phutil_tag_div( 'phabricator-project-layout', array($tasks, $feed)); $id = $this->id; $icon = id(new PHUIIconView()) ->setSpriteSheet(PHUIIconView::SPRITE_ICONS) ->setSpriteIcon('workboard'); $board_btn = id(new PHUIButtonView()) ->setTag('a') ->setText(pht('Workboards')) ->setHref($this->getApplicationURI("board/{$id}/")) ->setIcon($icon); $header = id(new PHUIHeaderView()) ->setHeader($project->getName()) ->setUser($user) ->setPolicyObject($project) ->setImage($picture) ->addActionLink($board_btn); if ($project->getStatus() == PhabricatorProjectStatus::STATUS_ACTIVE) { $header->setStatus('oh-ok', '', pht('Active')); } else { $header->setStatus('policy-noone', '', pht('Archived')); } $actions = $this->buildActionListView($project); $properties = $this->buildPropertyListView($project, $actions); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb($project->getName()) ->setActionList($actions); $object_box = id(new PHUIObjectBoxView()) ->setHeader($header) ->addPropertyList($properties); return $this->buildApplicationPage( array( $crumbs, $object_box, $content, ), array( 'title' => $project->getName(), 'device' => true, )); } private function renderFeedPage(PhabricatorProject $project) { $query = new PhabricatorFeedQuery(); $query->setFilterPHIDs(array($project->getPHID())); $query->setViewer($this->getRequest()->getUser()); $query->setLimit(100); $stories = $query->execute(); if (!$stories) { return pht('There are no stories about this project.'); } return $this->renderStories($stories); } private function renderStories(array $stories) { assert_instances_of($stories, 'PhabricatorFeedStory'); $builder = new PhabricatorFeedBuilder($stories); $builder->setUser($this->getRequest()->getUser()); $builder->setShowHovercards(true); $view = $builder->buildView(); return phutil_tag_div( 'profile-feed', $view->render()); } private function renderTasksPage(PhabricatorProject $project) { $user = $this->getRequest()->getUser(); $query = id(new ManiphestTaskQuery()) ->setViewer($user) ->withAnyProjects(array($project->getPHID())) ->withStatuses(ManiphestTaskStatus::getOpenStatusConstants()) ->setOrderBy(ManiphestTaskQuery::ORDER_PRIORITY) ->setLimit(10); $tasks = $query->execute(); $phids = mpull($tasks, 'getOwnerPHID'); $phids = array_merge( $phids, array_mergev(mpull($tasks, 'getProjectPHIDs'))); $phids = array_filter($phids); $handles = $this->loadViewerHandles($phids); $task_list = new ManiphestTaskListView(); $task_list->setUser($user); $task_list->setTasks($tasks); $task_list->setHandles($handles); $phid = $project->getPHID(); - $view_uri = sprintf( - '/maniphest/?statuses[]=%s&allProjects[]=%s#R', + $view_uri = urisprintf( + '/maniphest/?statuses=%s&allProjects[]=%s#R', implode(',', ManiphestTaskStatus::getOpenStatusConstants()), $phid); $create_uri = '/maniphest/task/create/?projects='.$phid; $icon = id(new PHUIIconView()) ->setSpriteSheet(PHUIIconView::SPRITE_ICONS) ->setSpriteIcon('action-menu'); $button_view = id(new PHUIButtonView()) ->setTag('a') ->setText(pht('View All')) ->setHref($view_uri) ->setIcon($icon); $icon_new = id(new PHUIIconView()) ->setSpriteSheet(PHUIIconView::SPRITE_ICONS) ->setSpriteIcon('new'); $button_add = id(new PHUIButtonView()) ->setTag('a') ->setText(pht('New Task')) ->setHref($create_uri) ->setIcon($icon_new); $header = id(new PHUIHeaderView()) ->setHeader(pht('Open Tasks')) ->addActionLink($button_add) ->addActionLink($button_view); $content = id(new PHUIObjectBoxView()) ->setHeader($header) ->appendChild($task_list); return $content; } private function buildActionListView(PhabricatorProject $project) { $request = $this->getRequest(); $viewer = $request->getUser(); $id = $project->getID(); $view = id(new PhabricatorActionListView()) ->setUser($viewer) ->setObject($project) ->setObjectURI($request->getRequestURI()); $can_edit = PhabricatorPolicyFilter::hasCapability( $viewer, $project, PhabricatorPolicyCapability::CAN_EDIT); $view->addAction( id(new PhabricatorActionView()) ->setName(pht('Edit Project')) ->setIcon('edit') ->setHref($this->getApplicationURI("edit/{$id}/"))); $view->addAction( id(new PhabricatorActionView()) ->setName(pht('Edit Members')) ->setIcon('user') ->setHref($this->getApplicationURI("members/{$id}/")) ->setDisabled(!$can_edit) ->setWorkflow(!$can_edit)); $action = null; if (!$project->isUserMember($viewer->getPHID())) { $can_join = PhabricatorPolicyFilter::hasCapability( $viewer, $project, PhabricatorPolicyCapability::CAN_JOIN); $action = id(new PhabricatorActionView()) ->setUser($viewer) ->setRenderAsForm(true) ->setHref('/project/update/'.$project->getID().'/join/') ->setIcon('new') ->setDisabled(!$can_join) ->setName(pht('Join Project')); } else { $action = id(new PhabricatorActionView()) ->setWorkflow(true) ->setHref('/project/update/'.$project->getID().'/leave/') ->setIcon('delete') ->setName(pht('Leave Project...')); } $view->addAction($action); return $view; } private function buildPropertyListView( PhabricatorProject $project, PhabricatorActionListView $actions) { $request = $this->getRequest(); $viewer = $request->getUser(); $this->loadHandles($project->getMemberPHIDs()); $view = id(new PHUIPropertyListView()) ->setUser($viewer) ->setObject($project) ->setActionList($actions); $view->addProperty( pht('Members'), $project->getMemberPHIDs() ? $this->renderHandlesForPHIDs($project->getMemberPHIDs(), ',') : phutil_tag('em', array(), pht('None'))); $field_list = PhabricatorCustomField::getObjectFields( $project, PhabricatorCustomField::ROLE_VIEW); $field_list->appendFieldsToPropertyList($project, $viewer, $view); return $view; } }