diff --git a/src/applications/search/controller/PhabricatorSearchController.php b/src/applications/search/controller/PhabricatorSearchController.php index f1111debc3..cde4501464 100644 --- a/src/applications/search/controller/PhabricatorSearchController.php +++ b/src/applications/search/controller/PhabricatorSearchController.php @@ -1,289 +1,298 @@ key = idx($data, 'key'); } public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); if ($this->key) { $query = id(new PhabricatorSearchQuery())->loadOneWhere( 'queryKey = %s', $this->key); if (!$query) { return new Aphront404Response(); } } else { $query = new PhabricatorSearchQuery(); if ($request->isFormPost()) { $query_str = $request->getStr('query'); $pref_jump = PhabricatorUserPreferences::PREFERENCE_SEARCHBAR_JUMP; if ($request->getStr('jump') != 'no' && $user && $user->loadPreferences()->getPreference($pref_jump, 1)) { $response = PhabricatorJumpNavHandler::jumpPostResponse($query_str); } else { $response = null; } if ($response) { return $response; } else { $query->setQuery($query_str); if ($request->getStr('scope')) { switch ($request->getStr('scope')) { case PhabricatorSearchScope::SCOPE_OPEN_REVISIONS: $query->setParameter('open', 1); $query->setParameter( 'type', DifferentialPHIDTypeRevision::TYPECONST); break; case PhabricatorSearchScope::SCOPE_OPEN_TASKS: $query->setParameter('open', 1); $query->setParameter( 'type', ManiphestPHIDTypeTask::TYPECONST); break; case PhabricatorSearchScope::SCOPE_WIKI: $query->setParameter( 'type', PhrictionPHIDTypeDocument::TYPECONST); break; case PhabricatorSearchScope::SCOPE_COMMITS: $query->setParameter( 'type', PhabricatorRepositoryPHIDTypeCommit::TYPECONST); break; default: break; } } else { if (strlen($request->getStr('type'))) { $query->setParameter('type', $request->getStr('type')); } if ($request->getArr('author')) { $query->setParameter('author', $request->getArr('author')); } if ($request->getArr('owner')) { $query->setParameter('owner', $request->getArr('owner')); } if ($request->getArr('subscribers')) { $query->setParameter('subscribers', $request->getArr('subscribers')); } if ($request->getInt('open')) { $query->setParameter('open', $request->getInt('open')); } if ($request->getArr('project')) { $query->setParameter('project', $request->getArr('project')); } } $query->save(); return id(new AphrontRedirectResponse()) ->setURI('/search/'.$query->getQueryKey().'/'); } } } $options = array( '' => 'All Documents', ) + PhabricatorSearchAbstractDocument::getSupportedTypes(); $status_options = array( 0 => 'Open and Closed Documents', 1 => 'Open Documents', ); $phids = array_merge( $query->getParameter('author', array()), $query->getParameter('owner', array()), $query->getParameter('subscribers', array()), $query->getParameter('project', array())); $handles = $this->loadViewerHandles($phids); $author_value = array_select_keys( $handles, $query->getParameter('author', array())); $author_value = mpull($author_value, 'getFullName', 'getPHID'); $owner_value = array_select_keys( $handles, $query->getParameter('owner', array())); $owner_value = mpull($owner_value, 'getFullName', 'getPHID'); $subscribers_value = array_select_keys( $handles, $query->getParameter('subscribers', array())); $subscribers_value = mpull($subscribers_value, 'getFullName', 'getPHID'); $project_value = array_select_keys( $handles, $query->getParameter('project', array())); $project_value = mpull($project_value, 'getFullName', 'getPHID'); $search_form = new AphrontFormView(); $search_form ->setUser($user) ->setAction('/search/') ->appendChild( phutil_tag( 'input', array( 'type' => 'hidden', 'name' => 'jump', 'value' => 'no', ))) ->appendChild( id(new AphrontFormTextControl()) ->setLabel('Search') ->setName('query') ->setValue($query->getQuery())) ->appendChild( id(new AphrontFormSelectControl()) ->setLabel('Document Type') ->setName('type') ->setOptions($options) ->setValue($query->getParameter('type'))) ->appendChild( id(new AphrontFormSelectControl()) ->setLabel('Document Status') ->setName('open') ->setOptions($status_options) ->setValue($query->getParameter('open'))) ->appendChild( id(new AphrontFormTokenizerControl()) ->setName('author') ->setLabel('Author') ->setDatasource('/typeahead/common/users/') ->setValue($author_value)) ->appendChild( id(new AphrontFormTokenizerControl()) ->setName('owner') ->setLabel('Owner') ->setDatasource('/typeahead/common/searchowner/') ->setValue($owner_value) ->setCaption( 'Tip: search for "Up For Grabs" to find unowned documents.')) ->appendChild( id(new AphrontFormTokenizerControl()) ->setName('subscribers') ->setLabel('Subscribers') ->setDatasource('/typeahead/common/users/') ->setValue($subscribers_value)) ->appendChild( id(new AphrontFormTokenizerControl()) ->setName('project') ->setLabel('Project') ->setDatasource('/typeahead/common/projects/') ->setValue($project_value)) ->appendChild( id(new AphrontFormSubmitControl()) ->setValue('Search')); $search_panel = new AphrontListFilterView(); $search_panel->appendChild($search_form); require_celerity_resource('phabricator-search-results-css'); if ($query->getID()) { $limit = 20; $pager = new AphrontPagerView(); $pager->setURI($request->getRequestURI(), 'page'); $pager->setPageSize($limit); $pager->setOffset($request->getInt('page')); $query->setParameter('limit', $limit + 1); $query->setParameter('offset', $pager->getOffset()); $engine = PhabricatorSearchEngineSelector::newSelector()->newEngine(); $results = $engine->executeSearch($query); $results = $pager->sliceResults($results); // If there are any objects which match the query by name, and we're // not paging through the results, prefix the results with the named // objects. if (!$request->getInt('page')) { $named = id(new PhabricatorObjectQuery()) ->setViewer($user) ->withNames(array($query->getQuery())) ->execute(); if ($named) { $results = array_merge(array_keys($named), $results); } } if ($results) { $handles = id(new PhabricatorHandleQuery()) ->setViewer($user) ->withPHIDs($results) ->execute(); $objects = id(new PhabricatorObjectQuery()) ->setViewer($user) ->withPHIDs($results) ->execute(); $results = array(); foreach ($handles as $phid => $handle) { $view = id(new PhabricatorSearchResultView()) ->setHandle($handle) ->setQuery($query) ->setObject(idx($objects, $phid)); $results[] = $view->render(); } $results = hsprintf( '
'. '%s'. '
%s
'. '
', phutil_implode_html("\n", $results), $pager->render()); } else { $results = hsprintf( '
'. '

No search results.

'. '
'); } $results = id(new PHUIBoxView()) ->addMargin(PHUI::MARGIN_LARGE) ->addPadding(PHUI::PADDING_LARGE) ->setShadow(true) ->appendChild($results) ->addClass('phabricator-search-result-box'); } else { $results = null; } + $crumbs = $this->buildApplicationCrumbs(); + $crumbs->addCrumb( + id(new PhabricatorCrumbView()) + ->setName(pht('Search'))); return $this->buildApplicationPage( array( + $crumbs, $search_panel, $results, ), array( 'title' => pht('Search Results'), 'device' => true, )); } } diff --git a/src/view/page/menu/PhabricatorMainMenuView.php b/src/view/page/menu/PhabricatorMainMenuView.php index 102958d2e7..9d8b25228d 100644 --- a/src/view/page/menu/PhabricatorMainMenuView.php +++ b/src/view/page/menu/PhabricatorMainMenuView.php @@ -1,399 +1,402 @@ applicationMenu = $application_menu; return $this; } public function getApplicationMenu() { return $this->applicationMenu; } public function setController(PhabricatorController $controller) { $this->controller = $controller; return $this; } public function getController() { return $this->controller; } public function setDefaultSearchScope($default_search_scope) { $this->defaultSearchScope = $default_search_scope; return $this; } public function getDefaultSearchScope() { return $this->defaultSearchScope; } public function render() { $user = $this->user; require_celerity_resource('phabricator-main-menu-view'); $header_id = celerity_generate_unique_node_id(); $menus = array(); $alerts = array(); $search_button = ''; $app_button = ''; if ($user->isLoggedIn()) { list($menu, $dropdowns) = $this->renderNotificationMenu(); $alerts[] = $menu; $menus = array_merge($menus, $dropdowns); $app_button = $this->renderApplicationMenuButton($header_id); $search_button = $this->renderSearchMenuButton($header_id); } $search_menu = $this->renderPhabricatorSearchMenu(); if ($alerts) { $alerts = phutil_tag( 'div', array( 'class' => 'phabricator-main-menu-alerts', ), $alerts); } $application_menu = $this->renderApplicationMenu(); return phutil_tag( 'div', array( 'class' => 'phabricator-main-menu', 'id' => $header_id, ), array( $app_button, $search_button, $this->renderPhabricatorLogo(), $alerts, $application_menu, $search_menu, $menus, )); } private function renderSearch() { $user = $this->user; $result = null; $keyboard_config = array( 'helpURI' => '/help/keyboardshortcut/', ); - if ($user->isLoggedIn()) { + $show_search = ($user->isLoggedIn()) || + (PhabricatorEnv::getEnvConfig('policy.allow-public')); + + if ($show_search) { $search = new PhabricatorMainMenuSearchView(); $search->setUser($user); $search->setScope($this->getDefaultSearchScope()); $result = $search; $pref_shortcut = PhabricatorUserPreferences::PREFERENCE_SEARCH_SHORTCUT; if ($user->loadPreferences()->getPreference($pref_shortcut, true)) { $keyboard_config['searchID'] = $search->getID(); } } Javelin::initBehavior('phabricator-keyboard-shortcuts', $keyboard_config); if ($result) { $result = id(new PHUIListItemView()) ->addClass('phabricator-main-menu-search') ->appendChild($result); } return $result; } public function renderApplicationMenuButton($header_id) { $button_id = celerity_generate_unique_node_id(); return javelin_tag( 'a', array( 'class' => 'phabricator-main-menu-expand-button '. 'phabricator-expand-search-menu', 'sigil' => 'jx-toggle-class', 'meta' => array( 'map' => array( $header_id => 'phabricator-application-menu-expanded', $button_id => 'menu-icon-app-blue', ), ), ), phutil_tag( 'span', array( 'class' => 'phabricator-menu-button-icon sprite-menu menu-icon-app', 'id' => $button_id, ), '')); } public function renderApplicationMenu() { $user = $this->getUser(); $controller = $this->getController(); $applications = PhabricatorApplication::getAllInstalledApplications(); $actions = array(); foreach ($applications as $application) { $app_actions = $application->buildMainMenuItems($user, $controller); foreach ($app_actions as $action) { $actions[] = $action; } } $view = $this->getApplicationMenu(); if (!$view) { $view = new PHUIListView(); } $view->addClass('phabricator-dark-menu'); $view->addClass('phabricator-application-menu'); if ($actions) { $view->addMenuItem( id(new PHUIListItemView()) ->setType(PHUIListItemView::TYPE_LABEL) ->setName(pht('Actions'))); foreach ($actions as $action) { $icon = $action->getIcon(); if ($icon) { if ($action->getSelected()) { $action->appendChild($this->renderMenuIcon($icon.'-blue-large')); } else { $action->appendChild($this->renderMenuIcon($icon.'-light-large')); } } $view->addMenuItem($action); } } return $view; } public function renderSearchMenuButton($header_id) { $button_id = celerity_generate_unique_node_id(); return javelin_tag( 'a', array( 'class' => 'phabricator-main-menu-search-button '. 'phabricator-expand-application-menu', 'sigil' => 'jx-toggle-class', 'meta' => array( 'map' => array( $header_id => 'phabricator-search-menu-expanded', $button_id => 'menu-icon-search-blue', ), ), ), phutil_tag( 'span', array( 'class' => 'phabricator-menu-button-icon sprite-menu menu-icon-search', 'id' => $button_id, ), '')); } private function renderPhabricatorSearchMenu() { $view = new PHUIListView(); $view->addClass('phabricator-dark-menu'); $view->addClass('phabricator-search-menu'); $search = $this->renderSearch(); if ($search) { $view->addMenuItem($search); } return $view; } private function renderPhabricatorLogo() { return phutil_tag( 'a', array( 'class' => 'phabricator-main-menu-logo', 'href' => '/', ), phutil_tag( 'span', array( 'class' => 'sprite-menu phabricator-main-menu-logo-image', ), '')); } private function renderNotificationMenu() { $user = $this->user; require_celerity_resource('phabricator-notification-css'); require_celerity_resource('phabricator-notification-menu-css'); require_celerity_resource('sprite-menu-css'); $container_classes = array( 'sprite-menu', 'alert-notifications', ); $message_tag = ''; $message_notification_dropdown = ''; $conpherence = 'PhabricatorApplicationConpherence'; if (PhabricatorApplication::isClassInstalled($conpherence)) { $message_id = celerity_generate_unique_node_id(); $message_count_id = celerity_generate_unique_node_id(); $message_dropdown_id = celerity_generate_unique_node_id(); $unread_status = ConpherenceParticipationStatus::BEHIND; $unread = id(new ConpherenceParticipantCountQuery()) ->withParticipantPHIDs(array($user->getPHID())) ->withParticipationStatus($unread_status) ->execute(); $message_count_number = idx($unread, $user->getPHID(), 0); if ($message_count_number > 999) { $message_count_number = "\xE2\x88\x9E"; } $message_count_tag = phutil_tag( 'span', array( 'id' => $message_count_id, 'class' => 'phabricator-main-menu-message-count' ), $message_count_number); $message_icon_tag = phutil_tag( 'span', array( 'class' => 'sprite-menu phabricator-main-menu-message-icon', ), ''); if ($message_count_number) { $container_classes[] = 'message-unread'; } $message_tag = phutil_tag( 'a', array( 'href' => '/conpherence/', 'class' => implode(' ', $container_classes), 'id' => $message_id, ), array( $message_icon_tag, $message_count_tag, )); Javelin::initBehavior( 'aphlict-dropdown', array( 'bubbleID' => $message_id, 'countID' => $message_count_id, 'dropdownID' => $message_dropdown_id, 'loadingText' => pht('Loading...'), 'uri' => '/conpherence/panel/', )); $message_notification_dropdown = javelin_tag( 'div', array( 'id' => $message_dropdown_id, 'class' => 'phabricator-notification-menu', 'sigil' => 'phabricator-notification-menu', 'style' => 'display: none;', ), ''); } $count_id = celerity_generate_unique_node_id(); $dropdown_id = celerity_generate_unique_node_id(); $bubble_id = celerity_generate_unique_node_id(); $count_number = id(new PhabricatorFeedStoryNotification()) ->countUnread($user); if ($count_number > 999) { $count_number = "\xE2\x88\x9E"; } $count_tag = phutil_tag( 'span', array( 'id' => $count_id, 'class' => 'phabricator-main-menu-alert-count' ), $count_number); $icon_tag = phutil_tag( 'span', array( 'class' => 'sprite-menu phabricator-main-menu-alert-icon', ), ''); if ($count_number) { $container_classes[] = 'alert-unread'; } $bubble_tag = phutil_tag( 'a', array( 'href' => '/notification/', 'class' => implode(' ', $container_classes), 'id' => $bubble_id, ), array($icon_tag, $count_tag)); Javelin::initBehavior( 'aphlict-dropdown', array( 'bubbleID' => $bubble_id, 'countID' => $count_id, 'dropdownID' => $dropdown_id, 'loadingText' => pht('Loading...'), 'uri' => '/notification/panel/', )); $notification_dropdown = javelin_tag( 'div', array( 'id' => $dropdown_id, 'class' => 'phabricator-notification-menu', 'sigil' => 'phabricator-notification-menu', 'style' => 'display: none;', ), ''); $dropdowns = array( $notification_dropdown, $message_notification_dropdown); return array( hsprintf('%s%s', $bubble_tag, $message_tag), $dropdowns ); } private function renderMenuIcon($name) { return phutil_tag( 'span', array( 'class' => 'phabricator-core-menu-icon '. 'sprite-apps-large apps-'.$name, ), ''); } }