From 15837388428d6dd3c37cf4b1d302e78657fce24e Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 10 Sep 2015 19:06:36 -0700 Subject: [PATCH] Allow search results to be snippeted, roughly Summary: Ref T8646. This is fairly rough: This interface is very niche, and not really flexible enough to accommodate other result customization (but I don't think we have any plans here)? I'm just //summarizing// the content of documents, basically showing the first paragraph of their content, summary, etc. This isn't what Google does: it shows snippets surrounding the actual search terms. However, this is more involved and might be less useful in structured data: for example, I'd imagine that the first line of most phriciton documents, maniphest tasks and Differential revisions really might be the best machine-generatable summary of them. The actual contextual snippeting in Google doesn't often seem hugely useful to me. But this might also not be very useful. There's not much design, not sure if you had any ideas. I only implemented this for tasks, revisions and the wiki since those seem most useful. I'm generally on the fence about this, but it's not a ton of work to swap out for something else later. Maybe we can see how it feels? But happy to toss it or rethink the approach. Test Plan: {F788026} Reviewers: chad Reviewed By: chad Maniphest Tasks: T8646 Differential Revision: https://secure.phabricator.com/D14095 --- resources/celerity/map.php | 46 +++++++++---------- src/__phutil_library_map__.php | 4 ++ .../storage/DifferentialRevision.php | 17 ++++++- .../maniphest/storage/ManiphestTask.php | 17 ++++++- .../phriction/storage/PhrictionDocument.php | 18 +++++++- .../PhabricatorSearchSnippetInterface.php | 11 +++++ ...abricatorSearchApplicationSearchEngine.php | 1 + .../view/PhabricatorSearchResultView.php | 18 ++++++++ .../css/application/search/search-results.css | 5 ++ 9 files changed, 111 insertions(+), 26 deletions(-) create mode 100644 src/applications/search/interface/PhabricatorSearchSnippetInterface.php diff --git a/resources/celerity/map.php b/resources/celerity/map.php index e3e81484cc..2181877bfc 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -11,7 +11,7 @@ return array( 'core.pkg.js' => '47dc9ebb', 'darkconsole.pkg.js' => 'e7393ebb', 'differential.pkg.css' => '2de124c9', - 'differential.pkg.js' => '6223dd9d', + 'differential.pkg.js' => '52d725be', 'diffusion.pkg.css' => '385e85b3', 'diffusion.pkg.js' => '0115b37c', 'maniphest.pkg.css' => '4845691a', @@ -99,7 +99,7 @@ return array( 'rsrc/css/application/releeph/releeph-preview-branch.css' => 'b7a6f4a5', 'rsrc/css/application/releeph/releeph-request-differential-create-dialog.css' => '8d8b92cd', 'rsrc/css/application/releeph/releeph-request-typeahead.css' => '667a48ae', - 'rsrc/css/application/search/search-results.css' => '7dea472c', + 'rsrc/css/application/search/search-results.css' => '586db3a4', 'rsrc/css/application/slowvote/slowvote.css' => '475b4bd2', 'rsrc/css/application/tokens/tokens.css' => '3d0f239e', 'rsrc/css/application/uiexample/example.css' => '528b19de', @@ -357,13 +357,13 @@ return array( 'rsrc/js/application/dashboard/behavior-dashboard-query-panel-select.js' => '453c5375', 'rsrc/js/application/dashboard/behavior-dashboard-tab-panel.js' => 'd4eecc63', 'rsrc/js/application/differential/ChangesetViewManager.js' => '58562350', - 'rsrc/js/application/differential/DifferentialInlineCommentEditor.js' => '64a5550f', + 'rsrc/js/application/differential/DifferentialInlineCommentEditor.js' => 'd4c87bf4', 'rsrc/js/application/differential/behavior-add-reviewers-and-ccs.js' => 'e10f8e18', 'rsrc/js/application/differential/behavior-comment-jump.js' => '4fdb476d', 'rsrc/js/application/differential/behavior-comment-preview.js' => 'b064af76', 'rsrc/js/application/differential/behavior-diff-radios.js' => 'e1ff79b1', 'rsrc/js/application/differential/behavior-dropdown-menus.js' => '2035b9cb', - 'rsrc/js/application/differential/behavior-edit-inline-comments.js' => '65ef6074', + 'rsrc/js/application/differential/behavior-edit-inline-comments.js' => '037b59eb', 'rsrc/js/application/differential/behavior-keyboard-nav.js' => '2c426492', 'rsrc/js/application/differential/behavior-populate.js' => '8694b1df', 'rsrc/js/application/differential/behavior-toggle-files.js' => 'ca3f91eb', @@ -517,7 +517,7 @@ return array( 'conpherence-widget-pane-css' => '775eaaba', 'differential-changeset-view-css' => 'b6b0d1bb', 'differential-core-view-css' => '7ac3cabc', - 'differential-inline-comment-editor' => '64a5550f', + 'differential-inline-comment-editor' => 'd4c87bf4', 'differential-revision-add-comment-css' => 'c47f8c40', 'differential-revision-comment-css' => '14b8565a', 'differential-revision-history-css' => '0e8eb855', @@ -568,7 +568,7 @@ return array( 'javelin-behavior-differential-comment-jump' => '4fdb476d', 'javelin-behavior-differential-diff-radios' => 'e1ff79b1', 'javelin-behavior-differential-dropdown-menus' => '2035b9cb', - 'javelin-behavior-differential-edit-inline-comments' => '65ef6074', + 'javelin-behavior-differential-edit-inline-comments' => '037b59eb', 'javelin-behavior-differential-feedback-preview' => 'b064af76', 'javelin-behavior-differential-keyboard-navigation' => '2c426492', 'javelin-behavior-differential-populate' => '8694b1df', @@ -738,7 +738,7 @@ return array( 'phabricator-phtize' => 'd254d646', 'phabricator-prefab' => '6920d200', 'phabricator-remarkup-css' => '1c4ac273', - 'phabricator-search-results-css' => '7dea472c', + 'phabricator-search-results-css' => '586db3a4', 'phabricator-shaped-request' => '7cbe244b', 'phabricator-side-menu-view-css' => 'bec2458e', 'phabricator-slowvote-css' => '475b4bd2', @@ -853,6 +853,14 @@ return array( 'javelin-behavior-device', 'phabricator-title', ), + '037b59eb' => array( + 'javelin-behavior', + 'javelin-stratcom', + 'javelin-dom', + 'javelin-util', + 'javelin-vector', + 'differential-inline-comment-editor', + ), '048330fa' => array( 'javelin-behavior', 'javelin-typeahead-ondemand-source', @@ -1281,22 +1289,6 @@ return array( 'javelin-workflow', 'javelin-dom', ), - '64a5550f' => array( - 'javelin-dom', - 'javelin-util', - 'javelin-stratcom', - 'javelin-install', - 'javelin-request', - 'javelin-workflow', - ), - '65ef6074' => array( - 'javelin-behavior', - 'javelin-stratcom', - 'javelin-dom', - 'javelin-util', - 'javelin-vector', - 'differential-inline-comment-editor', - ), '665cf6ac' => array( 'javelin-behavior', 'javelin-util', @@ -1825,6 +1817,14 @@ return array( 'javelin-dom', 'javelin-view', ), + 'd4c87bf4' => array( + 'javelin-dom', + 'javelin-util', + 'javelin-stratcom', + 'javelin-install', + 'javelin-request', + 'javelin-workflow', + ), 'd4eecc63' => array( 'javelin-behavior', 'javelin-dom', diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index c9db433f4b..14f128558d 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -2840,6 +2840,7 @@ phutil_register_library_map(array( 'PhabricatorSearchResultView' => 'applications/search/view/PhabricatorSearchResultView.php', 'PhabricatorSearchSelectController' => 'applications/search/controller/PhabricatorSearchSelectController.php', 'PhabricatorSearchSelectField' => 'applications/search/field/PhabricatorSearchSelectField.php', + 'PhabricatorSearchSnippetInterface' => 'applications/search/interface/PhabricatorSearchSnippetInterface.php', 'PhabricatorSearchStringListField' => 'applications/search/field/PhabricatorSearchStringListField.php', 'PhabricatorSearchSubscribersField' => 'applications/search/field/PhabricatorSearchSubscribersField.php', 'PhabricatorSearchTextField' => 'applications/search/field/PhabricatorSearchTextField.php', @@ -4132,6 +4133,7 @@ phutil_register_library_map(array( 'PhabricatorMentionableInterface', 'PhabricatorDestructibleInterface', 'PhabricatorProjectInterface', + 'PhabricatorSearchSnippetInterface', ), 'DifferentialRevisionAffectedFilesHeraldField' => 'DifferentialRevisionHeraldField', 'DifferentialRevisionAuthorHeraldField' => 'DifferentialRevisionHeraldField', @@ -5025,6 +5027,7 @@ phutil_register_library_map(array( 'PhabricatorApplicationTransactionInterface', 'PhabricatorProjectInterface', 'PhabricatorSpacesInterface', + 'PhabricatorSearchSnippetInterface', ), 'ManiphestTaskAssignHeraldAction' => 'HeraldAction', 'ManiphestTaskAssignOtherHeraldAction' => 'ManiphestTaskAssignHeraldAction', @@ -7623,6 +7626,7 @@ phutil_register_library_map(array( 'PhabricatorTokenReceiverInterface', 'PhabricatorDestructibleInterface', 'PhabricatorApplicationTransactionInterface', + 'PhabricatorSearchSnippetInterface', ), 'PhrictionDocumentAuthorHeraldField' => 'PhrictionDocumentHeraldField', 'PhrictionDocumentContentHeraldField' => 'PhrictionDocumentHeraldField', diff --git a/src/applications/differential/storage/DifferentialRevision.php b/src/applications/differential/storage/DifferentialRevision.php index 84b77f0c48..ff007e2638 100644 --- a/src/applications/differential/storage/DifferentialRevision.php +++ b/src/applications/differential/storage/DifferentialRevision.php @@ -13,7 +13,8 @@ final class DifferentialRevision extends DifferentialDAO PhabricatorApplicationTransactionInterface, PhabricatorMentionableInterface, PhabricatorDestructibleInterface, - PhabricatorProjectInterface { + PhabricatorProjectInterface, + PhabricatorSearchSnippetInterface { protected $title = ''; protected $originalTitle; @@ -629,4 +630,18 @@ final class DifferentialRevision extends DifferentialDAO $this->saveTransaction(); } + +/* -( PhabricatorSearchSnippetInterface )---------------------------------- */ + + + public function renderSearchResultSnippet(PhabricatorUser $viewer) { + $content = $this->getSummary(); + $content = PhabricatorMarkupEngine::summarize($content); + $content = PhabricatorMarkupEngine::renderOneObject( + id(new PhabricatorMarkupOneOff())->setContent($content), + 'default', + $viewer); + return $content; + } + } diff --git a/src/applications/maniphest/storage/ManiphestTask.php b/src/applications/maniphest/storage/ManiphestTask.php index 7fbc806bae..453d8c3458 100644 --- a/src/applications/maniphest/storage/ManiphestTask.php +++ b/src/applications/maniphest/storage/ManiphestTask.php @@ -13,7 +13,8 @@ final class ManiphestTask extends ManiphestDAO PhabricatorDestructibleInterface, PhabricatorApplicationTransactionInterface, PhabricatorProjectInterface, - PhabricatorSpacesInterface { + PhabricatorSpacesInterface, + PhabricatorSearchSnippetInterface { const MARKUP_FIELD_DESCRIPTION = 'markup:desc'; @@ -390,4 +391,18 @@ final class ManiphestTask extends ManiphestDAO return $this->spacePHID; } + +/* -( PhabricatorSearchSnippetInterface )---------------------------------- */ + + + public function renderSearchResultSnippet(PhabricatorUser $viewer) { + $content = $this->getDescription(); + $content = PhabricatorMarkupEngine::summarize($content); + $content = PhabricatorMarkupEngine::renderOneObject( + id(new PhabricatorMarkupOneOff())->setContent($content), + 'default', + $viewer); + return $content; + } + } diff --git a/src/applications/phriction/storage/PhrictionDocument.php b/src/applications/phriction/storage/PhrictionDocument.php index f274d87ad4..661feda3c3 100644 --- a/src/applications/phriction/storage/PhrictionDocument.php +++ b/src/applications/phriction/storage/PhrictionDocument.php @@ -7,7 +7,8 @@ final class PhrictionDocument extends PhrictionDAO PhabricatorFlaggableInterface, PhabricatorTokenReceiverInterface, PhabricatorDestructibleInterface, - PhabricatorApplicationTransactionInterface { + PhabricatorApplicationTransactionInterface, + PhabricatorSearchSnippetInterface { protected $slug; protected $depth; @@ -252,4 +253,19 @@ final class PhrictionDocument extends PhrictionDAO $this->saveTransaction(); } + +/* -( PhabricatorSearchSnippetInterface )---------------------------------- */ + + + public function renderSearchResultSnippet(PhabricatorUser $viewer) { + $content = $this->getContent()->getContent(); + $content = PhabricatorMarkupEngine::summarize($content); + $content = PhabricatorMarkupEngine::renderOneObject( + id(new PhabricatorMarkupOneOff())->setContent($content), + 'default', + $viewer); + return $content; + } + + } diff --git a/src/applications/search/interface/PhabricatorSearchSnippetInterface.php b/src/applications/search/interface/PhabricatorSearchSnippetInterface.php new file mode 100644 index 0000000000..0d0543a61c --- /dev/null +++ b/src/applications/search/interface/PhabricatorSearchSnippetInterface.php @@ -0,0 +1,11 @@ + $handle) { $view = id(new PhabricatorSearchResultView()) + ->setUser($viewer) ->setHandle($handle) ->setQuery($query) ->setObject(idx($objects, $phid)) diff --git a/src/applications/search/view/PhabricatorSearchResultView.php b/src/applications/search/view/PhabricatorSearchResultView.php index 63219b3252..2c20b60620 100644 --- a/src/applications/search/view/PhabricatorSearchResultView.php +++ b/src/applications/search/view/PhabricatorSearchResultView.php @@ -21,7 +21,13 @@ final class PhabricatorSearchResultView extends AphrontView { return $this; } + public function getObject() { + return $this->object; + } + public function render() { + $viewer = $this->getUser(); + $handle = $this->handle; if (!$handle->isComplete()) { return; @@ -46,6 +52,18 @@ final class PhabricatorSearchResultView extends AphrontView { $item->addAttribute(pht('Closed')); } + $object = $this->getObject(); + if ($object instanceof PhabricatorSearchSnippetInterface) { + $snippet = $object->renderSearchResultSnippet($viewer); + $snippet = phutil_tag( + 'div', + array( + 'class' => 'phui-search-snippet', + ), + $snippet); + $item->appendChild($snippet); + } + return $item; } diff --git a/webroot/rsrc/css/application/search/search-results.css b/webroot/rsrc/css/application/search/search-results.css index f02efe1315..19f1e77572 100644 --- a/webroot/rsrc/css/application/search/search-results.css +++ b/webroot/rsrc/css/application/search/search-results.css @@ -16,3 +16,8 @@ font-weight: normal; color: #000; } + +.phui-search-snippet { + margin: 0 8px; + color: {$greytext}; +}