From 0efad0276a8d4e49ee3a39ba981e99249a65d8d7 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Sun, 3 Sep 2017 08:56:02 -0700 Subject: [PATCH 01/54] Vertical align header buttons Summary: I can't seem to blame any rational for this, these should vertical align. Test Plan: Project headers with watching buttons. Reviewers: epriestley Reviewed By: epriestley Spies: Korvin Differential Revision: https://secure.phabricator.com/D18520 --- resources/celerity/map.php | 6 +++--- webroot/rsrc/css/phui/phui-header-view.css | 4 ---- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index e3854c740c..56165fac99 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -9,7 +9,7 @@ return array( 'names' => array( 'conpherence.pkg.css' => 'e68cf1fa', 'conpherence.pkg.js' => 'b5b51108', - 'core.pkg.css' => '4ac857bf', + 'core.pkg.css' => '9dd62a98', 'core.pkg.js' => '6c085267', 'darkconsole.pkg.js' => '1f9a31bc', 'differential.pkg.css' => '45951e9e', @@ -158,7 +158,7 @@ return array( 'rsrc/css/phui/phui-form-view.css' => 'ae9f8d16', 'rsrc/css/phui/phui-form.css' => '7aaa04e3', 'rsrc/css/phui/phui-head-thing.css' => 'fd311e5f', - 'rsrc/css/phui/phui-header-view.css' => '808b82c7', + 'rsrc/css/phui/phui-header-view.css' => '859c5150', 'rsrc/css/phui/phui-hovercard.css' => 'f0592bcf', 'rsrc/css/phui/phui-icon-set-selector.css' => '87db8fee', 'rsrc/css/phui/phui-icon.css' => '5c4a5de6', @@ -845,7 +845,7 @@ return array( 'phui-form-css' => '7aaa04e3', 'phui-form-view-css' => 'ae9f8d16', 'phui-head-thing-view-css' => 'fd311e5f', - 'phui-header-view-css' => '808b82c7', + 'phui-header-view-css' => '859c5150', 'phui-hovercard' => '1bd28176', 'phui-hovercard-view-css' => 'f0592bcf', 'phui-icon-set-selector-css' => '87db8fee', diff --git a/webroot/rsrc/css/phui/phui-header-view.css b/webroot/rsrc/css/phui/phui-header-view.css index 8aefcee31c..e0d75b903f 100644 --- a/webroot/rsrc/css/phui/phui-header-view.css +++ b/webroot/rsrc/css/phui/phui-header-view.css @@ -341,10 +341,6 @@ body .phui-header-shell.phui-bleed-header color: {$blacktext}; } -.phui-profile-header .phui-header-col3 { - vertical-align: top; -} - .phui-header-view .phui-tag-indigo a { color: {$sh-indigotext}; } From 33b4de9acff2b86a0a73936faa404e7cfd1922ab Mon Sep 17 00:00:00 2001 From: Chad Little Date: Sun, 3 Sep 2017 09:03:30 -0700 Subject: [PATCH 02/54] Update Setup Issue UI Summary: Slightly cleaner layout Test Plan: review setup issues resolved and unresolved in local config. fake a fatal. Reviewers: epriestley Reviewed By: epriestley Spies: Korvin Differential Revision: https://secure.phabricator.com/D18521 --- resources/celerity/map.php | 4 +- .../config/view/PhabricatorSetupIssueView.php | 17 +++- .../css/application/config/setup-issue.css | 81 +++++++++++-------- 3 files changed, 62 insertions(+), 40 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 56165fac99..7d07cde811 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -48,7 +48,7 @@ return array( 'rsrc/css/application/config/config-options.css' => 'd55ed093', 'rsrc/css/application/config/config-page.css' => 'c1d5121b', 'rsrc/css/application/config/config-template.css' => '8f18fa41', - 'rsrc/css/application/config/setup-issue.css' => 'f794cfc3', + 'rsrc/css/application/config/setup-issue.css' => '7dae7f18', 'rsrc/css/application/config/unhandled-exception.css' => '4c96257a', 'rsrc/css/application/conpherence/color.css' => 'abb4c358', 'rsrc/css/application/conpherence/durable-column.css' => '89ea6bef', @@ -896,7 +896,7 @@ return array( 'releeph-preview-branch' => 'b7a6f4a5', 'releeph-request-differential-create-dialog' => '8d8b92cd', 'releeph-request-typeahead-css' => '667a48ae', - 'setup-issue-css' => 'f794cfc3', + 'setup-issue-css' => '7dae7f18', 'sprite-login-css' => '396f3c3a', 'sprite-tokens-css' => '9cdfd599', 'syntax-default-css' => '9923583c', diff --git a/src/applications/config/view/PhabricatorSetupIssueView.php b/src/applications/config/view/PhabricatorSetupIssueView.php index 71bdb9d8dc..6fd75568ac 100644 --- a/src/applications/config/view/PhabricatorSetupIssueView.php +++ b/src/applications/config/view/PhabricatorSetupIssueView.php @@ -148,7 +148,6 @@ final class PhabricatorSetupIssueView extends AphrontView { array( 'href' => '/config/issue/'.$issue->getIssueKey().'/', 'class' => 'button button-grey', - 'style' => 'float: right', ), pht('Reload Page')); } @@ -194,14 +193,24 @@ final class PhabricatorSetupIssueView extends AphrontView { array( 'class' => 'setup-issue-head', ), - array($name, $status)); + $name); + + $body = phutil_tag( + 'div', + array( + 'class' => 'setup-issue-body', + ), + array( + $status, + $description, + )); $tail = phutil_tag( 'div', array( 'class' => 'setup-issue-tail', ), - array($actions)); + $actions); $issue = phutil_tag( 'div', @@ -210,7 +219,7 @@ final class PhabricatorSetupIssueView extends AphrontView { ), array( $head, - $description, + $body, $tail, )); diff --git a/webroot/rsrc/css/application/config/setup-issue.css b/webroot/rsrc/css/application/config/setup-issue.css index ae54394b4c..7ba033d9c2 100644 --- a/webroot/rsrc/css/application/config/setup-issue.css +++ b/webroot/rsrc/css/application/config/setup-issue.css @@ -6,15 +6,15 @@ } .setup-issue-shell { - max-width: 760px; + max-width: 880px; margin: 16px auto; } .setup-issue { background: #fff; - border: 1px solid #BFCFDA; - padding: 8px; - border-radius: 3px; + border: 1px solid #e4e5e6; + padding: 0; + border-radius: 5px; } .setup-issue p { @@ -24,29 +24,30 @@ .setup-issue table { width: 100%; border-collapse: collapse; - border: 1px solid #BFCFDA; + border: 1px solid #e2e2e2; } .setup-issue table th { text-align: right; width: 30%; background: #F8F9FC; - border: 1px solid #BFCFDA; + border: 1px solid #e2e2e2; padding: 8px; } .setup-issue table td { - border: 1px solid #BFCFDA; + border: 1px solid #e2e2e2; padding: 8px; word-break: break-word; } .setup-issue pre { width: auto; - border: 1px solid #BFCFDA; - padding: 10px 2%; + border: 1px solid #e2e2e2; + padding: 12px; background: #F8F9FC; overflow-x: auto; + border-radius: 3px; } .setup-issue tt { @@ -60,51 +61,51 @@ } .setup-issue-instructions { - font-size: 14px; - padding: 12px 0; + font-size: 13px; + padding: 16px; line-height: 20px; - background: #fff; - border-bottom: 1px solid #BFCFDA; - margin: 0 12px; + background: rgba(71,87,120,0.08); + border-radius: 3px; } .setup-fatal .setup-issue-instructions { - color: #c0392b; + color: #af1404; background: #f4dddb; - padding: 12px; - margin: 0 0 12px; - border-bottom: 1px solid #c0392b; } .setup-issue-name { - color: #464C5C; - padding: 4px 8px 12px; - border-bottom: 1px solid #BFCFDA; font-size: 15px; font-weight: bold; + color: #6B748C; + border-bottom: 1px solid #e2e2e2; + overflow: hidden; + padding: 16px; + line-height: 24px; } -.setup-issue-tail { - margin-top: 12px; +.setup-issue-body { + padding: 16px 16px 0 16px; } .setup-issue-status { - margin: 12px 4px 0; + margin: 0 0 16px 0; padding: 12px; background: #FDF5D4; - color: #bc7837; - border: 1px solid #bc7837; + color: #ab8206; border-radius: 3px; } .setup-issue-actions { - padding: 8px 12px; - border-top: 1px solid #dfdfdf; - background-color: #f7f7f7; - border-bottom-right-radius: 3px; - border-bottom-left-radius: 3px; + padding: 12px; + background-color: #f5f5f5; + border-bottom-right-radius: 5px; + border-bottom-left-radius: 5px; overflow: hidden; - margin: 0 -8px -8px -8px; + text-align: right; +} + +.setup-issue-actions .button { + margin-left: 8px; } .setup-issue-next { @@ -112,14 +113,17 @@ border: 1px solid #BFCFDA; background: #daeaf3; text-align: center; - font-size: 16px; margin: 12px 0; color: #2980b9; border-radius: 3px; } .setup-issue-config { - padding: 8px 12px; + padding: 12px 0; +} + +.setup-issue-config + .setup-issue-config { + padding-top: 0; } .setup-issue ul { @@ -134,3 +138,12 @@ text-align: right; color: #74777D; } + +.phui-two-column-view .setup-issue-background { + padding: 0; +} + +.phui-two-column-view .setup-issue-shell { + width: auto; + margin: 0; +} From 5ceca721cce3f874173aeaca6c72c2cae2e63c91 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Sun, 3 Sep 2017 09:39:19 -0700 Subject: [PATCH 03/54] Minor bug fix with PHUIInfoView Summary: Custom icons here aren't being set. Also use more standard `tt` UI. Test Plan: Set an icon, see set Icon. Reviewers: epriestley Reviewed By: epriestley Spies: Korvin Differential Revision: https://secure.phabricator.com/D18522 --- resources/celerity/map.php | 6 +++--- src/view/phui/PHUIInfoView.php | 1 + webroot/rsrc/css/phui/phui-info-view.css | 7 +++++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 7d07cde811..673f1952f1 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -9,7 +9,7 @@ return array( 'names' => array( 'conpherence.pkg.css' => 'e68cf1fa', 'conpherence.pkg.js' => 'b5b51108', - 'core.pkg.css' => '9dd62a98', + 'core.pkg.css' => '1071e7a2', 'core.pkg.js' => '6c085267', 'darkconsole.pkg.js' => '1f9a31bc', 'differential.pkg.css' => '45951e9e', @@ -163,7 +163,7 @@ return array( 'rsrc/css/phui/phui-icon-set-selector.css' => '87db8fee', 'rsrc/css/phui/phui-icon.css' => '5c4a5de6', 'rsrc/css/phui/phui-image-mask.css' => 'a8498f9c', - 'rsrc/css/phui/phui-info-view.css' => 'e1b4ec37', + 'rsrc/css/phui/phui-info-view.css' => '04e071d7', 'rsrc/css/phui/phui-invisible-character-view.css' => '6993d9f0', 'rsrc/css/phui/phui-left-right.css' => '75227a4d', 'rsrc/css/phui/phui-lightbox.css' => '0a035e40', @@ -851,7 +851,7 @@ return array( 'phui-icon-set-selector-css' => '87db8fee', 'phui-icon-view-css' => '5c4a5de6', 'phui-image-mask-css' => 'a8498f9c', - 'phui-info-view-css' => 'e1b4ec37', + 'phui-info-view-css' => '04e071d7', 'phui-inline-comment-view-css' => '65ae3bc2', 'phui-invisible-character-view-css' => '6993d9f0', 'phui-left-right-css' => '75227a4d', diff --git a/src/view/phui/PHUIInfoView.php b/src/view/phui/PHUIInfoView.php index 18f5af3374..161e49108b 100644 --- a/src/view/phui/PHUIInfoView.php +++ b/src/view/phui/PHUIInfoView.php @@ -59,6 +59,7 @@ final class PHUIInfoView extends AphrontTagView { } else { $icon = id(new PHUIIconView()) ->setIcon($icon); + $this->icon = $icon; } return $this; diff --git a/webroot/rsrc/css/phui/phui-info-view.css b/webroot/rsrc/css/phui/phui-info-view.css index 268385edec..7b20c63ccf 100644 --- a/webroot/rsrc/css/phui/phui-info-view.css +++ b/webroot/rsrc/css/phui/phui-info-view.css @@ -46,8 +46,11 @@ div.phui-info-view.phui-info-severity-plain { } .phui-info-view-body tt { - padding: 0 2px; - background-color: rgba({$alphagrey},.1); + color: {$blacktext}; + background: rgba({$alphablue},0.1); + padding: 1px 4px; + border-radius: 3px; + white-space: pre-wrap; } .phui-info-view-actions { From d5ba30c777f4f8c918d0fcf4540a076522fe692e Mon Sep 17 00:00:00 2001 From: epriestley Date: Tue, 5 Sep 2017 11:33:22 -0700 Subject: [PATCH 04/54] Fix credential control logic for restricted credentials Summary: Fixes T12975. This logic didn't deal with PolicyException correctly. Test Plan: {F5167549} Reviewers: chad Reviewed By: chad Maniphest Tasks: T12975 Differential Revision: https://secure.phabricator.com/D18537 --- .../view/PassphraseCredentialControl.php | 34 +++++++++++-------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/applications/passphrase/view/PassphraseCredentialControl.php b/src/applications/passphrase/view/PassphraseCredentialControl.php index 1c189e30e7..9c9706fe3f 100644 --- a/src/applications/passphrase/view/PassphraseCredentialControl.php +++ b/src/applications/passphrase/view/PassphraseCredentialControl.php @@ -53,13 +53,22 @@ final class PassphraseCredentialControl extends AphrontFormControl { if (strlen($current_phid) && empty($options_map[$current_phid])) { $viewer = $this->getViewer(); - $user_credential = id(new PassphraseCredentialQuery()) - ->setViewer($viewer) - ->withPHIDs(array($current_phid)) - ->executeOne(); - if (!$user_credential) { + $current_name = null; + try { + $user_credential = id(new PassphraseCredentialQuery()) + ->setViewer($viewer) + ->withPHIDs(array($current_phid)) + ->executeOne(); + + if ($user_credential) { + $current_name = pht( + '%s %s', + $user_credential->getMonogram(), + $user_credential->getName()); + } + } catch (PhabricatorPolicyException $policy_exception) { // Pull the credential with the ominipotent viewer so we can look up - // the ID and tell if it's restricted or invalid. + // the ID and provide the monogram. $omnipotent_credential = id(new PassphraseCredentialQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) ->withPHIDs(array($current_phid)) @@ -68,16 +77,13 @@ final class PassphraseCredentialControl extends AphrontFormControl { $current_name = pht( '%s (Restricted Credential)', $omnipotent_credential->getMonogram()); - } else { - $current_name = pht( - 'Invalid Credential ("%s")', - $current_phid); } - } else { + } + + if ($current_name === null) { $current_name = pht( - '%s %s', - $user_credential->getMonogram(), - $user_credential->getName()); + 'Invalid Credential ("%s")', + $current_phid); } $options_map = array( From 4a7593f47fc76590056928a578be2af4cc7fb994 Mon Sep 17 00:00:00 2001 From: epriestley Date: Tue, 5 Sep 2017 07:54:22 -0700 Subject: [PATCH 05/54] Consolidate more Ferret engine code into FerretEngine Summary: Ref T12819. Earlier I separated some ngram code into an "ngram engine" hoping to share it across the simple Ngrams stuff and the full Ferret stuff, but they actually use slightly different rules. Just pull more of this stuff into FerretEngine to reduce the number of moving pieces and the amount of code duplication. Test Plan: Searched for terms, rebuilt indexes. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12819 Differential Revision: https://secure.phabricator.com/D18533 --- src/__phutil_library_map__.php | 6 +- ...abricatorFerretFulltextEngineExtension.php | 9 +- .../search/ferret/PhabricatorFerretEngine.php | 93 ++++++++++++++++++ .../PhabricatorFerretEngineTestCase.php} | 5 +- .../search/ngrams/PhabricatorNgramEngine.php | 95 ------------------- ...PhabricatorCursorPagedPolicyAwareQuery.php | 17 ++-- 6 files changed, 110 insertions(+), 115 deletions(-) rename src/applications/search/{ngrams/__tests__/PhabricatorNgramEngineTestCase.php => ferret/__tests__/PhabricatorFerretEngineTestCase.php} (86%) delete mode 100644 src/applications/search/ngrams/PhabricatorNgramEngine.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index ff30ddae98..4ce066e802 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -2834,6 +2834,7 @@ phutil_register_library_map(array( 'PhabricatorFeedStoryReference' => 'applications/feed/storage/PhabricatorFeedStoryReference.php', 'PhabricatorFerretDocument' => 'applications/search/ferret/PhabricatorFerretDocument.php', 'PhabricatorFerretEngine' => 'applications/search/ferret/PhabricatorFerretEngine.php', + 'PhabricatorFerretEngineTestCase' => 'applications/search/ferret/__tests__/PhabricatorFerretEngineTestCase.php', 'PhabricatorFerretField' => 'applications/search/ferret/PhabricatorFerretField.php', 'PhabricatorFerretFulltextEngineExtension' => 'applications/search/engineextension/PhabricatorFerretFulltextEngineExtension.php', 'PhabricatorFerretInterface' => 'applications/search/ferret/PhabricatorFerretInterface.php', @@ -3205,8 +3206,6 @@ phutil_register_library_map(array( 'PhabricatorNamedQueryQuery' => 'applications/search/query/PhabricatorNamedQueryQuery.php', 'PhabricatorNavigationRemarkupRule' => 'infrastructure/markup/rule/PhabricatorNavigationRemarkupRule.php', 'PhabricatorNeverTriggerClock' => 'infrastructure/daemon/workers/clock/PhabricatorNeverTriggerClock.php', - 'PhabricatorNgramEngine' => 'applications/search/ngrams/PhabricatorNgramEngine.php', - 'PhabricatorNgramEngineTestCase' => 'applications/search/ngrams/__tests__/PhabricatorNgramEngineTestCase.php', 'PhabricatorNgramsIndexEngineExtension' => 'applications/search/engineextension/PhabricatorNgramsIndexEngineExtension.php', 'PhabricatorNgramsInterface' => 'applications/search/interface/PhabricatorNgramsInterface.php', 'PhabricatorNotificationBuilder' => 'applications/notification/builder/PhabricatorNotificationBuilder.php', @@ -8166,6 +8165,7 @@ phutil_register_library_map(array( 'PhabricatorFeedStoryReference' => 'PhabricatorFeedDAO', 'PhabricatorFerretDocument' => 'PhabricatorSearchDAO', 'PhabricatorFerretEngine' => 'Phobject', + 'PhabricatorFerretEngineTestCase' => 'PhabricatorTestCase', 'PhabricatorFerretField' => 'PhabricatorSearchDAO', 'PhabricatorFerretFulltextEngineExtension' => 'PhabricatorFulltextEngineExtension', 'PhabricatorFerretNgrams' => 'PhabricatorSearchDAO', @@ -8587,8 +8587,6 @@ phutil_register_library_map(array( 'PhabricatorNamedQueryQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorNavigationRemarkupRule' => 'PhutilRemarkupRule', 'PhabricatorNeverTriggerClock' => 'PhabricatorTriggerClock', - 'PhabricatorNgramEngine' => 'Phobject', - 'PhabricatorNgramEngineTestCase' => 'PhabricatorTestCase', 'PhabricatorNgramsIndexEngineExtension' => 'PhabricatorIndexEngineExtension', 'PhabricatorNgramsInterface' => 'PhabricatorIndexableInterface', 'PhabricatorNotificationBuilder' => 'Phobject', diff --git a/src/applications/search/engineextension/PhabricatorFerretFulltextEngineExtension.php b/src/applications/search/engineextension/PhabricatorFerretFulltextEngineExtension.php index 1c9efeba9d..766bc4e4c8 100644 --- a/src/applications/search/engineextension/PhabricatorFerretFulltextEngineExtension.php +++ b/src/applications/search/engineextension/PhabricatorFerretFulltextEngineExtension.php @@ -29,8 +29,7 @@ final class PhabricatorFerretFulltextEngineExtension ->setEpochCreated(0) ->setEpochModified(0); - $stemmer = new PhutilSearchStemmer(); - $ngram_engine = id(new PhabricatorNgramEngine()); + $stemmer = $engine->newStemmer(); // Copy all of the "title" and "body" fields to create new "core" fields. // This allows users to search "in title or body" with the "core:" prefix. @@ -69,10 +68,10 @@ final class PhabricatorFerretFulltextEngineExtension continue; } - $term_corpus = $ngram_engine->newTermsCorpus($raw_corpus); + $term_corpus = $engine->newTermsCorpus($raw_corpus); $normal_corpus = $stemmer->stemCorpus($raw_corpus); - $normal_coprus = $ngram_engine->newTermsCorpus($normal_corpus); + $normal_coprus = $engine->newTermsCorpus($normal_corpus); if (!isset($ferret_corpus_map[$key])) { $ferret_corpus_map[$key] = $empty_template; @@ -116,7 +115,7 @@ final class PhabricatorFerretFulltextEngineExtension } $ngrams_source = implode(' ', $ngrams_source); - $ngrams = $ngram_engine->getNgramsFromString($ngrams_source, 'index'); + $ngrams = $engine->getNgramsFromString($ngrams_source, 'index'); $ferret_document->openTransaction(); diff --git a/src/applications/search/ferret/PhabricatorFerretEngine.php b/src/applications/search/ferret/PhabricatorFerretEngine.php index e816ef3f59..3811e16289 100644 --- a/src/applications/search/ferret/PhabricatorFerretEngine.php +++ b/src/applications/search/ferret/PhabricatorFerretEngine.php @@ -6,4 +6,97 @@ abstract class PhabricatorFerretEngine extends Phobject { abstract public function newDocumentObject(); abstract public function newFieldObject(); + public function newStemmer() { + return new PhutilSearchStemmer(); + } + + public function tokenizeString($value) { + $value = trim($value, ' '); + $value = preg_split('/ +/', $value); + return $value; + } + + public function getNgramsFromString($value, $mode) { + $tokens = $this->tokenizeString($value); + + $ngrams = array(); + foreach ($tokens as $token) { + $token = phutil_utf8_strtolower($token); + + switch ($mode) { + case 'query': + break; + case 'index': + $token = ' '.$token.' '; + break; + case 'prefix': + $token = ' '.$token; + break; + } + + $token_v = phutil_utf8v($token); + $len = (count($token_v) - 2); + for ($ii = 0; $ii < $len; $ii++) { + $ngram = array_slice($token_v, $ii, 3); + $ngram = implode('', $ngram); + $ngrams[$ngram] = $ngram; + } + } + + ksort($ngrams); + + return array_keys($ngrams); + } + + public function newTermsCorpus($raw_corpus) { + $term_corpus = strtr( + $raw_corpus, + array( + '!' => ' ', + '"' => ' ', + '#' => ' ', + '$' => ' ', + '%' => ' ', + '&' => ' ', + '(' => ' ', + ')' => ' ', + '*' => ' ', + '+' => ' ', + ',' => ' ', + '-' => ' ', + '/' => ' ', + ':' => ' ', + ';' => ' ', + '<' => ' ', + '=' => ' ', + '>' => ' ', + '?' => ' ', + '@' => ' ', + '[' => ' ', + '\\' => ' ', + ']' => ' ', + '^' => ' ', + '`' => ' ', + '{' => ' ', + '|' => ' ', + '}' => ' ', + '~' => ' ', + '.' => ' ', + '_' => ' ', + "\n" => ' ', + "\r" => ' ', + "\t" => ' ', + )); + + // NOTE: Single quotes divide terms only if they're at a word boundary. + // In contractions, like "whom'st've", the entire word is a single term. + $term_corpus = preg_replace('/(^| )[\']+/', ' ', $term_corpus); + $term_corpus = preg_replace('/[\']+( |$)/', ' ', $term_corpus); + + $term_corpus = preg_replace('/\s+/u', ' ', $term_corpus); + $term_corpus = trim($term_corpus, ' '); + + return $term_corpus; + } + } diff --git a/src/applications/search/ngrams/__tests__/PhabricatorNgramEngineTestCase.php b/src/applications/search/ferret/__tests__/PhabricatorFerretEngineTestCase.php similarity index 86% rename from src/applications/search/ngrams/__tests__/PhabricatorNgramEngineTestCase.php rename to src/applications/search/ferret/__tests__/PhabricatorFerretEngineTestCase.php index fccb6fb324..b8f1043ab2 100644 --- a/src/applications/search/ngrams/__tests__/PhabricatorNgramEngineTestCase.php +++ b/src/applications/search/ferret/__tests__/PhabricatorFerretEngineTestCase.php @@ -1,6 +1,6 @@ $expect) { $actual = $engine->newTermsCorpus($input); diff --git a/src/applications/search/ngrams/PhabricatorNgramEngine.php b/src/applications/search/ngrams/PhabricatorNgramEngine.php deleted file mode 100644 index f8f55d8757..0000000000 --- a/src/applications/search/ngrams/PhabricatorNgramEngine.php +++ /dev/null @@ -1,95 +0,0 @@ -tokenizeString($value); - - $ngrams = array(); - foreach ($tokens as $token) { - $token = phutil_utf8_strtolower($token); - - switch ($mode) { - case 'query': - break; - case 'index': - $token = ' '.$token.' '; - break; - case 'prefix': - $token = ' '.$token; - break; - } - - $token_v = phutil_utf8v($token); - $len = (count($token_v) - 2); - for ($ii = 0; $ii < $len; $ii++) { - $ngram = array_slice($token_v, $ii, 3); - $ngram = implode('', $ngram); - $ngrams[$ngram] = $ngram; - } - } - - ksort($ngrams); - - return array_keys($ngrams); - } - - public function newTermsCorpus($raw_corpus) { - $term_corpus = strtr( - $raw_corpus, - array( - '!' => ' ', - '"' => ' ', - '#' => ' ', - '$' => ' ', - '%' => ' ', - '&' => ' ', - '(' => ' ', - ')' => ' ', - '*' => ' ', - '+' => ' ', - ',' => ' ', - '-' => ' ', - '/' => ' ', - ':' => ' ', - ';' => ' ', - '<' => ' ', - '=' => ' ', - '>' => ' ', - '?' => ' ', - '@' => ' ', - '[' => ' ', - '\\' => ' ', - ']' => ' ', - '^' => ' ', - '`' => ' ', - '{' => ' ', - '|' => ' ', - '}' => ' ', - '~' => ' ', - '.' => ' ', - '_' => ' ', - "\n" => ' ', - "\r" => ' ', - "\t" => ' ', - )); - - // NOTE: Single quotes divide terms only if they're at a word boundary. - // In contractions, like "whom'st've", the entire word is a single term. - $term_corpus = preg_replace('/(^| )[\']+/', ' ', $term_corpus); - $term_corpus = preg_replace('/[\']+( |$)/', ' ', $term_corpus); - - $term_corpus = preg_replace('/\s+/u', ' ', $term_corpus); - $term_corpus = trim($term_corpus, ' '); - - return $term_corpus; - } - - -} diff --git a/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php b/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php index 03d56bc1d2..ccf78de5df 100644 --- a/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php +++ b/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php @@ -1453,8 +1453,7 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery $op_not = PhutilSearchQueryCompiler::OPERATOR_NOT; $engine = $this->ferretEngine; - $ngram_engine = new PhabricatorNgramEngine(); - $stemmer = new PhutilSearchStemmer(); + $stemmer = $engine->newStemmer(); $ngram_table = $engine->newNgramsObject(); $ngram_table_name = $ngram_table->getTableName(); @@ -1498,15 +1497,15 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery } if ($is_substring) { - $ngrams = $ngram_engine->getNgramsFromString($value, 'query'); + $ngrams = $engine->getNgramsFromString($value, 'query'); } else { - $ngrams = $ngram_engine->getNgramsFromString($value, 'index'); + $ngrams = $engine->getNgramsFromString($value, 'index'); // If this is a stemmed term, only look for ngrams present in both the // unstemmed and stemmed variations. if ($is_stemmed) { $stem_value = $stemmer->stemToken($value); - $stem_ngrams = $ngram_engine->getNgramsFromString( + $stem_ngrams = $engine->getNgramsFromString( $stem_value, 'index'); @@ -1587,8 +1586,8 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery return array(); } - $ngram_engine = new PhabricatorNgramEngine(); - $stemmer = new PhutilSearchStemmer(); + $engine = $this->ferretEngine; + $stemmer = $engine->newStemmer(); $table_map = $this->ferretTables; $op_sub = PhutilSearchQueryCompiler::OPERATOR_SUBSTRING; @@ -1653,7 +1652,7 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery $term_constraints = array(); - $term_value = ' '.$ngram_engine->newTermsCorpus($value).' '; + $term_value = ' '.$engine->newTermsCorpus($value).' '; if ($is_not) { $term_constraints[] = qsprintf( $conn, @@ -1670,7 +1669,7 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery if ($is_stemmed) { $stem_value = $stemmer->stemToken($value); - $stem_value = $ngram_engine->newTermsCorpus($stem_value); + $stem_value = $engine->newTermsCorpus($stem_value); $stem_value = ' '.$stem_value.' '; $term_constraints[] = qsprintf( From 46abc11114c36fc92496f933f6f77e4a2753589e Mon Sep 17 00:00:00 2001 From: epriestley Date: Tue, 5 Sep 2017 09:38:03 -0700 Subject: [PATCH 06/54] Reduce the number of magic strings in the Ferret implementation Summary: Ref T12819. Push more of the magic `' '` stuff into the engine and simplify calls to ngram construction. Also fixes a bug where a task with title "apple banana" and description "cherry doughnut" could match query "banana cherry" by separating separate term segments with newlines instead of spaces. Test Plan: - Indexed some objects. - Searched (term, substring, quoted terms). - Viewed index in database. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12819 Differential Revision: https://secure.phabricator.com/D18534 --- ...abricatorFerretFulltextEngineExtension.php | 16 ++++++------ .../search/ferret/PhabricatorFerretEngine.php | 25 +++++++++++-------- .../PhabricatorFerretEngineTestCase.php | 8 +++--- ...PhabricatorCursorPagedPolicyAwareQuery.php | 12 +++------ 4 files changed, 31 insertions(+), 30 deletions(-) diff --git a/src/applications/search/engineextension/PhabricatorFerretFulltextEngineExtension.php b/src/applications/search/engineextension/PhabricatorFerretFulltextEngineExtension.php index 766bc4e4c8..8d1b6070e6 100644 --- a/src/applications/search/engineextension/PhabricatorFerretFulltextEngineExtension.php +++ b/src/applications/search/engineextension/PhabricatorFerretFulltextEngineExtension.php @@ -71,7 +71,7 @@ final class PhabricatorFerretFulltextEngineExtension $term_corpus = $engine->newTermsCorpus($raw_corpus); $normal_corpus = $stemmer->stemCorpus($raw_corpus); - $normal_coprus = $engine->newTermsCorpus($normal_corpus); + $normal_corpus = $engine->newTermsCorpus($normal_corpus); if (!isset($ferret_corpus_map[$key])) { $ferret_corpus_map[$key] = $empty_template; @@ -91,20 +91,20 @@ final class PhabricatorFerretFulltextEngineExtension foreach ($ferret_corpus_map as $key => $fields) { $raw_corpus = $fields['raw']; $raw_corpus = implode("\n", $raw_corpus); - $ngrams_source[] = $raw_corpus; + if (strlen($raw_corpus)) { + $ngrams_source[] = $raw_corpus; + } $normal_corpus = $fields['normal']; - $normal_corpus = implode(' ', $normal_corpus); + $normal_corpus = implode("\n", $normal_corpus); if (strlen($normal_corpus)) { $ngrams_source[] = $normal_corpus; - $normal_corpus = ' '.$normal_corpus.' '; } $term_corpus = $fields['term']; - $term_corpus = implode(' ', $term_corpus); + $term_corpus = implode("\n", $term_corpus); if (strlen($term_corpus)) { $ngrams_source[] = $term_corpus; - $term_corpus = ' '.$term_corpus.' '; } $ferret_fields[] = $engine->newFieldObject() @@ -113,9 +113,9 @@ final class PhabricatorFerretFulltextEngineExtension ->setTermCorpus($term_corpus) ->setNormalCorpus($normal_corpus); } - $ngrams_source = implode(' ', $ngrams_source); + $ngrams_source = implode("\n", $ngrams_source); - $ngrams = $engine->getNgramsFromString($ngrams_source, 'index'); + $ngrams = $engine->getTermNgramsFromString($ngrams_source); $ferret_document->openTransaction(); diff --git a/src/applications/search/ferret/PhabricatorFerretEngine.php b/src/applications/search/ferret/PhabricatorFerretEngine.php index 3811e16289..5f6470ca20 100644 --- a/src/applications/search/ferret/PhabricatorFerretEngine.php +++ b/src/applications/search/ferret/PhabricatorFerretEngine.php @@ -16,22 +16,23 @@ abstract class PhabricatorFerretEngine extends Phobject { return $value; } - public function getNgramsFromString($value, $mode) { + public function getTermNgramsFromString($string) { + return $this->getNgramsFromString($string, true); + } + + public function getSubstringNgramsFromString($string) { + return $this->getNgramsFromString($string, false); + } + + private function getNgramsFromString($value, $as_term) { $tokens = $this->tokenizeString($value); $ngrams = array(); foreach ($tokens as $token) { $token = phutil_utf8_strtolower($token); - switch ($mode) { - case 'query': - break; - case 'index': - $token = ' '.$token.' '; - break; - case 'prefix': - $token = ' '.$token; - break; + if ($as_term) { + $token = ' '.$token.' '; } $token_v = phutil_utf8v($token); @@ -96,6 +97,10 @@ abstract class PhabricatorFerretEngine extends Phobject { $term_corpus = preg_replace('/\s+/u', ' ', $term_corpus); $term_corpus = trim($term_corpus, ' '); + if (strlen($term_corpus)) { + $term_corpus = ' '.$term_corpus.' '; + } + return $term_corpus; } diff --git a/src/applications/search/ferret/__tests__/PhabricatorFerretEngineTestCase.php b/src/applications/search/ferret/__tests__/PhabricatorFerretEngineTestCase.php index b8f1043ab2..a8690f1d8b 100644 --- a/src/applications/search/ferret/__tests__/PhabricatorFerretEngineTestCase.php +++ b/src/applications/search/ferret/__tests__/PhabricatorFerretEngineTestCase.php @@ -5,11 +5,11 @@ final class PhabricatorFerretEngineTestCase public function testTermsCorpus() { $map = array( - 'Hear ye, hear ye!' => 'Hear ye hear ye', - "Thou whom'st've art worthy." => "Thou whom'st've art worthy", - 'Guaranteed to contain "food".' => 'Guaranteed to contain food', + 'Hear ye, hear ye!' => ' Hear ye hear ye ', + "Thou whom'st've art worthy." => " Thou whom'st've art worthy ", + 'Guaranteed to contain "food".' => ' Guaranteed to contain food ', 'http://example.org/path/to/file.jpg' => - 'http example org path to file jpg', + ' http example org path to file jpg ', ); $engine = new ManiphestTaskFerretEngine(); diff --git a/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php b/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php index ccf78de5df..3fdfb33bfe 100644 --- a/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php +++ b/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php @@ -1497,18 +1497,15 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery } if ($is_substring) { - $ngrams = $engine->getNgramsFromString($value, 'query'); + $ngrams = $engine->getSubstringNgramsFromString($value); } else { - $ngrams = $engine->getNgramsFromString($value, 'index'); + $ngrams = $engine->getTermNgramsFromString($value); // If this is a stemmed term, only look for ngrams present in both the // unstemmed and stemmed variations. if ($is_stemmed) { $stem_value = $stemmer->stemToken($value); - $stem_ngrams = $engine->getNgramsFromString( - $stem_value, - 'index'); - + $stem_ngrams = $engine->getTermNgramsFromString($stem_value); $ngrams = array_intersect($ngrams, $stem_ngrams); } } @@ -1652,7 +1649,7 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery $term_constraints = array(); - $term_value = ' '.$engine->newTermsCorpus($value).' '; + $term_value = $engine->newTermsCorpus($value); if ($is_not) { $term_constraints[] = qsprintf( $conn, @@ -1670,7 +1667,6 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery if ($is_stemmed) { $stem_value = $stemmer->stemToken($value); $stem_value = $engine->newTermsCorpus($stem_value); - $stem_value = ' '.$stem_value.' '; $term_constraints[] = qsprintf( $conn, From 20aad35e603661a371fad1fa1bc0e6c4dfd86399 Mon Sep 17 00:00:00 2001 From: epriestley Date: Tue, 5 Sep 2017 10:28:25 -0700 Subject: [PATCH 07/54] Move Ferret engine "title:..." field definitions to the engine itself Summary: Ref T12819. Move these out of the core engine into the Ferret engine. In the future different applications can define different functions, like "summary:..." or whatever. This may get more formalization when I possibly do "author:" and such some time down the road. Test Plan: Searched for "title:...". Searched for "dog:...", got a useful error. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12819 Differential Revision: https://secure.phabricator.com/D18536 --- .../search/ManiphestTaskFerretEngine.php | 9 +++ .../search/ferret/PhabricatorFerretEngine.php | 59 +++++++++++++++++++ ...PhabricatorCursorPagedPolicyAwareQuery.php | 19 +----- 3 files changed, 71 insertions(+), 16 deletions(-) diff --git a/src/applications/maniphest/search/ManiphestTaskFerretEngine.php b/src/applications/maniphest/search/ManiphestTaskFerretEngine.php index 7232d0251f..8aa503fbf8 100644 --- a/src/applications/maniphest/search/ManiphestTaskFerretEngine.php +++ b/src/applications/maniphest/search/ManiphestTaskFerretEngine.php @@ -15,4 +15,13 @@ final class ManiphestTaskFerretEngine return new ManiphestTaskFerretField(); } + protected function getFunctionMap() { + $map = parent::getFunctionMap(); + + $map['body']['aliases'][] = 'desc'; + $map['body']['aliases'][] = 'description'; + + return $map; + } + } diff --git a/src/applications/search/ferret/PhabricatorFerretEngine.php b/src/applications/search/ferret/PhabricatorFerretEngine.php index 5f6470ca20..1de336e70b 100644 --- a/src/applications/search/ferret/PhabricatorFerretEngine.php +++ b/src/applications/search/ferret/PhabricatorFerretEngine.php @@ -6,6 +6,65 @@ abstract class PhabricatorFerretEngine extends Phobject { abstract public function newDocumentObject(); abstract public function newFieldObject(); + public function getDefaultFunctionKey() { + return 'all'; + } + + public function getFieldForFunction($function) { + $function = phutil_utf8_strtolower($function); + + $map = $this->getFunctionMap(); + if (!isset($map[$function])) { + throw new PhutilSearchQueryCompilerSyntaxException( + pht( + 'Unknown search function "%s". Supported functions are: %s.', + $function, + implode(', ', array_keys($map)))); + } + + return $map[$function]['field']; + } + + public function getAllFunctionFields() { + $map = $this->getFunctionMap(); + + $fields = array(); + foreach ($map as $key => $spec) { + $fields[] = $spec['field']; + } + + return $fields; + } + + protected function getFunctionMap() { + return array( + 'all' => array( + 'field' => PhabricatorSearchDocumentFieldType::FIELD_ALL, + 'aliases' => array( + 'any', + ), + ), + 'title' => array( + 'field' => PhabricatorSearchDocumentFieldType::FIELD_TITLE, + 'aliases' => array(), + ), + 'body' => array( + 'field' => PhabricatorSearchDocumentFieldType::FIELD_BODY, + 'aliases' => array(), + ), + 'core' => array( + 'field' => PhabricatorSearchDocumentFieldType::FIELD_CORE, + 'aliases' => array(), + ), + 'comment' => array( + 'field' => PhabricatorSearchDocumentFieldType::FIELD_COMMENT, + 'aliases' => array( + 'comments', + ), + ), + ); + } + public function newStemmer() { return new PhutilSearchStemmer(); } diff --git a/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php b/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php index 3fdfb33bfe..6aa493f1e0 100644 --- a/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php +++ b/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php @@ -1402,15 +1402,7 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery $this->ferretEngine = $engine; $this->ferretTokens = $fulltext_tokens; - - $function_map = array( - 'all' => PhabricatorSearchDocumentFieldType::FIELD_ALL, - 'title' => PhabricatorSearchDocumentFieldType::FIELD_TITLE, - 'body' => PhabricatorSearchDocumentFieldType::FIELD_BODY, - 'core' => PhabricatorSearchDocumentFieldType::FIELD_CORE, - ); - - $current_function = 'all'; + $current_function = $engine->getDefaultFunctionKey(); $table_map = array(); $idx = 1; foreach ($this->ferretTokens as $fulltext_token) { @@ -1421,18 +1413,13 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery $function = $current_function; } - if (!isset($function_map[$function])) { - throw new PhutilSearchQueryCompilerSyntaxException( - pht( - 'Unknown search function "%s".', - $function)); - } + $raw_field = $engine->getFieldForFunction($function); if (!isset($table_map[$function])) { $alias = 'ftfield'.$idx++; $table_map[$function] = array( 'alias' => $alias, - 'key' => $function_map[$function], + 'key' => $raw_field, ); } From af7c92f2c64ebe234cfeafaba740b22af9d63022 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Tue, 5 Sep 2017 15:21:12 -0700 Subject: [PATCH 08/54] Config re-design Summary: This is a full UI pass at a cleaner "Config" application. The main idea is to simplify the UI, center it, and have a different feel than other UI, a sort of "manage" UI theme for objects with loads of settings. Also adds a new minimalistic "WHITE_CONFIG" box type which may get re-used in Diffusion settings. This is a 90% pass, I'll have a few follow up diffs. Specifically: - Build breadcrumbs as a flexible UI to go into headers. - One click ObjectItemView option, for hover states. - Sidenav doesn't always select (AphrontFilter issue) - Mobile touchups, though it's pretty reasonable. Test Plan: Click through every page here, edit options, see new navigation UI. Test a few various setup issue layouts including fatals. {F5163228} {F5163229} {F5163230} {F5163231} {F5163232} {F5163233} {F5163234} Reviewers: epriestley Reviewed By: epriestley Spies: Korvin, epriestley Differential Revision: https://secure.phabricator.com/D18519 --- resources/celerity/map.php | 26 ++-- src/__phutil_library_map__.php | 2 - .../PhabricatorConfigGroupConstants.php | 13 +- .../PhabricatorConfigAllController.php | 28 ++-- ...PhabricatorConfigApplicationController.php | 25 ++-- .../PhabricatorConfigCacheController.php | 58 +++----- ...icatorConfigClusterDatabasesController.php | 33 ++--- ...orConfigClusterNotificationsController.php | 35 +++-- ...torConfigClusterRepositoriesController.php | 48 +++---- ...abricatorConfigClusterSearchController.php | 48 +++---- .../PhabricatorConfigController.php | 36 ++++- ...abricatorConfigDatabaseIssueController.php | 25 ++-- ...bricatorConfigDatabaseStatusController.php | 51 ++++--- .../PhabricatorConfigEditController.php | 134 +++++++++--------- .../PhabricatorConfigGroupController.php | 35 +++-- .../PhabricatorConfigHistoryController.php | 21 ++- .../PhabricatorConfigIssueListController.php | 32 ++--- .../PhabricatorConfigIssueViewController.php | 12 +- .../PhabricatorConfigListController.php | 21 ++- .../PhabricatorConfigModuleController.php | 23 ++- .../PhabricatorConfigVersionController.php | 27 ++-- .../config/view/PhabricatorConfigPageView.php | 60 -------- src/view/phui/PHUIObjectBoxView.php | 1 + .../css/application/config/config-options.css | 22 +-- .../css/application/config/config-page.css | 77 ---------- .../css/phui/object-item/phui-oi-big-ui.css | 15 +- webroot/rsrc/css/phui/phui-box.css | 21 +++ webroot/rsrc/css/phui/phui-header-view.css | 8 +- 28 files changed, 429 insertions(+), 508 deletions(-) delete mode 100644 src/applications/config/view/PhabricatorConfigPageView.php delete mode 100644 webroot/rsrc/css/application/config/config-page.css diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 673f1952f1..276da03a0e 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -9,7 +9,7 @@ return array( 'names' => array( 'conpherence.pkg.css' => 'e68cf1fa', 'conpherence.pkg.js' => 'b5b51108', - 'core.pkg.css' => '1071e7a2', + 'core.pkg.css' => '042e1782', 'core.pkg.js' => '6c085267', 'darkconsole.pkg.js' => '1f9a31bc', 'differential.pkg.css' => '45951e9e', @@ -45,8 +45,7 @@ return array( 'rsrc/css/application/base/standard-page-view.css' => '34ee718b', 'rsrc/css/application/chatlog/chatlog.css' => 'd295b020', 'rsrc/css/application/conduit/conduit-api.css' => '7bc725c4', - 'rsrc/css/application/config/config-options.css' => 'd55ed093', - 'rsrc/css/application/config/config-page.css' => 'c1d5121b', + 'rsrc/css/application/config/config-options.css' => '4615667b', 'rsrc/css/application/config/config-template.css' => '8f18fa41', 'rsrc/css/application/config/setup-issue.css' => '7dae7f18', 'rsrc/css/application/config/unhandled-exception.css' => '4c96257a', @@ -132,7 +131,7 @@ return array( 'rsrc/css/phui/calendar/phui-calendar-list.css' => '576be600', 'rsrc/css/phui/calendar/phui-calendar-month.css' => '21154caf', 'rsrc/css/phui/calendar/phui-calendar.css' => 'f1ddf11c', - 'rsrc/css/phui/object-item/phui-oi-big-ui.css' => '19f9369b', + 'rsrc/css/phui/object-item/phui-oi-big-ui.css' => '628f59de', 'rsrc/css/phui/object-item/phui-oi-color.css' => 'cd2b9b77', 'rsrc/css/phui/object-item/phui-oi-drag-ui.css' => '08f4ccc3', 'rsrc/css/phui/object-item/phui-oi-flush-ui.css' => '9d9685d6', @@ -143,7 +142,7 @@ return array( 'rsrc/css/phui/phui-badge.css' => '22c0cf4f', 'rsrc/css/phui/phui-basic-nav-view.css' => '98c11ab3', 'rsrc/css/phui/phui-big-info-view.css' => 'acc3492c', - 'rsrc/css/phui/phui-box.css' => '745e881d', + 'rsrc/css/phui/phui-box.css' => '4165eb0d', 'rsrc/css/phui/phui-chart.css' => '6bf6f78e', 'rsrc/css/phui/phui-cms.css' => '504b4b23', 'rsrc/css/phui/phui-comment-form.css' => 'ac68149f', @@ -158,7 +157,7 @@ return array( 'rsrc/css/phui/phui-form-view.css' => 'ae9f8d16', 'rsrc/css/phui/phui-form.css' => '7aaa04e3', 'rsrc/css/phui/phui-head-thing.css' => 'fd311e5f', - 'rsrc/css/phui/phui-header-view.css' => '859c5150', + 'rsrc/css/phui/phui-header-view.css' => '3c722648', 'rsrc/css/phui/phui-hovercard.css' => 'f0592bcf', 'rsrc/css/phui/phui-icon-set-selector.css' => '87db8fee', 'rsrc/css/phui/phui-icon.css' => '5c4a5de6', @@ -551,8 +550,7 @@ return array( 'auth-css' => '0877ed6e', 'bulk-job-css' => 'df9c1d4a', 'conduit-api-css' => '7bc725c4', - 'config-options-css' => 'd55ed093', - 'config-page-css' => 'c1d5121b', + 'config-options-css' => '4615667b', 'conpherence-color-css' => 'abb4c358', 'conpherence-durable-column-view' => '89ea6bef', 'conpherence-header-pane-css' => 'cb6f4e19', @@ -822,7 +820,7 @@ return array( 'phui-badge-view-css' => '22c0cf4f', 'phui-basic-nav-view-css' => '98c11ab3', 'phui-big-info-view-css' => 'acc3492c', - 'phui-box-css' => '745e881d', + 'phui-box-css' => '4165eb0d', 'phui-button-bar-css' => 'f1ff5494', 'phui-button-css' => '1863cc6e', 'phui-button-simple-css' => '8e1baf68', @@ -845,7 +843,7 @@ return array( 'phui-form-css' => '7aaa04e3', 'phui-form-view-css' => 'ae9f8d16', 'phui-head-thing-view-css' => 'fd311e5f', - 'phui-header-view-css' => '859c5150', + 'phui-header-view-css' => '3c722648', 'phui-hovercard' => '1bd28176', 'phui-hovercard-view-css' => 'f0592bcf', 'phui-icon-set-selector-css' => '87db8fee', @@ -858,7 +856,7 @@ return array( 'phui-lightbox-css' => '0a035e40', 'phui-list-view-css' => '38f8c9bd', 'phui-object-box-css' => '9cff003c', - 'phui-oi-big-ui-css' => '19f9369b', + 'phui-oi-big-ui-css' => '628f59de', 'phui-oi-color-css' => 'cd2b9b77', 'phui-oi-drag-ui-css' => '08f4ccc3', 'phui-oi-flush-ui-css' => '9d9685d6', @@ -997,9 +995,6 @@ return array( '185bbd53' => array( 'javelin-install', ), - '19f9369b' => array( - 'phui-oi-list-view-css', - ), '1ad0a787' => array( 'javelin-install', 'javelin-reactor', @@ -1366,6 +1361,9 @@ return array( 'javelin-magical-init', 'javelin-util', ), + '628f59de' => array( + 'phui-oi-list-view-css', + ), '62dfea03' => array( 'javelin-install', 'javelin-util', diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 4ce066e802..7e30139059 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -2445,7 +2445,6 @@ phutil_register_library_map(array( 'PhabricatorConfigOption' => 'applications/config/option/PhabricatorConfigOption.php', 'PhabricatorConfigOptionType' => 'applications/config/custom/PhabricatorConfigOptionType.php', 'PhabricatorConfigPHIDModule' => 'applications/config/module/PhabricatorConfigPHIDModule.php', - 'PhabricatorConfigPageView' => 'applications/config/view/PhabricatorConfigPageView.php', 'PhabricatorConfigProxySource' => 'infrastructure/env/PhabricatorConfigProxySource.php', 'PhabricatorConfigPurgeCacheController' => 'applications/config/controller/PhabricatorConfigPurgeCacheController.php', 'PhabricatorConfigRegexOptionType' => 'applications/config/custom/PhabricatorConfigRegexOptionType.php', @@ -7734,7 +7733,6 @@ phutil_register_library_map(array( ), 'PhabricatorConfigOptionType' => 'Phobject', 'PhabricatorConfigPHIDModule' => 'PhabricatorConfigModule', - 'PhabricatorConfigPageView' => 'AphrontTagView', 'PhabricatorConfigProxySource' => 'PhabricatorConfigSource', 'PhabricatorConfigPurgeCacheController' => 'PhabricatorConfigController', 'PhabricatorConfigRegexOptionType' => 'PhabricatorConfigJSONOptionType', diff --git a/src/applications/config/constants/PhabricatorConfigGroupConstants.php b/src/applications/config/constants/PhabricatorConfigGroupConstants.php index d3200abf2b..7dba1ca808 100644 --- a/src/applications/config/constants/PhabricatorConfigGroupConstants.php +++ b/src/applications/config/constants/PhabricatorConfigGroupConstants.php @@ -28,8 +28,17 @@ abstract class PhabricatorConfigGroupConstants public static function getGroupURI($group) { $map = array( self::GROUP_CORE => '/', - self::GROUP_APPLICATION => pht('application/'), - self::GROUP_DEVELOPER => pht('developer/'), + self::GROUP_APPLICATION => 'application/', + self::GROUP_DEVELOPER => 'developer/', + ); + return idx($map, $group, '#'); + } + + public static function getGroupFullURI($group) { + $map = array( + self::GROUP_CORE => '/config/', + self::GROUP_APPLICATION => '/config/application/', + self::GROUP_DEVELOPER => '/config/developer/', ); return idx($map, $group, '#'); } diff --git a/src/applications/config/controller/PhabricatorConfigAllController.php b/src/applications/config/controller/PhabricatorConfigAllController.php index 421e0078cf..3a19eff006 100644 --- a/src/applications/config/controller/PhabricatorConfigAllController.php +++ b/src/applications/config/controller/PhabricatorConfigAllController.php @@ -49,29 +49,29 @@ final class PhabricatorConfigAllController )); $title = pht('Current Settings'); - - $crumbs = $this - ->buildApplicationCrumbs() - ->addTextCrumb($title) - ->setBorder(true); - - $header = id(new PHUIHeaderView()) - ->setHeader($title) - ->setProfileHeader(true); + $header = $this->buildHeaderView($title); $nav = $this->buildSideNavView(); $nav->selectFilter('all/'); - $content = id(new PhabricatorConfigPageView()) + $view = $this->buildConfigBoxView( + pht('All Settings'), + $table); + + $crumbs = $this->buildApplicationCrumbs() + ->addTextCrumb($title) + ->setBorder(true); + + $content = id(new PHUITwoColumnView()) ->setHeader($header) - ->setContent($table); + ->setNavigation($nav) + ->setFixed(true) + ->setMainColumn($view); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) - ->setNavigation($nav) - ->appendChild($content) - ->addClass('white-background'); + ->appendChild($content); } diff --git a/src/applications/config/controller/PhabricatorConfigApplicationController.php b/src/applications/config/controller/PhabricatorConfigApplicationController.php index 10f639adc7..b4f60982e7 100644 --- a/src/applications/config/controller/PhabricatorConfigApplicationController.php +++ b/src/applications/config/controller/PhabricatorConfigApplicationController.php @@ -11,28 +11,25 @@ final class PhabricatorConfigApplicationController $groups = PhabricatorApplicationConfigOptions::loadAll(); $apps_list = $this->buildConfigOptionsList($groups, 'apps'); + $apps_list = $this->buildConfigBoxView(pht('Applications'), $apps_list); $title = pht('Application Settings'); + $header = $this->buildHeaderView($title); - $header = id(new PHUIHeaderView()) - ->setHeader($title) - ->setProfileHeader(true); - - $crumbs = $this - ->buildApplicationCrumbs() - ->addTextCrumb(pht('Applications')) - ->setBorder(true); - - $content = id(new PhabricatorConfigPageView()) + $content = id(new PHUITwoColumnView()) ->setHeader($header) - ->setContent($apps_list); + ->setNavigation($nav) + ->setFixed(true) + ->setMainColumn($apps_list); + + $crumbs = $this->buildApplicationCrumbs() + ->addTextCrumb($title) + ->setBorder(true); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) - ->setNavigation($nav) - ->appendChild($content) - ->addClass('white-background'); + ->appendChild($content); } private function buildConfigOptionsList(array $groups, $type) { diff --git a/src/applications/config/controller/PhabricatorConfigCacheController.php b/src/applications/config/controller/PhabricatorConfigCacheController.php index 91b0be27cf..a23ab1f9c1 100644 --- a/src/applications/config/controller/PhabricatorConfigCacheController.php +++ b/src/applications/config/controller/PhabricatorConfigCacheController.php @@ -9,16 +9,15 @@ final class PhabricatorConfigCacheController $nav = $this->buildSideNavView(); $nav->selectFilter('cache/'); + $purge_button = id(new PHUIButtonView()) + ->setText(pht('Purge Caches')) + ->setHref('/config/cache/purge/') + ->setTag('a') + ->setWorkflow(true) + ->setIcon('fa-exclamation-triangle'); + $title = pht('Cache Status'); - - $header = id(new PHUIHeaderView()) - ->setHeader($title) - ->setProfileHeader(true); - - $crumbs = $this - ->buildApplicationCrumbs() - ->addTextCrumb(pht('Cache Status')) - ->setBorder(true); + $header = $this->buildHeaderView($title, $purge_button); $code_box = $this->renderCodeBox(); $data_box = $this->renderDataBox(); @@ -28,40 +27,27 @@ final class PhabricatorConfigCacheController $data_box, ); - $content = id(new PhabricatorConfigPageView()) + $crumbs = $this->buildApplicationCrumbs() + ->addTextCrumb($title) + ->setBorder(true); + + $content = id(new PHUITwoColumnView()) ->setHeader($header) - ->setContent($page); + ->setNavigation($nav) + ->setFixed(true) + ->setMainColumn($page); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) - ->setNavigation($nav) - ->appendChild($content) - ->addClass('white-background'); + ->appendChild($content); } private function renderCodeBox() { $cache = PhabricatorOpcodeCacheSpec::getActiveCacheSpec(); - $properties = id(new PHUIPropertyListView()); - $this->renderCommonProperties($properties, $cache); - - $purge_button = id(new PHUIButtonView()) - ->setText(pht('Purge Caches')) - ->setHref('/config/cache/purge/') - ->setTag('a') - ->setWorkflow(true) - ->setIcon('fa-exclamation-triangle'); - - $header = id(new PHUIHeaderView()) - ->setHeader(pht('Opcode Cache')) - ->addActionLink($purge_button); - - return id(new PHUIObjectBoxView()) - ->setHeader($header) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) - ->addPropertyList($properties); + return $this->buildConfigBoxView(pht('Opcode Cache'), $properties); } private function renderDataBox() { @@ -109,11 +95,9 @@ final class PhabricatorConfigCacheController )); } - return id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Data Cache')) - ->addPropertyList($properties) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) - ->setTable($table); + $properties = $this->buildConfigBoxView(pht('Data Cache'), $properties); + $table = $this->buildConfigBoxView(pht('Cache Storage'), $table); + return array($properties, $table); } private function renderCommonProperties( diff --git a/src/applications/config/controller/PhabricatorConfigClusterDatabasesController.php b/src/applications/config/controller/PhabricatorConfigClusterDatabasesController.php index 03dfa3f64c..43e5a15b9d 100644 --- a/src/applications/config/controller/PhabricatorConfigClusterDatabasesController.php +++ b/src/applications/config/controller/PhabricatorConfigClusterDatabasesController.php @@ -9,34 +9,31 @@ final class PhabricatorConfigClusterDatabasesController $title = pht('Cluster Database Status'); $doc_href = PhabricatorEnv::getDoclink('Cluster: Databases'); + $button = id(new PHUIButtonView()) + ->setIcon('fa-book') + ->setHref($doc_href) + ->setTag('a') + ->setText(pht('Documentation')); - $header = id(new PHUIHeaderView()) - ->setHeader($title) - ->setProfileHeader(true) - ->addActionLink( - id(new PHUIButtonView()) - ->setIcon('fa-book') - ->setHref($doc_href) - ->setTag('a') - ->setText(pht('Documentation'))); + $header = $this->buildHeaderView($title, $button); - $crumbs = $this - ->buildApplicationCrumbs() + $database_status = $this->buildClusterDatabaseStatus(); + $status = $this->buildConfigBoxView(pht('Status'), $database_status); + + $crumbs = $this->buildApplicationCrumbs() ->addTextCrumb($title) ->setBorder(true); - $database_status = $this->buildClusterDatabaseStatus(); - - $content = id(new PhabricatorConfigPageView()) + $content = id(new PHUITwoColumnView()) ->setHeader($header) - ->setContent($database_status); + ->setNavigation($nav) + ->setFixed(true) + ->setMainColumn($status); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) - ->setNavigation($nav) - ->appendChild($content) - ->addClass('white-background'); + ->appendChild($content); } private function buildClusterDatabaseStatus() { diff --git a/src/applications/config/controller/PhabricatorConfigClusterNotificationsController.php b/src/applications/config/controller/PhabricatorConfigClusterNotificationsController.php index cc0cc2bf45..443b51a903 100644 --- a/src/applications/config/controller/PhabricatorConfigClusterNotificationsController.php +++ b/src/applications/config/controller/PhabricatorConfigClusterNotificationsController.php @@ -9,34 +9,33 @@ final class PhabricatorConfigClusterNotificationsController $title = pht('Cluster Notifications'); $doc_href = PhabricatorEnv::getDoclink('Cluster: Notifications'); + $button = id(new PHUIButtonView()) + ->setIcon('fa-book') + ->setHref($doc_href) + ->setTag('a') + ->setText(pht('Documentation')); - $header = id(new PHUIHeaderView()) - ->setHeader($title) - ->setProfileHeader(true) - ->addActionLink( - id(new PHUIButtonView()) - ->setIcon('fa-book') - ->setHref($doc_href) - ->setTag('a') - ->setText(pht('Documentation'))); + $header = $this->buildHeaderView($title, $button); - $crumbs = $this - ->buildApplicationCrumbs() + $notification_status = $this->buildClusterNotificationStatus(); + $status = $this->buildConfigBoxView( + pht('Notifications Status'), + $notification_status); + + $crumbs = $this->buildApplicationCrumbs() ->addTextCrumb($title) ->setBorder(true); - $notification_status = $this->buildClusterNotificationStatus(); - - $content = id(new PhabricatorConfigPageView()) + $content = id(new PHUITwoColumnView()) ->setHeader($header) - ->setContent($notification_status); + ->setNavigation($nav) + ->setFixed(true) + ->setMainColumn($status); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) - ->setNavigation($nav) - ->appendChild($content) - ->addClass('white-background'); + ->appendChild($content); } private function buildClusterNotificationStatus() { diff --git a/src/applications/config/controller/PhabricatorConfigClusterRepositoriesController.php b/src/applications/config/controller/PhabricatorConfigClusterRepositoriesController.php index 3531c916a4..471c4cedf0 100644 --- a/src/applications/config/controller/PhabricatorConfigClusterRepositoriesController.php +++ b/src/applications/config/controller/PhabricatorConfigClusterRepositoriesController.php @@ -10,39 +10,39 @@ final class PhabricatorConfigClusterRepositoriesController $title = pht('Cluster Repository Status'); $doc_href = PhabricatorEnv::getDoclink('Cluster: Repositories'); + $button = id(new PHUIButtonView()) + ->setIcon('fa-book') + ->setHref($doc_href) + ->setTag('a') + ->setText(pht('Documentation')); - $header = id(new PHUIHeaderView()) - ->setHeader($title) - ->setProfileHeader(true) - ->addActionLink( - id(new PHUIButtonView()) - ->setIcon('fa-book') - ->setHref($doc_href) - ->setTag('a') - ->setText(pht('Documentation'))); - - $crumbs = $this - ->buildApplicationCrumbs() - ->addTextCrumb(pht('Repository Servers')) - ->setBorder(true); + $header = $this->buildHeaderView($title, $button); $repository_status = $this->buildClusterRepositoryStatus(); - $repository_errors = $this->buildClusterRepositoryErrors(); + $repo_status = $this->buildConfigBoxView( + pht('Repository Status'), $repository_status); - $content = id(new PhabricatorConfigPageView()) + $repository_errors = $this->buildClusterRepositoryErrors(); + $repo_errors = $this->buildConfigBoxView( + pht('Repository Errors'), $repository_errors); + + $crumbs = $this->buildApplicationCrumbs() + ->addTextCrumb($title) + ->setBorder(true); + + $content = id(new PHUITwoColumnView()) ->setHeader($header) - ->setContent( - array( - $repository_status, - $repository_errors, - )); + ->setNavigation($nav) + ->setFixed(true) + ->setMainColumn(array( + $repo_status, + $repo_errors, + )); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) - ->setNavigation($nav) - ->appendChild($content) - ->addClass('white-background'); + ->appendChild($content); } private function buildClusterRepositoryStatus() { diff --git a/src/applications/config/controller/PhabricatorConfigClusterSearchController.php b/src/applications/config/controller/PhabricatorConfigClusterSearchController.php index 4d3ce407ab..cd00ef73a0 100644 --- a/src/applications/config/controller/PhabricatorConfigClusterSearchController.php +++ b/src/applications/config/controller/PhabricatorConfigClusterSearchController.php @@ -10,33 +10,30 @@ final class PhabricatorConfigClusterSearchController $title = pht('Cluster Search'); $doc_href = PhabricatorEnv::getDoclink('Cluster: Search'); - $header = id(new PHUIHeaderView()) - ->setHeader($title) - ->setProfileHeader(true) - ->addActionLink( - id(new PHUIButtonView()) - ->setIcon('fa-book') - ->setHref($doc_href) - ->setTag('a') - ->setText(pht('Documentation'))); + $button = id(new PHUIButtonView()) + ->setIcon('fa-book') + ->setHref($doc_href) + ->setTag('a') + ->setText(pht('Documentation')); - $crumbs = $this - ->buildApplicationCrumbs($nav) - ->addTextCrumb($title) - ->setBorder(true); + $header = $this->buildHeaderView($title, $button); $search_status = $this->buildClusterSearchStatus(); - $content = id(new PhabricatorConfigPageView()) + $crumbs = $this->buildApplicationCrumbs() + ->addTextCrumb($title) + ->setBorder(true); + + $content = id(new PHUITwoColumnView()) ->setHeader($header) - ->setContent($search_status); + ->setNavigation($nav) + ->setFixed(true) + ->setMainColumn($search_status); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) - ->setNavigation($nav) - ->appendChild($content) - ->addClass('white-background'); + ->appendChild($content); } private function buildClusterSearchStatus() { @@ -105,15 +102,16 @@ final class PhabricatorConfigClusterSearchController ->setNoDataString(pht('No search servers are configured.')) ->setHeaders($head); - $view = id(new PHUIObjectBoxView()) - ->setHeaderText($service->getDisplayName()) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) - ->setTable($table); + $view = $this->buildConfigBoxView(pht('Search Servers'), $table); - if ($stats_view) { - $view->addPropertyList($stats_view); + $stats = null; + if ($stats_view->hasAnyProperties()) { + $stats = $this->buildConfigBoxView( + pht('%s Stats', $service->getDisplayName()), + $stats_view); } - return $view; + + return array($stats, $view); } private function renderIndexStats($stats) { diff --git a/src/applications/config/controller/PhabricatorConfigController.php b/src/applications/config/controller/PhabricatorConfigController.php index 2abf2b3b31..ad5ea6cd27 100644 --- a/src/applications/config/controller/PhabricatorConfigController.php +++ b/src/applications/config/controller/PhabricatorConfigController.php @@ -8,10 +8,10 @@ abstract class PhabricatorConfigController extends PhabricatorController { public function buildSideNavView($filter = null, $for_app = false) { + $guide_href = new PhutilURI('/guides/'); $nav = new AphrontSideNavFilterView(); $nav->setBaseURI(new PhutilURI($this->getApplicationURI())); - $nav->addLabel(pht('Configuration')); $nav->addFilter('/', pht('Core Settings'), null, 'fa-gear'); $nav->addFilter('application/', @@ -46,7 +46,6 @@ abstract class PhabricatorConfigController extends PhabricatorController { pht('Search Servers'), null, 'fa-search'); $nav->addLabel(pht('Modules')); - $modules = PhabricatorConfigModule::getAllModules(); foreach ($modules as $key => $module) { $nav->addFilter('module/'.$key.'/', @@ -60,4 +59,37 @@ abstract class PhabricatorConfigController extends PhabricatorController { return $this->buildSideNavView(null, true)->getMenu(); } + public function buildHeaderView($text, $action = null) { + $viewer = $this->getViewer(); + + $file = PhabricatorFile::loadBuiltin($viewer, 'projects/v3/manage.png'); + $image = $file->getBestURI($file); + $header = id(new PHUIHeaderView()) + ->setHeader($text) + ->setProfileHeader(true) + ->setImage($image); + + if ($action) { + $header->addActionLink($action); + } + + return $header; + } + + public function buildConfigBoxView($title, $content, $action = null) { + $header = id(new PHUIHeaderView()) + ->setHeader($title); + + if ($action) { + $header->addActionItem($action); + } + + $view = id(new PHUIObjectBoxView()) + ->setHeader($header) + ->appendChild($content) + ->setBackground(PHUIObjectBoxView::WHITE_CONFIG); + + return $view; + } + } diff --git a/src/applications/config/controller/PhabricatorConfigDatabaseIssueController.php b/src/applications/config/controller/PhabricatorConfigDatabaseIssueController.php index 7674d28f51..708a708043 100644 --- a/src/applications/config/controller/PhabricatorConfigDatabaseIssueController.php +++ b/src/applications/config/controller/PhabricatorConfigDatabaseIssueController.php @@ -12,10 +12,6 @@ final class PhabricatorConfigDatabaseIssueController $expect = $query->loadExpectedSchemata(); $comp_servers = $query->buildComparisonSchemata($expect, $actual); - $crumbs = $this->buildApplicationCrumbs(); - $crumbs->addTextCrumb(pht('Database Issues')); - $crumbs->setBorder(true); - // Collect all open issues. $issues = array(); foreach ($comp_servers as $ref_name => $comp) { @@ -158,24 +154,27 @@ final class PhabricatorConfigDatabaseIssueController } $title = pht('Database Issues'); - - $header = id(new PHUIHeaderView()) - ->setHeader($title) - ->setProfileHeader(true); + $header = $this->buildHeaderView($title); $nav = $this->buildSideNavView(); $nav->selectFilter('dbissue/'); - $content = id(new PhabricatorConfigPageView()) + $view = $this->buildConfigBoxView(pht('Issues'), $table); + + $crumbs = $this->buildApplicationCrumbs() + ->addTextCrumb($title) + ->setBorder(true); + + $content = id(new PHUITwoColumnView()) ->setHeader($header) - ->setContent($table); + ->setNavigation($nav) + ->setFixed(true) + ->setMainColumn($view); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) - ->setNavigation($nav) - ->appendChild($content) - ->addClass('white-background'); + ->appendChild($content); } } diff --git a/src/applications/config/controller/PhabricatorConfigDatabaseStatusController.php b/src/applications/config/controller/PhabricatorConfigDatabaseStatusController.php index d49a546387..a67c57e6f9 100644 --- a/src/applications/config/controller/PhabricatorConfigDatabaseStatusController.php +++ b/src/applications/config/controller/PhabricatorConfigDatabaseStatusController.php @@ -132,27 +132,24 @@ final class PhabricatorConfigDatabaseStatusController } $doc_link = PhabricatorEnv::getDoclink('Managing Storage Adjustments'); + $button = id(new PHUIButtonView()) + ->setTag('a') + ->setIcon('fa-book') + ->setHref($doc_link) + ->setText(pht('Documentation')); - $header = id(new PHUIHeaderView()) - ->setHeader($title) - ->setProfileHeader(true) - ->addActionLink( - id(new PHUIButtonView()) - ->setTag('a') - ->setIcon('fa-book') - ->setHref($doc_link) - ->setText(pht('Learn More'))); + $header = $this->buildHeaderView($title, $button); - $content = id(new PhabricatorConfigPageView()) + $content = id(new PHUITwoColumnView()) ->setHeader($header) - ->setContent($body); + ->setNavigation($nav) + ->setFixed(true) + ->setMainColumn($body); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) - ->setNavigation($nav) - ->appendChild($content) - ->addClass('white-background'); + ->appendChild($content); } @@ -221,11 +218,12 @@ final class PhabricatorConfigDatabaseStatusController )); $title = pht('Database Status'); - $properties = $this->buildProperties( array( ), $comp->getIssues()); + $properties = $this->buildConfigBoxView(pht('Properties'), $properties); + $table = $this->buildConfigBoxView(pht('Database'), $table); return $this->buildResponse($title, array($properties, $table)); } @@ -280,7 +278,7 @@ final class PhabricatorConfigDatabaseStatusController null, )); - $title = pht('Database: %s', $database_name); + $title = $database_name; $actual_database = $actual->getDatabase($database_name); if ($actual_database) { @@ -325,6 +323,9 @@ final class PhabricatorConfigDatabaseStatusController ), $database->getIssues()); + $properties = $this->buildConfigBoxView(pht('Properties'), $properties); + $table = $this->buildConfigBoxView(pht('Database'), $table); + return $this->buildResponse($title, array($properties, $table)); } @@ -503,7 +504,7 @@ final class PhabricatorConfigDatabaseStatusController null, )); - $title = pht('Database: %s.%s', $database_name, $table_name); + $title = pht('%s.%s', $database_name, $table_name); if ($actual_table) { $actual_collation = $actual_table->getCollation(); @@ -534,8 +535,14 @@ final class PhabricatorConfigDatabaseStatusController ), $table->getIssues()); + $box_header = pht('%s.%s', $database_name, $table_name); + + $properties = $this->buildConfigBoxView(pht('Properties'), $properties); + $table = $this->buildConfigBoxView(pht('Database'), $table_view); + $keys = $this->buildConfigBoxView(pht('Keys'), $keys_view); + return $this->buildResponse( - $title, array($properties, $table_view, $keys_view)); + $title, array($properties, $table, $keys)); } private function renderColumn( @@ -613,7 +620,7 @@ final class PhabricatorConfigDatabaseStatusController $title = pht( - 'Database Status: %s.%s.%s', + '%s.%s.%s', $database_name, $table_name, $column_name); @@ -671,6 +678,8 @@ final class PhabricatorConfigDatabaseStatusController ), $column->getIssues()); + $properties = $this->buildConfigBoxView(pht('Properties'), $properties); + return $this->buildResponse($title, $properties); } @@ -734,7 +743,7 @@ final class PhabricatorConfigDatabaseStatusController } $title = pht( - 'Database Status: %s.%s (%s)', + '%s.%s (%s)', $database_name, $table_name, $key_name); @@ -764,6 +773,8 @@ final class PhabricatorConfigDatabaseStatusController ), $key->getIssues()); + $properties = $this->buildConfigBoxView(pht('Properties'), $properties); + return $this->buildResponse($title, $properties); } diff --git a/src/applications/config/controller/PhabricatorConfigEditController.php b/src/applications/config/controller/PhabricatorConfigEditController.php index 783fcb4dd3..06df0de889 100644 --- a/src/applications/config/controller/PhabricatorConfigEditController.php +++ b/src/applications/config/controller/PhabricatorConfigEditController.php @@ -7,7 +7,6 @@ final class PhabricatorConfigEditController $viewer = $request->getViewer(); $key = $request->getURIData('key'); - $options = PhabricatorApplicationConfigOptions::loadAllOptions(); if (empty($options[$key])) { $ancient = PhabricatorExtraConfigSetupCheck::getAncientConfig(); @@ -104,44 +103,45 @@ final class PhabricatorConfigEditController $error_view = null; if ($errors) { $error_view = id(new PHUIInfoView()) + ->setSeverity(PHUIInfoView::SEVERITY_ERROR) ->setErrors($errors); } + $doc_href = PhabricatorEnv::getDoclink( + 'Configuration Guide: Locked and Hidden Configuration'); + + $doc_link = phutil_tag( + 'a', + array( + 'href' => $doc_href, + 'target' => '_blank', + ), + pht('Learn more about locked and hidden options.')); + $status_items = array(); + $tag = null; if ($option->getHidden()) { + $tag = id(new PHUITagView()) + ->setName(pht('Hidden')) + ->setColor(PHUITagView::COLOR_GREY) + ->setBorder(PHUITagView::BORDER_NONE) + ->setType(PHUITagView::TYPE_SHADE); + $message = pht( 'This configuration is hidden and can not be edited or viewed from '. 'the web interface.'); - - $status_items[] = id(new PHUIStatusItemView()) - ->setIcon('fa-eye-slash red') - ->setTarget(phutil_tag('strong', array(), pht('Configuration Hidden'))) - ->setNote($message); + $status_items[] = id(new PHUIInfoView()) + ->appendChild(array($message, ' ', $doc_link)); } else if ($option->getLocked()) { + $tag = id(new PHUITagView()) + ->setName(pht('Locked')) + ->setColor(PHUITagView::COLOR_RED) + ->setBorder(PHUITagView::BORDER_NONE) + ->setType(PHUITagView::TYPE_SHADE); + $message = $option->getLockedMessage(); - - $status_items[] = id(new PHUIStatusItemView()) - ->setIcon('fa-lock red') - ->setTarget(phutil_tag('strong', array(), pht('Configuration Locked'))) - ->setNote($message); - } - - if ($status_items) { - $doc_href = PhabricatorEnv::getDoclink( - 'Configuration Guide: Locked and Hidden Configuration'); - - $doc_link = phutil_tag( - 'a', - array( - 'href' => $doc_href, - 'target' => '_blank', - ), - pht('Configuration Guide: Locked and Hidden Configuration')); - - $status_items[] = id(new PHUIStatusItemView()) - ->setIcon('fa-book') - ->setTarget(phutil_tag('strong', array(), pht('Learn More'))) - ->setNote($doc_link); + $status_items[] = id(new PHUIInfoView()) + ->appendChild(array($message, ' ', $doc_link)); } if ($option->getHidden() || $option->getLocked()) { @@ -168,18 +168,6 @@ final class PhabricatorConfigEditController ->setUser($viewer) ->addHiddenInput('issue', $request->getStr('issue')); - if ($status_items) { - $status_view = id(new PHUIStatusListView()); - - foreach ($status_items as $status_item) { - $status_view->addItem($status_item); - } - - $form->appendControl( - id(new AphrontFormMarkupControl()) - ->setValue($status_view)); - } - $description = $option->getDescription(); if (strlen($description)) { $description_view = new PHUIRemarkupView($viewer, $description); @@ -213,56 +201,66 @@ final class PhabricatorConfigEditController ->setValue(pht('Save Config Entry'))); } + $current_config = null; if (!$option->getHidden()) { - $form->appendChild( - id(new AphrontFormMarkupControl()) - ->setLabel(pht('Current Configuration')) - ->setValue($this->renderDefaults($option, $config_entry))); + $current_config = $this->renderDefaults($option, $config_entry); + $current_config = $this->buildConfigBoxView( + pht('Current Configuration'), + $current_config); } $examples = $this->renderExamples($option); if ($examples) { - $form->appendChild( - id(new AphrontFormMarkupControl()) - ->setLabel(pht('Examples')) - ->setValue($examples)); + $examples = $this->buildConfigBoxView( + pht('Examples'), + $examples); } - $title = pht('Edit Option: %s', $key); - $header_icon = 'fa-pencil'; - $short = pht('Edit'); + $title = $key; - $form_box = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Config Option')) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) - ->setForm($form); - - if ($error_view) { - $form_box->setInfoView($error_view); + $box_header = array(); + if ($group) { + $box_header[] = phutil_tag( + 'a', + array( + 'href' => $group_uri, + ), + $group->getName()); + $box_header[] = " \xC2\xBB "; } + $box_header[] = $key; $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb(pht('Config'), $this->getApplicationURI()); - if ($group) { $crumbs->addTextCrumb($group->getName(), $group_uri); } - $crumbs->addTextCrumb($key, '/config/edit/'.$key); $crumbs->setBorder(true); + $form_box = $this->buildConfigBoxView($box_header, $form, $tag); + $timeline = $this->buildTransactionTimeline( $config_entry, new PhabricatorConfigTransactionQuery()); $timeline->setShouldTerminate(true); - $header = id(new PHUIHeaderView()) - ->setHeader($title) - ->setHeaderIcon($header_icon); + $nav = $this->buildSideNavView(); + $nav->selectFilter($group_uri); + + $header = $this->buildHeaderView($title); $view = id(new PHUITwoColumnView()) ->setHeader($header) - ->setFooter($form_box); + ->setNavigation($nav) + ->setFixed(true) + ->setMainColumn(array( + $error_view, + $form_box, + $status_items, + $examples, + $current_config, + )); return $this->newPage() ->setTitle($title) @@ -426,7 +424,7 @@ final class PhabricatorConfigEditController } } - $table[] = phutil_tag('tr', array(), array( + $table[] = phutil_tag('tr', array('class' => 'column-labels'), array( phutil_tag('th', array(), $description), phutil_tag('td', array(), $value), )); @@ -438,6 +436,8 @@ final class PhabricatorConfigEditController 'table', array( 'class' => 'config-option-table', + 'cellspacing' => '0', + 'cellpadding' => '0', ), $table); } @@ -497,6 +497,8 @@ final class PhabricatorConfigEditController 'table', array( 'class' => 'config-option-table', + 'cellspacing' => '0', + 'cellpadding' => '0', ), $table); } diff --git a/src/applications/config/controller/PhabricatorConfigGroupController.php b/src/applications/config/controller/PhabricatorConfigGroupController.php index 6e713f7eab..920b2092ac 100644 --- a/src/applications/config/controller/PhabricatorConfigGroupController.php +++ b/src/applications/config/controller/PhabricatorConfigGroupController.php @@ -13,7 +13,7 @@ final class PhabricatorConfigGroupController return new Aphront404Response(); } - $group_uri = PhabricatorConfigGroupConstants::getGroupURI( + $group_uri = PhabricatorConfigGroupConstants::getGroupFullURI( $options->getGroup()); $group_name = PhabricatorConfigGroupConstants::getGroupShortName( $options->getGroup()); @@ -22,28 +22,28 @@ final class PhabricatorConfigGroupController $nav->selectFilter($group_uri); $title = pht('%s Configuration', $options->getName()); + $header = $this->buildHeaderView($title); $list = $this->buildOptionList($options->getOptions()); + $group_url = phutil_tag('a', array('href' => $group_uri), $group_name); - $crumbs = $this - ->buildApplicationCrumbs() + $box_header = pht("%s \xC2\xBB %s", $group_url, $options->getName()); + $view = $this->buildConfigBoxView($box_header, $list); + + $crumbs = $this->buildApplicationCrumbs() ->addTextCrumb($group_name, $this->getApplicationURI($group_uri)) ->addTextCrumb($options->getName()) ->setBorder(true); - $header = id(new PHUIHeaderView()) - ->setHeader($title) - ->setProfileHeader(true); - - $content = id(new PhabricatorConfigPageView()) + $content = id(new PHUITwoColumnView()) ->setHeader($header) - ->setContent($list); + ->setNavigation($nav) + ->setFixed(true) + ->setMainColumn($view); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) - ->setNavigation($nav) - ->appendChild($content) - ->addClass('white-background'); + ->appendChild($content); } private function buildOptionList(array $options) { @@ -77,13 +77,11 @@ final class PhabricatorConfigGroupController ->setHref('/config/edit/'.$option->getKey().'/') ->addAttribute($summary); - $label = pht('Current Value:'); $color = null; $db_value = idx($db_values, $option->getKey()); if ($db_value && !$db_value->getIsDeleted()) { $item->setEffect('visited'); $color = 'violet'; - $label = pht('Customized Value:'); } if ($option->getHidden()) { @@ -91,6 +89,8 @@ final class PhabricatorConfigGroupController $item->setDisabled(true); } else if ($option->getLocked()) { $item->setStatusIcon('fa-lock '.$color, pht('Locked')); + } else if ($color) { + $item->setStatusIcon('fa-pencil '.$color, pht('Editable')); } else { $item->setStatusIcon('fa-pencil-square-o '.$color, pht('Editable')); } @@ -102,14 +102,13 @@ final class PhabricatorConfigGroupController $current_value = phutil_tag( 'div', array( - 'class' => 'config-options-current-value', + 'class' => 'config-options-current-value '.$color, ), array( - phutil_tag('span', array(), $label), - ' '.$current_value, + $current_value, )); - $item->appendChild($current_value); + $item->setSideColumn($current_value); } $list->addItem($item); diff --git a/src/applications/config/controller/PhabricatorConfigHistoryController.php b/src/applications/config/controller/PhabricatorConfigHistoryController.php index eb7fbf607b..238d09234d 100644 --- a/src/applications/config/controller/PhabricatorConfigHistoryController.php +++ b/src/applications/config/controller/PhabricatorConfigHistoryController.php @@ -29,28 +29,25 @@ final class PhabricatorConfigHistoryController $object->willRenderTimeline($timeline, $this->getRequest()); $title = pht('Settings History'); - - $crumbs = $this->buildApplicationCrumbs(); - $crumbs->addTextCrumb($title); - $crumbs->setBorder(true); + $header = $this->buildHeaderView($title); $nav = $this->buildSideNavView(); $nav->selectFilter('history/'); - $header = id(new PHUIHeaderView()) - ->setHeader($title) - ->setProfileHeader(true); + $crumbs = $this->buildApplicationCrumbs() + ->addTextCrumb($title) + ->setBorder(true); - $content = id(new PhabricatorConfigPageView()) + $content = id(new PHUITwoColumnView()) ->setHeader($header) - ->setContent($timeline); + ->setNavigation($nav) + ->setFixed(true) + ->setMainColumn($timeline); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) - ->setNavigation($nav) - ->appendChild($content) - ->addClass('white-background'); + ->appendChild($content); } } diff --git a/src/applications/config/controller/PhabricatorConfigIssueListController.php b/src/applications/config/controller/PhabricatorConfigIssueListController.php index 869f53c223..770f79a9f2 100644 --- a/src/applications/config/controller/PhabricatorConfigIssueListController.php +++ b/src/applications/config/controller/PhabricatorConfigIssueListController.php @@ -43,34 +43,34 @@ final class PhabricatorConfigIssueListController } $title = pht('Setup Issues'); + $header = $this->buildHeaderView($title); - $header = id(new PHUIHeaderView()) - ->setHeader($title) - ->setProfileHeader(true); - - $crumbs = $this - ->buildApplicationCrumbs() - ->addTextCrumb(pht('Setup Issues')) - ->setBorder(true); - - $page = array( - $no_issues, + $issue_list = array( $important, $php, $mysql, $other, ); - $content = id(new PhabricatorConfigPageView()) + $issue_list = $this->buildConfigBoxView(pht('Issues'), $issue_list); + + $crumbs = $this->buildApplicationCrumbs() + ->addTextCrumb($title) + ->setBorder(true); + + $content = id(new PHUITwoColumnView()) ->setHeader($header) - ->setContent($page); + ->setNavigation($nav) + ->setFixed(true) + ->setMainColumn(array( + $no_issues, + $issue_list, + )); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) - ->setNavigation($nav) - ->appendChild($content) - ->addClass('white-background'); + ->appendChild($content); } private function buildIssueList(array $issues, $group, $fonticon) { diff --git a/src/applications/config/controller/PhabricatorConfigIssueViewController.php b/src/applications/config/controller/PhabricatorConfigIssueViewController.php index 43946a3e7b..29c9078413 100644 --- a/src/applications/config/controller/PhabricatorConfigIssueViewController.php +++ b/src/applications/config/controller/PhabricatorConfigIssueViewController.php @@ -36,6 +36,8 @@ final class PhabricatorConfigIssueViewController $title = $issue->getShortName(); } + $header = $this->buildHeaderView($title); + $crumbs = $this ->buildApplicationCrumbs() ->setBorder(true) @@ -43,12 +45,16 @@ final class PhabricatorConfigIssueViewController ->addTextCrumb($title, $request->getRequestURI()) ->setBorder(true); + $content = id(new PHUITwoColumnView()) + ->setHeader($header) + ->setNavigation($nav) + ->setFixed(true) + ->setMainColumn($content); + return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) - ->setNavigation($nav) - ->appendChild($content) - ->addClass('white-background'); + ->appendChild($content); } private function renderIssue(PhabricatorSetupIssue $issue) { diff --git a/src/applications/config/controller/PhabricatorConfigListController.php b/src/applications/config/controller/PhabricatorConfigListController.php index 517fe014a9..1a136ea416 100644 --- a/src/applications/config/controller/PhabricatorConfigListController.php +++ b/src/applications/config/controller/PhabricatorConfigListController.php @@ -11,28 +11,25 @@ final class PhabricatorConfigListController $groups = PhabricatorApplicationConfigOptions::loadAll(); $core_list = $this->buildConfigOptionsList($groups, 'core'); + $core_list = $this->buildConfigBoxView(pht('Core'), $core_list); $title = pht('Core Settings'); + $header = $this->buildHeaderView($title); - $header = id(new PHUIHeaderView()) - ->setHeader($title) - ->setProfileHeader(true); - - $crumbs = $this - ->buildApplicationCrumbs() - ->addTextCrumb(pht('Core')) + $crumbs = $this->buildApplicationCrumbs() + ->addTextCrumb($title) ->setBorder(true); - $content = id(new PhabricatorConfigPageView()) + $content = id(new PHUITwoColumnView()) ->setHeader($header) - ->setContent($core_list); + ->setNavigation($nav) + ->setFixed(true) + ->setMainColumn($core_list); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) - ->setNavigation($nav) - ->appendChild($content) - ->addClass('white-background'); + ->appendChild($content); } private function buildConfigOptionsList(array $groups, $type) { diff --git a/src/applications/config/controller/PhabricatorConfigModuleController.php b/src/applications/config/controller/PhabricatorConfigModuleController.php index e10d70561b..63cc5b3843 100644 --- a/src/applications/config/controller/PhabricatorConfigModuleController.php +++ b/src/applications/config/controller/PhabricatorConfigModuleController.php @@ -16,27 +16,26 @@ final class PhabricatorConfigModuleController $content = $module->renderModuleStatus($request); $title = $module->getModuleName(); - $crumbs = $this->buildApplicationCrumbs(); - $crumbs->addTextCrumb($title); - $crumbs->setBorder(true); - $nav = $this->buildSideNavView(); $nav->selectFilter('module/'.$key.'/'); + $header = $this->buildHeaderView($title); - $header = id(new PHUIHeaderView()) - ->setHeader($title) - ->setProfileHeader(true); + $view = $this->buildConfigBoxView($title, $content); - $content = id(new PhabricatorConfigPageView()) + $crumbs = $this->buildApplicationCrumbs() + ->addTextCrumb($title) + ->setBorder(true); + + $content = id(new PHUITwoColumnView()) ->setHeader($header) - ->setContent($content); + ->setNavigation($nav) + ->setFixed(true) + ->setMainColumn($view); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) - ->setNavigation($nav) - ->appendChild($content) - ->addClass('white-background'); + ->appendChild($content); } } diff --git a/src/applications/config/controller/PhabricatorConfigVersionController.php b/src/applications/config/controller/PhabricatorConfigVersionController.php index ca638051e4..8a87dec5cc 100644 --- a/src/applications/config/controller/PhabricatorConfigVersionController.php +++ b/src/applications/config/controller/PhabricatorConfigVersionController.php @@ -7,31 +7,30 @@ final class PhabricatorConfigVersionController $viewer = $request->getViewer(); $title = pht('Version Information'); - - $crumbs = $this - ->buildApplicationCrumbs() - ->addTextCrumb($title) - ->setBorder(true); - $versions = $this->renderModuleStatus($viewer); $nav = $this->buildSideNavView(); $nav->selectFilter('version/'); + $header = $this->buildHeaderView($title); - $header = id(new PHUIHeaderView()) - ->setHeader($title) - ->setProfileHeader(true); + $view = $this->buildConfigBoxView( + pht('Installed Versions'), + $versions); - $content = id(new PhabricatorConfigPageView()) + $crumbs = $this->buildApplicationCrumbs() + ->addTextCrumb($title) + ->setBorder(true); + + $content = id(new PHUITwoColumnView()) ->setHeader($header) - ->setContent($versions); + ->setNavigation($nav) + ->setFixed(true) + ->setMainColumn($view); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) - ->setNavigation($nav) - ->appendChild($content) - ->addClass('white-background'); + ->appendChild($content); } diff --git a/src/applications/config/view/PhabricatorConfigPageView.php b/src/applications/config/view/PhabricatorConfigPageView.php deleted file mode 100644 index 9fed2d4f47..0000000000 --- a/src/applications/config/view/PhabricatorConfigPageView.php +++ /dev/null @@ -1,60 +0,0 @@ -header = $header; - return $this; - } - - public function setContent($content) { - $this->content = $content; - return $this; - } - - public function setFooter($footer) { - $this->footer = $footer; - return $this; - } - - protected function getTagName() { - return 'div'; - } - - protected function getTagAttributes() { - require_celerity_resource('config-page-css'); - - $classes = array(); - $classes[] = 'config-page'; - - return array( - 'class' => implode(' ', $classes), - ); - } - - protected function getTagContent() { - - $header = null; - if ($this->header) { - $header = phutil_tag_div('config-page-header', $this->header); - } - - $content = null; - if ($this->content) { - $content = phutil_tag_div('config-page-content', $this->content); - } - - $footer = null; - if ($this->footer) { - $footer = phutil_tag_div('config-page-footer', $this->footer); - } - - return array($header, $content, $footer); - - } - -} diff --git a/src/view/phui/PHUIObjectBoxView.php b/src/view/phui/PHUIObjectBoxView.php index 0089e8e26e..f5fdbfffc4 100644 --- a/src/view/phui/PHUIObjectBoxView.php +++ b/src/view/phui/PHUIObjectBoxView.php @@ -35,6 +35,7 @@ final class PHUIObjectBoxView extends AphrontTagView { const BLUE = 'phui-box-blue'; const BLUE_PROPERTY = 'phui-box-blue-property'; + const WHITE_CONFIG = 'phui-box-white-config'; const GREY = 'phui-box-grey'; public function addPropertyList(PHUIPropertyListView $property_list) { diff --git a/webroot/rsrc/css/application/config/config-options.css b/webroot/rsrc/css/application/config/config-options.css index d8a6af6012..0c80e31b5e 100644 --- a/webroot/rsrc/css/application/config/config-options.css +++ b/webroot/rsrc/css/application/config/config-options.css @@ -5,20 +5,20 @@ .config-option-table { width: 100%; border-collapse: collapse; - border: 1px solid {$thinblueborder}; + border: none; background: {$page.content}; } .config-option-table th, .config-option-table td { - padding: 4px 12px; - border: 1px solid {$lightgreyborder}; + padding: 8px 12px; + border-bottom: 1px solid {$thinblueborder}; } .config-option-table th { background: {$lightgreybackground}; color: {$bluetext}; - text-align: right; + text-align: left; white-space: nowrap; } @@ -37,17 +37,19 @@ .config-option-table .column-labels th { font-weight: bold; color: {$bluetext}; - text-align: center; - background: {$greybackground}; + background: {$lightgreybackground}; + border-right: 1px solid {$thinblueborder}; } .config-options-current-value { - padding: 0 8px 6px; - white-space: pre-wrap; + white-space: nowrap; + width: 200px; + text-overflow: ellipsis; + overflow: hidden; } -.config-options-current-value span { - color: {$greytext}; +.config-options-current-value.violet { + color: {$violet}; } .config-options-effective-value, diff --git a/webroot/rsrc/css/application/config/config-page.css b/webroot/rsrc/css/application/config/config-page.css deleted file mode 100644 index 82cb9642d2..0000000000 --- a/webroot/rsrc/css/application/config/config-page.css +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @provides config-page-css - */ - -.config-page-header { - margin: 28px 24px 0; - padding-bottom: 28px; - border-bottom: 1px solid {$thinblueborder}; -} - -.device-phone .config-page-header { - margin: 4px 12px 0; - padding-bottom: 4px; -} - -.config-page-header .phui-profile-header { - padding: 0; -} - -.device-phone .config-page-header .phui-profile-header { - padding-left: 4px; - padding-right: 4px; -} - -.config-page-header .phui-profile-header.phui-header-shell .phui-header-header { - font-size: 20px; -} - -.device-phone .config-page-header .phui-profile-header.phui-header-shell - .phui-header-header { - font-size: 16px; -} - -.config-page-content { - margin: 0 24px; -} - -.device-phone .config-page-content { - margin: 0 4px; -} - -.device-desktop .config-page-content .phui-oi-list-view { - padding-left: 0; - padding-right: 0; -} - -.device-desktop .config-page-content .phui-document-fluid .phui-document-view { - padding: 16px 0; - margin: 0; -} - -.config-page-content .aphront-table-view { - border: none; -} - -.config-page-property { - padding-top: 4px; - border-bottom: 1px solid {$thinblueborder}; -} - -.config-page-content .aphront-table-notice { - padding: 0; -} - -.config-page-content .aphront-table-notice .phui-info-view { - margin-left: 0; - margin-right: 0; -} - -.config-page-content .aphront-table-wrap + .aphront-table-wrap { - margin-top: 20px; - border-top: 1px solid {$thinblueborder}; -} - -.config-page-content .phui-box.phui-box-blue-property { - margin-top: 16px; -} diff --git a/webroot/rsrc/css/phui/object-item/phui-oi-big-ui.css b/webroot/rsrc/css/phui/object-item/phui-oi-big-ui.css index e4d636cf46..67ce566733 100644 --- a/webroot/rsrc/css/phui/object-item/phui-oi-big-ui.css +++ b/webroot/rsrc/css/phui/object-item/phui-oi-big-ui.css @@ -31,7 +31,7 @@ } .device-desktop .phui-oi-list-big .phui-oi { - margin-bottom: 8px; + margin-bottom: 4px; } .phui-oi-list-big .phui-oi-col0 { @@ -46,3 +46,16 @@ .phui-oi-list-big .phui-oi-visited a.phui-oi-link { color: {$violet}; } + +.phui-box-white-config .phui-oi-list-big.phui-oi-list-view { + padding: 8px 8px 4px; +} + +.phui-box-white-config .phui-oi-frame { + padding: 4px 8px 0; +} + +.device-desktop .phui-box-white-config .phui-oi:hover .phui-oi-frame { + background-color: {$hoverblue}; + border-radius: 3px; +} diff --git a/webroot/rsrc/css/phui/phui-box.css b/webroot/rsrc/css/phui/phui-box.css index 4c44fa04d6..2477437c06 100644 --- a/webroot/rsrc/css/phui/phui-box.css +++ b/webroot/rsrc/css/phui/phui-box.css @@ -115,3 +115,24 @@ body .phui-box-blue-property .phui-header-shell + .phui-object-box { .phui-header-shell { background: {$page.content}; } + +/* Config Boxes */ + +.phui-box-white-config.phui-box-border { + border-color: #e2e2e2; + border-radius: 5px; +} + +.phui-box-white-config.phui-object-box { + padding: 16px 0 0 0; +} + +.phui-box-white-config .phui-header-shell { + border-bottom: 1px solid #e2e2e2; + overflow: hidden; + padding: 0 16px 16px; +} + +.phui-box-white-config .phui-header-header { + color: {$bluetext}; +} diff --git a/webroot/rsrc/css/phui/phui-header-view.css b/webroot/rsrc/css/phui/phui-header-view.css index e0d75b903f..82816b0220 100644 --- a/webroot/rsrc/css/phui/phui-header-view.css +++ b/webroot/rsrc/css/phui/phui-header-view.css @@ -34,10 +34,6 @@ vertical-align: middle; } -.device-phone .phui-header-col3 { - vertical-align: top; -} - body .phui-header-shell.phui-header-no-backgound { background-color: transparent; border: none; @@ -341,6 +337,10 @@ body .phui-header-shell.phui-bleed-header color: {$blacktext}; } +.phui-profile-header .phui-header-col3 { + vertical-align: top; +} + .phui-header-view .phui-tag-indigo a { color: {$sh-indigotext}; } From 64b7778f3257ca49f40fe05a5ccb43788baa3e81 Mon Sep 17 00:00:00 2001 From: epriestley Date: Tue, 5 Sep 2017 15:58:34 -0700 Subject: [PATCH 09/54] Add support for relevance-ranking Ferret engine results Summary: Ref T12819. "Relevance" here just means "how many of your search terms are present in the title?" but that's about the best we can do anyway. Test Plan: Indexed tasks "A B", "A Z", "Z B", and "Z Z" (all with "A B" in comments). Searched for "A B". Got results ranked in the listed order, with "A B" as the most relevant hit for query "A B". Reviewers: chad Reviewed By: chad Maniphest Tasks: T12819 Differential Revision: https://secure.phabricator.com/D18539 --- ...PhabricatorCursorPagedPolicyAwareQuery.php | 121 +++++++++++++++++- 1 file changed, 120 insertions(+), 1 deletion(-) diff --git a/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php b/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php index 6aa493f1e0..04fafa7cd2 100644 --- a/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php +++ b/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php @@ -251,6 +251,7 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery } $select[] = $this->buildEdgeLogicSelectClause($conn); + $select[] = $this->buildFerretSelectClause($conn); return $select; } @@ -769,6 +770,13 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery } } + if ($this->supportsFerretEngine()) { + $orders['relevance'] = array( + 'vector' => array('rank', 'id'), + 'name' => pht('Relevence'), + ); + } + return $orders; } @@ -961,6 +969,14 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery } } + if ($this->supportsFerretEngine()) { + $columns['rank'] = array( + 'table' => null, + 'column' => '_ft_rank', + 'type' => 'int', + ); + } + $cache->setKey($cache_key, $columns); return $columns; @@ -1385,10 +1401,23 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery /* -( Ferret )------------------------------------------------------------- */ + public function supportsFerretEngine() { + $object = $this->newResultObject(); + return ($object instanceof PhabricatorFerretInterface); + } + + public function withFerretConstraint( PhabricatorFerretEngine $engine, array $fulltext_tokens) { + if (!$this->supportsFerretEngine()) { + throw new Exception( + pht( + 'Query ("%s") does not support the Ferret fulltext engine.', + get_class($this))); + } + if ($this->ferretEngine) { throw new Exception( pht( @@ -1416,7 +1445,7 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery $raw_field = $engine->getFieldForFunction($function); if (!isset($table_map[$function])) { - $alias = 'ftfield'.$idx++; + $alias = 'ftfield_'.$idx++; $table_map[$function] = array( 'alias' => $alias, 'key' => $raw_field, @@ -1426,11 +1455,101 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery $current_function = $function; } + // Join the title field separately so we can rank results. + $table_map['rank'] = array( + 'alias' => 'ft_rank', + 'key' => PhabricatorSearchDocumentFieldType::FIELD_TITLE, + ); + $this->ferretTables = $table_map; return $this; } + protected function buildFerretSelectClause(AphrontDatabaseConnection $conn) { + $select = array(); + + if (!$this->supportsFerretEngine()) { + return $select; + } + + if (!$this->ferretEngine) { + $select[] = '0 _ft_rank'; + return $select; + } + + $engine = $this->ferretEngine; + $stemmer = $engine->newStemmer(); + + $op_sub = PhutilSearchQueryCompiler::OPERATOR_SUBSTRING; + $op_not = PhutilSearchQueryCompiler::OPERATOR_NOT; + $table_alias = 'ft_rank'; + + $parts = array(); + foreach ($this->ferretTokens as $fulltext_token) { + $raw_token = $fulltext_token->getToken(); + $value = $raw_token->getValue(); + + if ($raw_token->getOperator() == $op_not) { + // Ignore "not" terms when ranking, since they aren't useful. + continue; + } + + if ($raw_token->getOperator() == $op_sub) { + $is_substring = true; + } else { + $is_substring = false; + } + + if ($is_substring) { + $parts[] = qsprintf( + $conn, + 'IF(%T.rawCorpus LIKE %~, 2, 0)', + $table_alias, + $value); + continue; + } + + if ($raw_token->isQuoted()) { + $is_quoted = true; + $is_stemmed = false; + } else { + $is_quoted = false; + $is_stemmed = true; + } + + $term_constraints = array(); + + $term_value = $engine->newTermsCorpus($value); + + $parts[] = qsprintf( + $conn, + 'IF(%T.termCorpus LIKE %~, 2, 0)', + $table_alias, + $term_value); + + if ($is_stemmed) { + $stem_value = $stemmer->stemToken($value); + $stem_value = $engine->newTermsCorpus($stem_value); + + $parts[] = qsprintf( + $conn, + 'IF(%T.normalCorpus LIKE %~, 1, 0)', + $table_alias, + $stem_value); + } + + $parts[] = '0'; + } + + $select[] = qsprintf( + $conn, + '%Q _ft_rank', + implode(' + ', $parts)); + + return $select; + } + protected function buildFerretJoinClause(AphrontDatabaseConnection $conn) { if (!$this->ferretEngine) { return array(); From f40f3ca74c919839d4777fe64d6b750a65256c37 Mon Sep 17 00:00:00 2001 From: epriestley Date: Tue, 5 Sep 2017 16:25:28 -0700 Subject: [PATCH 10/54] Add Ferret engine index support to Differential Summary: Ref T12819. Adds storage and indexing for the Ferret engine to Differential. Test Plan: Ran `bin/search index D123 --force`, saw indexes appear in database. No UI/user impact yet. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12819 Differential Revision: https://secure.phabricator.com/D18540 --- .../20170905.ferret.01.diff.doc.sql | 9 +++++++ .../20170905.ferret.02.diff.field.sql | 8 ++++++ .../20170905.ferret.03.diff.ngrams.sql | 5 ++++ src/__phutil_library_map__.php | 9 +++++++ .../DifferentialRevisionFerretEngine.php | 26 +++++++++++++++++++ .../storage/DifferentialRevision.php | 9 +++++++ .../DifferentialRevisionFerretDocument.php | 14 ++++++++++ .../DifferentialRevisionFerretField.php | 14 ++++++++++ .../DifferentialRevisionFerretNgrams.php | 14 ++++++++++ 9 files changed, 108 insertions(+) create mode 100644 resources/sql/autopatches/20170905.ferret.01.diff.doc.sql create mode 100644 resources/sql/autopatches/20170905.ferret.02.diff.field.sql create mode 100644 resources/sql/autopatches/20170905.ferret.03.diff.ngrams.sql create mode 100644 src/applications/differential/search/DifferentialRevisionFerretEngine.php create mode 100644 src/applications/differential/storage/DifferentialRevisionFerretDocument.php create mode 100644 src/applications/differential/storage/DifferentialRevisionFerretField.php create mode 100644 src/applications/differential/storage/DifferentialRevisionFerretNgrams.php diff --git a/resources/sql/autopatches/20170905.ferret.01.diff.doc.sql b/resources/sql/autopatches/20170905.ferret.01.diff.doc.sql new file mode 100644 index 0000000000..9fdadbf11c --- /dev/null +++ b/resources/sql/autopatches/20170905.ferret.01.diff.doc.sql @@ -0,0 +1,9 @@ +CREATE TABLE {$NAMESPACE}_differential.differential_revision_fdocument ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + objectPHID VARBINARY(64) NOT NULL, + isClosed BOOL NOT NULL, + authorPHID VARBINARY(64), + ownerPHID VARBINARY(64), + epochCreated INT UNSIGNED NOT NULL, + epochModified INT UNSIGNED NOT NULL +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/resources/sql/autopatches/20170905.ferret.02.diff.field.sql b/resources/sql/autopatches/20170905.ferret.02.diff.field.sql new file mode 100644 index 0000000000..ff5f065a39 --- /dev/null +++ b/resources/sql/autopatches/20170905.ferret.02.diff.field.sql @@ -0,0 +1,8 @@ +CREATE TABLE {$NAMESPACE}_differential.differential_revision_ffield ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + documentID INT UNSIGNED NOT NULL, + fieldKey VARCHAR(4) NOT NULL COLLATE {$COLLATE_TEXT}, + rawCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT}, + termCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT}, + normalCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT} +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/resources/sql/autopatches/20170905.ferret.03.diff.ngrams.sql b/resources/sql/autopatches/20170905.ferret.03.diff.ngrams.sql new file mode 100644 index 0000000000..ec12354e38 --- /dev/null +++ b/resources/sql/autopatches/20170905.ferret.03.diff.ngrams.sql @@ -0,0 +1,5 @@ +CREATE TABLE {$NAMESPACE}_differential.differential_revision_fngrams ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + documentID INT UNSIGNED NOT NULL, + ngram CHAR(3) NOT NULL COLLATE {$COLLATE_TEXT} +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 7e30139059..6af5144d95 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -532,6 +532,10 @@ phutil_register_library_map(array( 'DifferentialRevisionEditConduitAPIMethod' => 'applications/differential/conduit/DifferentialRevisionEditConduitAPIMethod.php', 'DifferentialRevisionEditController' => 'applications/differential/controller/DifferentialRevisionEditController.php', 'DifferentialRevisionEditEngine' => 'applications/differential/editor/DifferentialRevisionEditEngine.php', + 'DifferentialRevisionFerretDocument' => 'applications/differential/storage/DifferentialRevisionFerretDocument.php', + 'DifferentialRevisionFerretEngine' => 'applications/differential/search/DifferentialRevisionFerretEngine.php', + 'DifferentialRevisionFerretField' => 'applications/differential/storage/DifferentialRevisionFerretField.php', + 'DifferentialRevisionFerretNgrams' => 'applications/differential/storage/DifferentialRevisionFerretNgrams.php', 'DifferentialRevisionFulltextEngine' => 'applications/differential/search/DifferentialRevisionFulltextEngine.php', 'DifferentialRevisionGraph' => 'infrastructure/graph/DifferentialRevisionGraph.php', 'DifferentialRevisionHasChildRelationship' => 'applications/differential/relationships/DifferentialRevisionHasChildRelationship.php', @@ -5522,6 +5526,7 @@ phutil_register_library_map(array( 'PhabricatorDestructibleInterface', 'PhabricatorProjectInterface', 'PhabricatorFulltextInterface', + 'PhabricatorFerretInterface', 'PhabricatorConduitResultInterface', 'PhabricatorDraftInterface', ), @@ -5545,6 +5550,10 @@ phutil_register_library_map(array( 'DifferentialRevisionEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', 'DifferentialRevisionEditController' => 'DifferentialController', 'DifferentialRevisionEditEngine' => 'PhabricatorEditEngine', + 'DifferentialRevisionFerretDocument' => 'PhabricatorFerretDocument', + 'DifferentialRevisionFerretEngine' => 'PhabricatorFerretEngine', + 'DifferentialRevisionFerretField' => 'PhabricatorFerretField', + 'DifferentialRevisionFerretNgrams' => 'PhabricatorFerretNgrams', 'DifferentialRevisionFulltextEngine' => 'PhabricatorFulltextEngine', 'DifferentialRevisionGraph' => 'PhabricatorObjectGraph', 'DifferentialRevisionHasChildRelationship' => 'DifferentialRevisionRelationship', diff --git a/src/applications/differential/search/DifferentialRevisionFerretEngine.php b/src/applications/differential/search/DifferentialRevisionFerretEngine.php new file mode 100644 index 0000000000..0581cf281d --- /dev/null +++ b/src/applications/differential/search/DifferentialRevisionFerretEngine.php @@ -0,0 +1,26 @@ + Date: Tue, 5 Sep 2017 19:01:18 -0700 Subject: [PATCH 11/54] Update Repository Management pages to new fixed UI Summary: Simplifies the Repository Management pages to the new fixed column layout. I've also moved "Status" into the Basics page, which feels better, and moved "Documentation" as a nav item to a button in the header. This removed "action list" and "curtain view" from the management panels and uses the new bits from Config/Phacility. Undecided if the icons should stay or go for the nav. Left them in for Diffusion. I want to update the EditEngine pages to display in this UI and not leave the portal, but I haven't dug into that this page. I'm a bit worried it will not easily be possible. Test Plan: Generate a svn, git, hg repository, test each of the new pages and each of the new buttons. Activate, deactivate, etc. {F5164674} Reviewers: epriestley Reviewed By: epriestley Spies: Korvin Differential Revision: https://secure.phabricator.com/D18523 --- resources/celerity/map.php | 10 +- src/__phutil_library_map__.php | 4 - ...iffusionRepositoryEditUpdateController.php | 2 +- .../DiffusionRepositoryManageController.php | 16 + ...fusionRepositoryManagePanelsController.php | 84 +-- ...fusionRepositoryActionsManagementPanel.php | 55 +- ...ionRepositoryAutomationManagementPanel.php | 71 +-- ...ffusionRepositoryBasicsManagementPanel.php | 517 +++++++++++++++++- ...usionRepositoryBranchesManagementPanel.php | 61 +-- ...RepositoryDocumentationManagementPanel.php | 33 -- ...fusionRepositoryHistoryManagementPanel.php | 4 - .../DiffusionRepositoryManagementPanel.php | 34 +- ...usionRepositoryPoliciesManagementPanel.php | 70 +-- ...fusionRepositoryStagingManagementPanel.php | 50 +- ...ffusionRepositoryStatusManagementPanel.php | 507 ----------------- ...fusionRepositoryStorageManagementPanel.php | 42 +- ...ionRepositorySubversionManagementPanel.php | 49 +- ...fusionRepositorySymbolsManagementPanel.php | 52 +- ...DiffusionRepositoryURIsManagementPanel.php | 57 +- webroot/rsrc/css/phui/phui-box.css | 5 + webroot/rsrc/css/phui/phui-header-view.css | 4 + 21 files changed, 749 insertions(+), 978 deletions(-) delete mode 100644 src/applications/diffusion/management/DiffusionRepositoryDocumentationManagementPanel.php delete mode 100644 src/applications/diffusion/management/DiffusionRepositoryStatusManagementPanel.php diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 276da03a0e..8ca8f081df 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -9,7 +9,7 @@ return array( 'names' => array( 'conpherence.pkg.css' => 'e68cf1fa', 'conpherence.pkg.js' => 'b5b51108', - 'core.pkg.css' => '042e1782', + 'core.pkg.css' => 'ebbf04f7', 'core.pkg.js' => '6c085267', 'darkconsole.pkg.js' => '1f9a31bc', 'differential.pkg.css' => '45951e9e', @@ -142,7 +142,7 @@ return array( 'rsrc/css/phui/phui-badge.css' => '22c0cf4f', 'rsrc/css/phui/phui-basic-nav-view.css' => '98c11ab3', 'rsrc/css/phui/phui-big-info-view.css' => 'acc3492c', - 'rsrc/css/phui/phui-box.css' => '4165eb0d', + 'rsrc/css/phui/phui-box.css' => '9f3745fb', 'rsrc/css/phui/phui-chart.css' => '6bf6f78e', 'rsrc/css/phui/phui-cms.css' => '504b4b23', 'rsrc/css/phui/phui-comment-form.css' => 'ac68149f', @@ -157,7 +157,7 @@ return array( 'rsrc/css/phui/phui-form-view.css' => 'ae9f8d16', 'rsrc/css/phui/phui-form.css' => '7aaa04e3', 'rsrc/css/phui/phui-head-thing.css' => 'fd311e5f', - 'rsrc/css/phui/phui-header-view.css' => '3c722648', + 'rsrc/css/phui/phui-header-view.css' => '369275d6', 'rsrc/css/phui/phui-hovercard.css' => 'f0592bcf', 'rsrc/css/phui/phui-icon-set-selector.css' => '87db8fee', 'rsrc/css/phui/phui-icon.css' => '5c4a5de6', @@ -820,7 +820,7 @@ return array( 'phui-badge-view-css' => '22c0cf4f', 'phui-basic-nav-view-css' => '98c11ab3', 'phui-big-info-view-css' => 'acc3492c', - 'phui-box-css' => '4165eb0d', + 'phui-box-css' => '9f3745fb', 'phui-button-bar-css' => 'f1ff5494', 'phui-button-css' => '1863cc6e', 'phui-button-simple-css' => '8e1baf68', @@ -843,7 +843,7 @@ return array( 'phui-form-css' => '7aaa04e3', 'phui-form-view-css' => 'ae9f8d16', 'phui-head-thing-view-css' => 'fd311e5f', - 'phui-header-view-css' => '3c722648', + 'phui-header-view-css' => '369275d6', 'phui-hovercard' => '1bd28176', 'phui-hovercard-view-css' => 'f0592bcf', 'phui-icon-set-selector-css' => '87db8fee', diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 6af5144d95..e9244fd7ca 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -843,7 +843,6 @@ phutil_register_library_map(array( 'DiffusionRepositoryController' => 'applications/diffusion/controller/DiffusionRepositoryController.php', 'DiffusionRepositoryDatasource' => 'applications/diffusion/typeahead/DiffusionRepositoryDatasource.php', 'DiffusionRepositoryDefaultController' => 'applications/diffusion/controller/DiffusionRepositoryDefaultController.php', - 'DiffusionRepositoryDocumentationManagementPanel' => 'applications/diffusion/management/DiffusionRepositoryDocumentationManagementPanel.php', 'DiffusionRepositoryEditActivateController' => 'applications/diffusion/controller/DiffusionRepositoryEditActivateController.php', 'DiffusionRepositoryEditConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionRepositoryEditConduitAPIMethod.php', 'DiffusionRepositoryEditController' => 'applications/diffusion/controller/DiffusionRepositoryEditController.php', @@ -864,7 +863,6 @@ phutil_register_library_map(array( 'DiffusionRepositoryRemarkupRule' => 'applications/diffusion/remarkup/DiffusionRepositoryRemarkupRule.php', 'DiffusionRepositorySearchConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionRepositorySearchConduitAPIMethod.php', 'DiffusionRepositoryStagingManagementPanel' => 'applications/diffusion/management/DiffusionRepositoryStagingManagementPanel.php', - 'DiffusionRepositoryStatusManagementPanel' => 'applications/diffusion/management/DiffusionRepositoryStatusManagementPanel.php', 'DiffusionRepositoryStorageManagementPanel' => 'applications/diffusion/management/DiffusionRepositoryStorageManagementPanel.php', 'DiffusionRepositorySubversionManagementPanel' => 'applications/diffusion/management/DiffusionRepositorySubversionManagementPanel.php', 'DiffusionRepositorySymbolsManagementPanel' => 'applications/diffusion/management/DiffusionRepositorySymbolsManagementPanel.php', @@ -5863,7 +5861,6 @@ phutil_register_library_map(array( 'DiffusionRepositoryController' => 'DiffusionController', 'DiffusionRepositoryDatasource' => 'PhabricatorTypeaheadDatasource', 'DiffusionRepositoryDefaultController' => 'DiffusionController', - 'DiffusionRepositoryDocumentationManagementPanel' => 'DiffusionRepositoryManagementPanel', 'DiffusionRepositoryEditActivateController' => 'DiffusionRepositoryManageController', 'DiffusionRepositoryEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', 'DiffusionRepositoryEditController' => 'DiffusionRepositoryManageController', @@ -5884,7 +5881,6 @@ phutil_register_library_map(array( 'DiffusionRepositoryRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'DiffusionRepositorySearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod', 'DiffusionRepositoryStagingManagementPanel' => 'DiffusionRepositoryManagementPanel', - 'DiffusionRepositoryStatusManagementPanel' => 'DiffusionRepositoryManagementPanel', 'DiffusionRepositoryStorageManagementPanel' => 'DiffusionRepositoryManagementPanel', 'DiffusionRepositorySubversionManagementPanel' => 'DiffusionRepositoryManagementPanel', 'DiffusionRepositorySymbolsManagementPanel' => 'DiffusionRepositoryManagementPanel', diff --git a/src/applications/diffusion/controller/DiffusionRepositoryEditUpdateController.php b/src/applications/diffusion/controller/DiffusionRepositoryEditUpdateController.php index 4cb6ffda67..dd95654302 100644 --- a/src/applications/diffusion/controller/DiffusionRepositoryEditUpdateController.php +++ b/src/applications/diffusion/controller/DiffusionRepositoryEditUpdateController.php @@ -13,7 +13,7 @@ final class DiffusionRepositoryEditUpdateController $drequest = $this->getDiffusionRequest(); $repository = $drequest->getRepository(); - $panel_uri = id(new DiffusionRepositoryStatusManagementPanel()) + $panel_uri = id(new DiffusionRepositoryBasicsManagementPanel()) ->setRepository($repository) ->getPanelURI(); diff --git a/src/applications/diffusion/controller/DiffusionRepositoryManageController.php b/src/applications/diffusion/controller/DiffusionRepositoryManageController.php index 8b0740c540..b04e72960b 100644 --- a/src/applications/diffusion/controller/DiffusionRepositoryManageController.php +++ b/src/applications/diffusion/controller/DiffusionRepositoryManageController.php @@ -22,4 +22,20 @@ abstract class DiffusionRepositoryManageController return $crumbs; } + public function newBox($title, $content, $action = null) { + $header = id(new PHUIHeaderView()) + ->setHeader($title); + + if ($action) { + $header->addActionItem($action); + } + + $view = id(new PHUIObjectBoxView()) + ->setHeader($header) + ->appendChild($content) + ->setBackground(PHUIObjectBoxView::WHITE_CONFIG); + + return $view; + } + } diff --git a/src/applications/diffusion/controller/DiffusionRepositoryManagePanelsController.php b/src/applications/diffusion/controller/DiffusionRepositoryManagePanelsController.php index 12faa6799d..7871c5192a 100644 --- a/src/applications/diffusion/controller/DiffusionRepositoryManagePanelsController.php +++ b/src/applications/diffusion/controller/DiffusionRepositoryManagePanelsController.php @@ -53,6 +53,10 @@ final class DiffusionRepositoryManagePanelsController $panel = $panels[$selected]; + $crumbs = $this->buildApplicationCrumbs(); + $crumbs->addTextCrumb($panel->getManagementPanelLabel()); + $crumbs->setBorder(true); + $content = $panel->buildManagementPanelContent(); $title = array( @@ -60,45 +64,17 @@ final class DiffusionRepositoryManagePanelsController $repository->getDisplayName(), ); - $crumbs = $this->buildApplicationCrumbs(); - $crumbs->addTextCrumb($panel->getManagementPanelLabel()); - $crumbs->setBorder(true); - - $header_text = pht( - '%s: %s', - $repository->getDisplayName(), - $panel->getManagementPanelLabel()); - - $header = id(new PHUIHeaderView()) - ->setHeader($header_text) - ->setHeaderIcon('fa-pencil'); - if ($repository->isTracked()) { - $header->setStatus('fa-check', 'bluegrey', pht('Active')); - } else { - $header->setStatus('fa-ban', 'dark', pht('Inactive')); - } - - $header->addActionLink( - id(new PHUIButtonView()) - ->setTag('a') - ->setText(pht('View Repository')) - ->setHref($repository->getURI()) - ->setIcon('fa-code') - ->setColor(PHUIButtonView::GREEN)); + $header = $this->buildHeaderView($repository->getDisplayName()); $view = id(new PHUITwoColumnView()) ->setHeader($header) + ->setNavigation($nav) + ->setFixed(true) ->setMainColumn($content); - $curtain = $panel->buildManagementPanelCurtain(); - if ($curtain) { - $view->setCurtain($curtain); - } - return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) - ->setNavigation($nav) ->appendChild($view); } @@ -113,12 +89,6 @@ final class DiffusionRepositoryManagePanelsController $nav = id(new AphrontSideNavFilterView()) ->setBaseURI($base_uri); - $item = id(new PHUIListItemView()) - ->setName(pht('manage')) - ->setType(PHUIListItemView::TYPE_LABEL); - - $nav->addMenuItem($item); - foreach ($panels as $panel) { $key = $panel->getManagementPanelKey(); $label = $panel->getManagementPanelLabel(); @@ -140,6 +110,46 @@ final class DiffusionRepositoryManagePanelsController return $nav; } + public function buildHeaderView($title) { + $viewer = $this->getViewer(); + + $drequest = $this->getDiffusionRequest(); + $repository = $drequest->getRepository(); + + $header = id(new PHUIHeaderView()) + ->setHeader($title) + ->setProfileHeader(true) + ->setHref($repository->getURI()) + ->setImage($repository->getProfileImageURI()); + + if ($repository->isTracked()) { + $header->setStatus('fa-check', 'bluegrey', pht('Active')); + } else { + $header->setStatus('fa-ban', 'dark', pht('Inactive')); + } + + $doc_href = PhabricatorEnv::getDoclink( + 'Diffusion User Guide: Managing Repositories'); + + $header->addActionLink( + id(new PHUIButtonView()) + ->setTag('a') + ->setText(pht('View Repository')) + ->setHref($repository->getURI()) + ->setIcon('fa-code') + ->setColor(PHUIButtonView::GREY)); + + $header->addActionLink( + id(new PHUIButtonView()) + ->setTag('a') + ->setIcon('fa-book') + ->setHref($doc_href) + ->setText(pht('Help')) + ->setColor(PHUIButtonView::GREY)); + + return $header; + } + public function newTimeline(PhabricatorRepository $repository) { $timeline = $this->buildTransactionTimeline( $repository, diff --git a/src/applications/diffusion/management/DiffusionRepositoryActionsManagementPanel.php b/src/applications/diffusion/management/DiffusionRepositoryActionsManagementPanel.php index 83697e52e3..a5805fd0cc 100644 --- a/src/applications/diffusion/management/DiffusionRepositoryActionsManagementPanel.php +++ b/src/applications/diffusion/management/DiffusionRepositoryActionsManagementPanel.php @@ -14,20 +14,7 @@ final class DiffusionRepositoryActionsManagementPanel } public function getManagementPanelIcon() { - $repository = $this->getRepository(); - - $has_any = - $repository->getDetail('herald-disabled') || - $repository->getDetail('disable-autoclose'); - - // NOTE: Any value here really means something is disabled, so try to - // hint that a little bit with the icon. - - if ($has_any) { - return 'fa-comment-o'; - } else { - return 'fa-commenting grey'; - } + return 'fa-flash'; } protected function getEditEngineFieldKeys() { @@ -37,29 +24,6 @@ final class DiffusionRepositoryActionsManagementPanel ); } - public function buildManagementPanelCurtain() { - $repository = $this->getRepository(); - $viewer = $this->getViewer(); - $action_list = $this->getNewActionList(); - - $can_edit = PhabricatorPolicyFilter::hasCapability( - $viewer, - $repository, - PhabricatorPolicyCapability::CAN_EDIT); - - $actions_uri = $this->getEditPageURI(); - - $action_list->addAction( - id(new PhabricatorActionView()) - ->setIcon('fa-pencil') - ->setName(pht('Edit Actions')) - ->setHref($actions_uri) - ->setDisabled(!$can_edit) - ->setWorkflow(!$can_edit)); - - return $this->getNewCurtainView($action_list); - } - public function buildManagementPanelContent() { $repository = $this->getRepository(); $viewer = $this->getViewer(); @@ -79,7 +43,22 @@ final class DiffusionRepositoryActionsManagementPanel $autoclose = phutil_tag('em', array(), $autoclose); $view->addProperty(pht('Autoclose'), $autoclose); - return $this->newBox(pht('Actions'), $view); + $can_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + $repository, + PhabricatorPolicyCapability::CAN_EDIT); + + $actions_uri = $this->getEditPageURI(); + + $button = id(new PHUIButtonView()) + ->setTag('a') + ->setIcon('fa-pencil') + ->setText(pht('Edit')) + ->setHref($actions_uri) + ->setDisabled(!$can_edit) + ->setWorkflow(!$can_edit); + + return $this->newBox(pht('Actions'), $view, array($button)); } } diff --git a/src/applications/diffusion/management/DiffusionRepositoryAutomationManagementPanel.php b/src/applications/diffusion/management/DiffusionRepositoryAutomationManagementPanel.php index b37aa05ecf..22afd5a53b 100644 --- a/src/applications/diffusion/management/DiffusionRepositoryAutomationManagementPanel.php +++ b/src/applications/diffusion/management/DiffusionRepositoryAutomationManagementPanel.php @@ -27,59 +27,18 @@ final class DiffusionRepositoryAutomationManagementPanel public function getManagementPanelIcon() { $repository = $this->getRepository(); - if (!$repository->canPerformAutomation()) { - return 'fa-truck grey'; - } - $blueprint_phids = $repository->getAutomationBlueprintPHIDs(); - if (!$blueprint_phids) { - return 'fa-truck grey'; - } $is_authorized = DrydockAuthorizationQuery::isFullyAuthorized( $repository->getPHID(), $blueprint_phids); if (!$is_authorized) { - return 'fa-exclamation-triangle yellow'; + return 'fa-exclamation-triangle'; } return 'fa-truck'; } - public function buildManagementPanelCurtain() { - $repository = $this->getRepository(); - $viewer = $this->getViewer(); - $action_list = $this->getNewActionList(); - - $can_edit = PhabricatorPolicyFilter::hasCapability( - $viewer, - $repository, - PhabricatorPolicyCapability::CAN_EDIT); - - $can_test = $can_edit && $repository->canPerformAutomation(); - - $automation_uri = $this->getEditPageURI(); - $test_uri = $repository->getPathURI('edit/testautomation/'); - - $action_list->addAction( - id(new PhabricatorActionView()) - ->setIcon('fa-pencil') - ->setName(pht('Edit Automation')) - ->setHref($automation_uri) - ->setDisabled(!$can_edit) - ->setWorkflow(!$can_edit)); - - $action_list->addAction( - id(new PhabricatorActionView()) - ->setIcon('fa-gamepad') - ->setName(pht('Test Configuration')) - ->setWorkflow(true) - ->setDisabled(!$can_test) - ->setHref($test_uri)); - - return $this->getNewCurtainView($action_list); - } - public function buildManagementPanelContent() { $repository = $this->getRepository(); $viewer = $this->getViewer(); @@ -99,7 +58,33 @@ final class DiffusionRepositoryAutomationManagementPanel $view->addProperty(pht('Automation'), $blueprint_view); - return $this->newBox(pht('Automation'), $view); + $can_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + $repository, + PhabricatorPolicyCapability::CAN_EDIT); + + $can_test = $can_edit && $repository->canPerformAutomation(); + + $automation_uri = $this->getEditPageURI(); + $test_uri = $repository->getPathURI('edit/testautomation/'); + + $edit = id(new PHUIButtonView()) + ->setTag('a') + ->setIcon('fa-pencil') + ->setText(pht('Edit')) + ->setHref($automation_uri) + ->setDisabled(!$can_edit) + ->setWorkflow(!$can_edit); + + $test = id(new PHUIButtonView()) + ->setTag('a') + ->setIcon('fa-gamepad') + ->setText(pht('Test Config')) + ->setWorkflow(true) + ->setDisabled(!$can_test) + ->setHref($test_uri); + + return $this->newBox(pht('Automation'), $view, array($edit, $test)); } } diff --git a/src/applications/diffusion/management/DiffusionRepositoryBasicsManagementPanel.php b/src/applications/diffusion/management/DiffusionRepositoryBasicsManagementPanel.php index a5e09e40d3..6e527e81b5 100644 --- a/src/applications/diffusion/management/DiffusionRepositoryBasicsManagementPanel.php +++ b/src/applications/diffusion/management/DiffusionRepositoryBasicsManagementPanel.php @@ -14,13 +14,7 @@ final class DiffusionRepositoryBasicsManagementPanel } public function getManagementPanelIcon() { - $repository = $this->getRepository(); - - if (!$repository->isTracked()) { - return 'fa-ban indigo'; - } else { - return 'fa-code'; - } + return 'fa-code'; } protected function getEditEngineFieldKeys() { @@ -33,10 +27,11 @@ final class DiffusionRepositoryBasicsManagementPanel ); } - public function buildManagementPanelCurtain() { + private function buildActionMenu() { $repository = $this->getRepository(); $viewer = $this->getViewer(); - $action_list = $this->getNewActionList(); + $action_list = id(new PhabricatorActionListView()) + ->setViewer($viewer); $can_edit = PhabricatorPolicyFilter::hasCapability( $viewer, @@ -50,27 +45,22 @@ final class DiffusionRepositoryBasicsManagementPanel $dangerous_uri = $repository->getPathURI('edit/dangerous/'); if ($repository->isTracked()) { - $activate_icon = 'fa-pause'; $activate_label = pht('Deactivate Repository'); } else { - $activate_icon = 'fa-play'; $activate_label = pht('Activate Repository'); } $should_dangerous = $repository->shouldAllowDangerousChanges(); if ($should_dangerous) { - $dangerous_icon = 'fa-shield'; $dangerous_name = pht('Prevent Dangerous Changes'); $can_dangerous = $can_edit; } else { - $dangerous_icon = 'fa-bullseye'; $dangerous_name = pht('Allow Dangerous Changes'); $can_dangerous = ($can_edit && $repository->canAllowDangerousChanges()); } $action_list->addAction( id(new PhabricatorActionView()) - ->setIcon('fa-pencil') ->setName(pht('Edit Basic Information')) ->setHref($edit_uri) ->setDisabled(!$can_edit) @@ -78,7 +68,6 @@ final class DiffusionRepositoryBasicsManagementPanel $action_list->addAction( id(new PhabricatorActionView()) - ->setIcon('fa-text-width') ->setName(pht('Edit Text Encoding')) ->setHref($encoding_uri) ->setDisabled(!$can_edit) @@ -86,7 +75,6 @@ final class DiffusionRepositoryBasicsManagementPanel $action_list->addAction( id(new PhabricatorActionView()) - ->setIcon($dangerous_icon) ->setName($dangerous_name) ->setHref($dangerous_uri) ->setDisabled(!$can_dangerous) @@ -95,26 +83,37 @@ final class DiffusionRepositoryBasicsManagementPanel $action_list->addAction( id(new PhabricatorActionView()) ->setHref($activate_uri) - ->setIcon($activate_icon) ->setName($activate_label) ->setDisabled(!$can_edit) ->setWorkflow(true)); + $action_list->addAction( + id(new PhabricatorActionView()) + ->setType(PhabricatorActionView::TYPE_DIVIDER)); + $action_list->addAction( id(new PhabricatorActionView()) ->setName(pht('Delete Repository')) - ->setIcon('fa-times') ->setHref($delete_uri) + ->setColor(PhabricatorActionView::RED) ->setDisabled(true) ->setWorkflow(true)); - return $this->getNewCurtainView($action_list); + return $action_list; } public function buildManagementPanelContent() { - $result = array(); - $basics = $this->newBox(pht('Repository Basics'), $this->buildBasics()); + $button = id(new PHUIButtonView()) + ->setTag('a') + ->setText(pht('Actions')) + ->setHref('#') + ->setIcon('fa-bars') + ->addClass('phui-mobile-menu') + ->setDropdownMenu($this->buildActionMenu()); + + $basics = $this->buildBasics(); + $basics = $this->newBox(pht('Properties'), $basics, array($button)); $repository = $this->getRepository(); $is_new = $repository->isNewlyInitialized(); @@ -144,14 +143,13 @@ final class DiffusionRepositoryBasicsManagementPanel ->setErrors($messages); } - $result[] = $basics; - $description = $this->buildDescription(); if ($description) { - $result[] = $this->newBox(pht('Description'), $description); + $description = $this->newBox(pht('Description'), $description); } + $status = $this->buildStatus(); - return array($info_view, $result); + return array($info_view, $basics, $description, $status); } private function buildBasics() { @@ -213,7 +211,7 @@ final class DiffusionRepositoryBasicsManagementPanel $view = id(new PHUIPropertyListView()) ->setViewer($viewer); if (!strlen($description)) { - $description = phutil_tag('em', array(), pht('No description provided.')); + return null; } else { $description = new PHUIRemarkupView($viewer, $description); } @@ -222,4 +220,471 @@ final class DiffusionRepositoryBasicsManagementPanel return $view; } + private function buildStatus() { + $repository = $this->getRepository(); + $viewer = $this->getViewer(); + $update_uri = $repository->getPathURI('edit/update/'); + + $view = id(new PHUIPropertyListView()) + ->setViewer($viewer); + + $view->addProperty( + pht('Update Frequency'), + $this->buildRepositoryUpdateInterval($repository)); + + $messages = $this->loadStatusMessages($repository); + + $status = $this->buildRepositoryStatus($repository, $messages); + $raw_error = $this->buildRepositoryRawError($repository, $messages); + + $view->addProperty(pht('Status'), $status); + if ($raw_error) { + $view->addSectionHeader(pht('Raw Error')); + $view->addTextContent($raw_error); + } + + $can_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + $repository, + PhabricatorPolicyCapability::CAN_EDIT); + + $button = id(new PHUIButtonView()) + ->setTag('a') + ->setIcon('fa-refresh') + ->setText(pht('Update Now')) + ->setWorkflow(true) + ->setDisabled(!$can_edit) + ->setHref($update_uri); + + return $this->newBox(pht('Status'), $view, array($button)); + } + + private function buildRepositoryUpdateInterval( + PhabricatorRepository $repository) { + + $smart_wait = $repository->loadUpdateInterval(); + + $doc_href = PhabricatorEnv::getDoclink( + 'Diffusion User Guide: Repository Updates'); + + return array( + phutil_format_relative_time_detailed($smart_wait), + " \xC2\xB7 ", + phutil_tag( + 'a', + array( + 'href' => $doc_href, + 'target' => '_blank', + ), + pht('Learn More')), + ); + } + + private function buildRepositoryStatus( + PhabricatorRepository $repository, + array $messages) { + + $viewer = $this->getViewer(); + $is_cluster = $repository->getAlmanacServicePHID(); + + $view = new PHUIStatusListView(); + + if ($repository->isTracked()) { + $view->addItem( + id(new PHUIStatusItemView()) + ->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green') + ->setTarget(pht('Repository Active'))); + } else { + $view->addItem( + id(new PHUIStatusItemView()) + ->setIcon(PHUIStatusItemView::ICON_WARNING, 'bluegrey') + ->setTarget(pht('Repository Inactive')) + ->setNote( + pht('Activate this repository to begin or resume import.'))); + return $view; + } + + $binaries = array(); + $svnlook_check = false; + switch ($repository->getVersionControlSystem()) { + case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: + $binaries[] = 'git'; + break; + case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: + $binaries[] = 'svn'; + break; + case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: + $binaries[] = 'hg'; + break; + } + + if ($repository->isHosted()) { + $proto_https = PhabricatorRepositoryURI::BUILTIN_PROTOCOL_HTTPS; + $proto_http = PhabricatorRepositoryURI::BUILTIN_PROTOCOL_HTTP; + $can_http = $repository->canServeProtocol($proto_http, false) || + $repository->canServeProtocol($proto_https, false); + + if ($can_http) { + switch ($repository->getVersionControlSystem()) { + case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: + $binaries[] = 'git-http-backend'; + break; + case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: + $binaries[] = 'svnserve'; + $binaries[] = 'svnadmin'; + $binaries[] = 'svnlook'; + $svnlook_check = true; + break; + case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: + $binaries[] = 'hg'; + break; + } + } + + + $proto_ssh = PhabricatorRepositoryURI::BUILTIN_PROTOCOL_SSH; + $can_ssh = $repository->canServeProtocol($proto_ssh, false); + + if ($can_ssh) { + switch ($repository->getVersionControlSystem()) { + case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: + $binaries[] = 'git-receive-pack'; + $binaries[] = 'git-upload-pack'; + break; + case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: + $binaries[] = 'svnserve'; + $binaries[] = 'svnadmin'; + $binaries[] = 'svnlook'; + $svnlook_check = true; + break; + case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: + $binaries[] = 'hg'; + break; + } + } + } + + $binaries = array_unique($binaries); + if (!$is_cluster) { + // We're only checking for binaries if we aren't running with a cluster + // configuration. In theory, we could check for binaries on the + // repository host machine, but we'd need to make this more complicated + // to do that. + + foreach ($binaries as $binary) { + $where = Filesystem::resolveBinary($binary); + if (!$where) { + $view->addItem( + id(new PHUIStatusItemView()) + ->setIcon(PHUIStatusItemView::ICON_WARNING, 'red') + ->setTarget( + pht('Missing Binary %s', phutil_tag('tt', array(), $binary))) + ->setNote(pht( + "Unable to find this binary in the webserver's PATH. You may ". + "need to configure %s.", + $this->getEnvConfigLink()))); + } else { + $view->addItem( + id(new PHUIStatusItemView()) + ->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green') + ->setTarget( + pht('Found Binary %s', phutil_tag('tt', array(), $binary))) + ->setNote(phutil_tag('tt', array(), $where))); + } + } + + // This gets checked generically above. However, for svn commit hooks, we + // need this to be in environment.append-paths because subversion strips + // PATH. + if ($svnlook_check) { + $where = Filesystem::resolveBinary('svnlook'); + if ($where) { + $path = substr($where, 0, strlen($where) - strlen('svnlook')); + $dirs = PhabricatorEnv::getEnvConfig('environment.append-paths'); + $in_path = false; + foreach ($dirs as $dir) { + if (Filesystem::isDescendant($path, $dir)) { + $in_path = true; + break; + } + } + if (!$in_path) { + $view->addItem( + id(new PHUIStatusItemView()) + ->setIcon(PHUIStatusItemView::ICON_WARNING, 'red') + ->setTarget( + pht('Missing Binary %s', phutil_tag('tt', array(), $binary))) + ->setNote(pht( + 'Unable to find this binary in `%s`. '. + 'You need to configure %s and include %s.', + 'environment.append-paths', + $this->getEnvConfigLink(), + $path))); + } + } + } + } + + $doc_href = PhabricatorEnv::getDoclink('Managing Daemons with phd'); + + $daemon_instructions = pht( + 'Use %s to start daemons. See %s.', + phutil_tag('tt', array(), 'bin/phd start'), + phutil_tag( + 'a', + array( + 'href' => $doc_href, + ), + pht('Managing Daemons with phd'))); + + + $pull_daemon = id(new PhabricatorDaemonLogQuery()) + ->setViewer(PhabricatorUser::getOmnipotentUser()) + ->withStatus(PhabricatorDaemonLogQuery::STATUS_ALIVE) + ->withDaemonClasses(array('PhabricatorRepositoryPullLocalDaemon')) + ->setLimit(1) + ->execute(); + + if ($pull_daemon) { + + // TODO: In a cluster environment, we need a daemon on this repository's + // host, specifically, and we aren't checking for that right now. This + // is a reasonable proxy for things being more-or-less correctly set up, + // though. + + $view->addItem( + id(new PHUIStatusItemView()) + ->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green') + ->setTarget(pht('Pull Daemon Running'))); + } else { + $view->addItem( + id(new PHUIStatusItemView()) + ->setIcon(PHUIStatusItemView::ICON_WARNING, 'red') + ->setTarget(pht('Pull Daemon Not Running')) + ->setNote($daemon_instructions)); + } + + + $task_daemon = id(new PhabricatorDaemonLogQuery()) + ->setViewer(PhabricatorUser::getOmnipotentUser()) + ->withStatus(PhabricatorDaemonLogQuery::STATUS_ALIVE) + ->withDaemonClasses(array('PhabricatorTaskmasterDaemon')) + ->setLimit(1) + ->execute(); + if ($task_daemon) { + $view->addItem( + id(new PHUIStatusItemView()) + ->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green') + ->setTarget(pht('Task Daemon Running'))); + } else { + $view->addItem( + id(new PHUIStatusItemView()) + ->setIcon(PHUIStatusItemView::ICON_WARNING, 'red') + ->setTarget(pht('Task Daemon Not Running')) + ->setNote($daemon_instructions)); + } + + + if ($is_cluster) { + // Just omit this status check for now in cluster environments. We + // could make a service call and pull it from the repository host + // eventually. + } else if ($repository->usesLocalWorkingCopy()) { + $local_parent = dirname($repository->getLocalPath()); + if (Filesystem::pathExists($local_parent)) { + $view->addItem( + id(new PHUIStatusItemView()) + ->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green') + ->setTarget(pht('Storage Directory OK')) + ->setNote(phutil_tag('tt', array(), $local_parent))); + } else { + $view->addItem( + id(new PHUIStatusItemView()) + ->setIcon(PHUIStatusItemView::ICON_WARNING, 'red') + ->setTarget(pht('No Storage Directory')) + ->setNote( + pht( + 'Storage directory %s does not exist, or is not readable by '. + 'the webserver. Create this directory or make it readable.', + phutil_tag('tt', array(), $local_parent)))); + return $view; + } + + $local_path = $repository->getLocalPath(); + $message = idx($messages, PhabricatorRepositoryStatusMessage::TYPE_INIT); + if ($message) { + switch ($message->getStatusCode()) { + case PhabricatorRepositoryStatusMessage::CODE_ERROR: + $view->addItem( + id(new PHUIStatusItemView()) + ->setIcon(PHUIStatusItemView::ICON_WARNING, 'red') + ->setTarget(pht('Initialization Error')) + ->setNote($message->getParameter('message'))); + return $view; + case PhabricatorRepositoryStatusMessage::CODE_OKAY: + if (Filesystem::pathExists($local_path)) { + $view->addItem( + id(new PHUIStatusItemView()) + ->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green') + ->setTarget(pht('Working Copy OK')) + ->setNote(phutil_tag('tt', array(), $local_path))); + } else { + $view->addItem( + id(new PHUIStatusItemView()) + ->setIcon(PHUIStatusItemView::ICON_WARNING, 'red') + ->setTarget(pht('Working Copy Error')) + ->setNote( + pht( + 'Working copy %s has been deleted, or is not '. + 'readable by the webserver. Make this directory '. + 'readable. If it has been deleted, the daemons should '. + 'restore it automatically.', + phutil_tag('tt', array(), $local_path)))); + return $view; + } + break; + default: + $view->addItem( + id(new PHUIStatusItemView()) + ->setIcon(PHUIStatusItemView::ICON_CLOCK, 'green') + ->setTarget(pht('Initializing Working Copy')) + ->setNote(pht('Daemons are initializing the working copy.'))); + return $view; + } + } else { + $view->addItem( + id(new PHUIStatusItemView()) + ->setIcon(PHUIStatusItemView::ICON_CLOCK, 'orange') + ->setTarget(pht('No Working Copy Yet')) + ->setNote( + pht('Waiting for daemons to build a working copy.'))); + return $view; + } + } + + $message = idx($messages, PhabricatorRepositoryStatusMessage::TYPE_FETCH); + if ($message) { + switch ($message->getStatusCode()) { + case PhabricatorRepositoryStatusMessage::CODE_ERROR: + $message = $message->getParameter('message'); + + $suggestion = null; + if (preg_match('/Permission denied \(publickey\)./', $message)) { + $suggestion = pht( + 'Public Key Error: This error usually indicates that the '. + 'keypair you have configured does not have permission to '. + 'access the repository.'); + } + + $view->addItem( + id(new PHUIStatusItemView()) + ->setIcon(PHUIStatusItemView::ICON_WARNING, 'red') + ->setTarget(pht('Update Error')) + ->setNote($suggestion)); + return $view; + case PhabricatorRepositoryStatusMessage::CODE_OKAY: + $ago = (PhabricatorTime::getNow() - $message->getEpoch()); + $view->addItem( + id(new PHUIStatusItemView()) + ->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green') + ->setTarget(pht('Updates OK')) + ->setNote( + pht( + 'Last updated %s (%s ago).', + phabricator_datetime($message->getEpoch(), $viewer), + phutil_format_relative_time_detailed($ago)))); + break; + } + } else { + $view->addItem( + id(new PHUIStatusItemView()) + ->setIcon(PHUIStatusItemView::ICON_CLOCK, 'orange') + ->setTarget(pht('Waiting For Update')) + ->setNote( + pht('Waiting for daemons to read updates.'))); + } + + if ($repository->isImporting()) { + $ratio = $repository->loadImportProgress(); + $percentage = sprintf('%.2f%%', 100 * $ratio); + + $view->addItem( + id(new PHUIStatusItemView()) + ->setIcon(PHUIStatusItemView::ICON_CLOCK, 'green') + ->setTarget(pht('Importing')) + ->setNote( + pht('%s Complete', $percentage))); + } else { + $view->addItem( + id(new PHUIStatusItemView()) + ->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green') + ->setTarget(pht('Fully Imported'))); + } + + if (idx($messages, PhabricatorRepositoryStatusMessage::TYPE_NEEDS_UPDATE)) { + $view->addItem( + id(new PHUIStatusItemView()) + ->setIcon(PHUIStatusItemView::ICON_UP, 'indigo') + ->setTarget(pht('Prioritized')) + ->setNote(pht('This repository will be updated soon!'))); + } + + return $view; + } + + private function buildRepositoryRawError( + PhabricatorRepository $repository, + array $messages) { + $viewer = $this->getViewer(); + + $can_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + $repository, + PhabricatorPolicyCapability::CAN_EDIT); + + $raw_error = null; + + $message = idx($messages, PhabricatorRepositoryStatusMessage::TYPE_FETCH); + if ($message) { + switch ($message->getStatusCode()) { + case PhabricatorRepositoryStatusMessage::CODE_ERROR: + $raw_error = $message->getParameter('message'); + break; + } + } + + if ($raw_error !== null) { + if (!$can_edit) { + $raw_message = pht( + 'You must be able to edit a repository to see raw error messages '. + 'because they sometimes disclose sensitive information.'); + $raw_message = phutil_tag('em', array(), $raw_message); + } else { + $raw_message = phutil_escape_html_newlines($raw_error); + } + } else { + $raw_message = null; + } + + return $raw_message; + } + + private function loadStatusMessages(PhabricatorRepository $repository) { + $messages = id(new PhabricatorRepositoryStatusMessage()) + ->loadAllWhere('repositoryID = %d', $repository->getID()); + $messages = mpull($messages, null, 'getStatusType'); + + return $messages; + } + + private function getEnvConfigLink() { + $config_href = '/config/edit/environment.append-paths/'; + return phutil_tag( + 'a', + array( + 'href' => $config_href, + ), + 'environment.append-paths'); + } + } diff --git a/src/applications/diffusion/management/DiffusionRepositoryBranchesManagementPanel.php b/src/applications/diffusion/management/DiffusionRepositoryBranchesManagementPanel.php index 90b646c3f9..7c7f4bcf63 100644 --- a/src/applications/diffusion/management/DiffusionRepositoryBranchesManagementPanel.php +++ b/src/applications/diffusion/management/DiffusionRepositoryBranchesManagementPanel.php @@ -19,18 +19,7 @@ final class DiffusionRepositoryBranchesManagementPanel } public function getManagementPanelIcon() { - $repository = $this->getRepository(); - - $has_any = - $repository->getDetail('default-branch') || - $repository->getDetail('branch-filter') || - $repository->getDetail('close-commits-filter'); - - if ($has_any) { - return 'fa-code-fork'; - } else { - return 'fa-code-fork grey'; - } + return 'fa-code-fork'; } protected function getEditEngineFieldKeys() { @@ -41,29 +30,6 @@ final class DiffusionRepositoryBranchesManagementPanel ); } - public function buildManagementPanelCurtain() { - $repository = $this->getRepository(); - $viewer = $this->getViewer(); - $action_list = $this->getNewActionList(); - - $can_edit = PhabricatorPolicyFilter::hasCapability( - $viewer, - $repository, - PhabricatorPolicyCapability::CAN_EDIT); - - $branches_uri = $this->getEditPageURI(); - - $action_list->addAction( - id(new PhabricatorActionView()) - ->setIcon('fa-pencil') - ->setName(pht('Edit Branches')) - ->setHref($branches_uri) - ->setDisabled(!$can_edit) - ->setWorkflow(!$can_edit)); - - return $this->getNewCurtainView($action_list); - } - public function buildManagementPanelContent() { $repository = $this->getRepository(); $viewer = $this->getViewer(); @@ -94,7 +60,23 @@ final class DiffusionRepositoryBranchesManagementPanel } $view->addProperty(pht('Autoclose Only'), $autoclose_only); - $content[] = $this->newBox(pht('Branches'), $view); + + $can_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + $repository, + PhabricatorPolicyCapability::CAN_EDIT); + + $branches_uri = $this->getEditPageURI(); + + $button = id(new PHUIButtonView()) + ->setTag('a') + ->setIcon('fa-pencil') + ->setText(pht('Edit')) + ->setHref($branches_uri) + ->setDisabled(!$can_edit) + ->setWorkflow(!$can_edit); + + $content[] = $this->newBox(pht('Branches'), $view, array($button)); // Branch Autoclose Table if (!$repository->isImporting()) { @@ -176,11 +158,8 @@ final class DiffusionRepositoryBranchesManagementPanel true, )); - $box = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Branch Status')) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) - ->setTable($branch_table) - ->setPager($pager); + $box = $this->newBox(pht('Branch Status'), $branch_table); + $box->setPager($pager); $content[] = $box; } else { $content[] = id(new PHUIInfoView()) diff --git a/src/applications/diffusion/management/DiffusionRepositoryDocumentationManagementPanel.php b/src/applications/diffusion/management/DiffusionRepositoryDocumentationManagementPanel.php deleted file mode 100644 index 9d067cd90b..0000000000 --- a/src/applications/diffusion/management/DiffusionRepositoryDocumentationManagementPanel.php +++ /dev/null @@ -1,33 +0,0 @@ -newTimeline(); } - public function buildManagementPanelCurtain() { - return null; - } - } diff --git a/src/applications/diffusion/management/DiffusionRepositoryManagementPanel.php b/src/applications/diffusion/management/DiffusionRepositoryManagementPanel.php index f9e76eb523..282fa1b7b1 100644 --- a/src/applications/diffusion/management/DiffusionRepositoryManagementPanel.php +++ b/src/applications/diffusion/management/DiffusionRepositoryManagementPanel.php @@ -41,7 +41,6 @@ abstract class DiffusionRepositoryManagementPanel abstract public function getManagementPanelLabel(); abstract public function getManagementPanelOrder(); abstract public function buildManagementPanelContent(); - abstract public function buildManagementPanelCurtain(); public function getManagementPanelIcon() { return 'fa-pencil'; @@ -56,22 +55,6 @@ abstract class DiffusionRepositoryManagementPanel return true; } - public function getNewActionList() { - $viewer = $this->getViewer(); - $action_id = celerity_generate_unique_node_id(); - - return id(new PhabricatorActionListView()) - ->setViewer($viewer) - ->setID($action_id); - } - - public function getNewCurtainView(PhabricatorActionListView $action_list) { - $viewer = $this->getViewer(); - return id(new PHUICurtainView()) - ->setViewer($viewer) - ->setActionList($action_list); - } - public static function getAllPanels() { return id(new PhutilClassMapQuery()) ->setAncestorClass(__CLASS__) @@ -80,11 +63,20 @@ abstract class DiffusionRepositoryManagementPanel ->execute(); } - final protected function newBox($header_text, $body) { - return id(new PHUIObjectBoxView()) - ->setHeaderText($header_text) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) + final protected function newBox($header_text, $body, $button = array()) { + $header = id(new PHUIHeaderView()) + ->setHeader($header_text); + + foreach ($button as $link) { + $header->addActionLink($link); + } + + $view = id(new PHUIObjectBoxView()) + ->setHeader($header) + ->setBackground(PHUIObjectBoxView::WHITE_CONFIG) ->appendChild($body); + + return $view; } final protected function newTimeline() { diff --git a/src/applications/diffusion/management/DiffusionRepositoryPoliciesManagementPanel.php b/src/applications/diffusion/management/DiffusionRepositoryPoliciesManagementPanel.php index 6b2972e30c..3da6ea80dc 100644 --- a/src/applications/diffusion/management/DiffusionRepositoryPoliciesManagementPanel.php +++ b/src/applications/diffusion/management/DiffusionRepositoryPoliciesManagementPanel.php @@ -14,35 +14,7 @@ final class DiffusionRepositoryPoliciesManagementPanel } public function getManagementPanelIcon() { - $viewer = $this->getViewer(); - $repository = $this->getRepository(); - - $can_view = PhabricatorPolicyCapability::CAN_VIEW; - $can_edit = PhabricatorPolicyCapability::CAN_EDIT; - $can_push = DiffusionPushCapability::CAPABILITY; - - $actual_values = array( - 'spacePHID' => $repository->getSpacePHID(), - 'view' => $repository->getPolicy($can_view), - 'edit' => $repository->getPolicy($can_edit), - 'push' => $repository->getPolicy($can_push), - ); - - $default = PhabricatorRepository::initializeNewRepository( - $viewer); - - $default_values = array( - 'spacePHID' => $default->getSpacePHID(), - 'view' => $default->getPolicy($can_view), - 'edit' => $default->getPolicy($can_edit), - 'push' => $default->getPolicy($can_push), - ); - - if ($actual_values === $default_values) { - return 'fa-lock grey'; - } else { - return 'fa-lock'; - } + return 'fa-lock'; } protected function getEditEngineFieldKeys() { @@ -54,29 +26,6 @@ final class DiffusionRepositoryPoliciesManagementPanel ); } - public function buildManagementPanelCurtain() { - $repository = $this->getRepository(); - $viewer = $this->getViewer(); - $action_list = $this->getNewActionList(); - - $can_edit = PhabricatorPolicyFilter::hasCapability( - $viewer, - $repository, - PhabricatorPolicyCapability::CAN_EDIT); - - $edit_uri = $this->getEditPageURI(); - - $action_list->addAction( - id(new PhabricatorActionView()) - ->setIcon('fa-pencil') - ->setName(pht('Edit Policies')) - ->setHref($edit_uri) - ->setDisabled(!$can_edit) - ->setWorkflow(!$can_edit)); - - return $this->getNewCurtainView($action_list); - } - public function buildManagementPanelContent() { $repository = $this->getRepository(); $viewer = $this->getViewer(); @@ -109,7 +58,22 @@ final class DiffusionRepositoryPoliciesManagementPanel : phutil_tag('em', array(), pht('Not a Hosted Repository')); $view->addProperty(pht('Pushable By'), $pushable); - return $this->newBox(pht('Policies'), $view); + $can_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + $repository, + PhabricatorPolicyCapability::CAN_EDIT); + + $edit_uri = $this->getEditPageURI(); + + $button = id(new PHUIButtonView()) + ->setTag('a') + ->setIcon('fa-pencil') + ->setText(pht('Edit')) + ->setHref($edit_uri) + ->setDisabled(!$can_edit) + ->setWorkflow(!$can_edit); + + return $this->newBox(pht('Policies'), $view, array($button)); } } diff --git a/src/applications/diffusion/management/DiffusionRepositoryStagingManagementPanel.php b/src/applications/diffusion/management/DiffusionRepositoryStagingManagementPanel.php index bab7e72857..ebd970f032 100644 --- a/src/applications/diffusion/management/DiffusionRepositoryStagingManagementPanel.php +++ b/src/applications/diffusion/management/DiffusionRepositoryStagingManagementPanel.php @@ -20,15 +20,7 @@ final class DiffusionRepositoryStagingManagementPanel public function getManagementPanelIcon() { - $repository = $this->getRepository(); - - $staging_uri = $repository->getStagingURI(); - - if ($staging_uri) { - return 'fa-upload'; - } else { - return 'fa-upload grey'; - } + return 'fa-upload'; } protected function getEditEngineFieldKeys() { @@ -37,29 +29,6 @@ final class DiffusionRepositoryStagingManagementPanel ); } - public function buildManagementPanelCurtain() { - $repository = $this->getRepository(); - $viewer = $this->getViewer(); - $action_list = $this->getNewActionList(); - - $can_edit = PhabricatorPolicyFilter::hasCapability( - $viewer, - $repository, - PhabricatorPolicyCapability::CAN_EDIT); - - $staging_uri = $this->getEditPageURI(); - - $action_list->addAction( - id(new PhabricatorActionView()) - ->setIcon('fa-pencil') - ->setName(pht('Edit Staging')) - ->setHref($staging_uri) - ->setDisabled(!$can_edit) - ->setWorkflow(!$can_edit)); - - return $this->getNewCurtainView($action_list); - } - public function buildManagementPanelContent() { $repository = $this->getRepository(); $viewer = $this->getViewer(); @@ -74,7 +43,22 @@ final class DiffusionRepositoryStagingManagementPanel $view->addProperty(pht('Staging Area URI'), $staging_uri); - return $this->newBox(pht('Staging Area'), $view); + $can_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + $repository, + PhabricatorPolicyCapability::CAN_EDIT); + + $staging_uri = $this->getEditPageURI(); + + $button = id(new PHUIButtonView()) + ->setTag('a') + ->setIcon('fa-pencil') + ->setText(pht('Edit')) + ->setHref($staging_uri) + ->setDisabled(!$can_edit) + ->setWorkflow(!$can_edit); + + return $this->newBox(pht('Staging Area'), $view, array($button)); } } diff --git a/src/applications/diffusion/management/DiffusionRepositoryStatusManagementPanel.php b/src/applications/diffusion/management/DiffusionRepositoryStatusManagementPanel.php deleted file mode 100644 index 23b2cd1684..0000000000 --- a/src/applications/diffusion/management/DiffusionRepositoryStatusManagementPanel.php +++ /dev/null @@ -1,507 +0,0 @@ -getRepository(); - - // TODO: We could try to show a warning icon in more cases, but just - // raise in the most serious cases for now. - $messages = $this->loadStatusMessages($repository); - - $raw_error = $this->buildRepositoryRawError($repository, $messages); - if ($raw_error) { - return 'fa-exclamation-triangle red'; - } - - return 'fa-check grey'; - } - - public function buildManagementPanelCurtain() { - $repository = $this->getRepository(); - $viewer = $this->getViewer(); - $action_list = $this->getNewActionList(); - - $can_edit = PhabricatorPolicyFilter::hasCapability( - $viewer, - $repository, - PhabricatorPolicyCapability::CAN_EDIT); - - $update_uri = $repository->getPathURI('edit/update/'); - - $action_list->addAction( - id(new PhabricatorActionView()) - ->setIcon('fa-refresh') - ->setName(pht('Update Now')) - ->setWorkflow(true) - ->setDisabled(!$can_edit) - ->setHref($update_uri)); - - return $this->getNewCurtainView($action_list); - } - - public function buildManagementPanelContent() { - $repository = $this->getRepository(); - $viewer = $this->getViewer(); - - $view = id(new PHUIPropertyListView()) - ->setViewer($viewer); - - $view->addProperty( - pht('Update Frequency'), - $this->buildRepositoryUpdateInterval($repository)); - - $messages = $this->loadStatusMessages($repository); - - $status = $this->buildRepositoryStatus($repository, $messages); - $raw_error = $this->buildRepositoryRawError($repository, $messages); - - $view->addProperty(pht('Status'), $status); - if ($raw_error) { - $view->addSectionHeader(pht('Raw Error')); - $view->addTextContent($raw_error); - } - - return $this->newBox(pht('Status'), $view); - } - - private function buildRepositoryUpdateInterval( - PhabricatorRepository $repository) { - - $smart_wait = $repository->loadUpdateInterval(); - - $doc_href = PhabricatorEnv::getDoclink( - 'Diffusion User Guide: Repository Updates'); - - return array( - phutil_format_relative_time_detailed($smart_wait), - " \xC2\xB7 ", - phutil_tag( - 'a', - array( - 'href' => $doc_href, - 'target' => '_blank', - ), - pht('Learn More')), - ); - } - - private function buildRepositoryStatus( - PhabricatorRepository $repository, - array $messages) { - - $viewer = $this->getViewer(); - $is_cluster = $repository->getAlmanacServicePHID(); - - $view = new PHUIStatusListView(); - - if ($repository->isTracked()) { - $view->addItem( - id(new PHUIStatusItemView()) - ->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green') - ->setTarget(pht('Repository Active'))); - } else { - $view->addItem( - id(new PHUIStatusItemView()) - ->setIcon(PHUIStatusItemView::ICON_WARNING, 'bluegrey') - ->setTarget(pht('Repository Inactive')) - ->setNote( - pht('Activate this repository to begin or resume import.'))); - return $view; - } - - $binaries = array(); - $svnlook_check = false; - switch ($repository->getVersionControlSystem()) { - case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: - $binaries[] = 'git'; - break; - case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: - $binaries[] = 'svn'; - break; - case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: - $binaries[] = 'hg'; - break; - } - - if ($repository->isHosted()) { - $proto_https = PhabricatorRepositoryURI::BUILTIN_PROTOCOL_HTTPS; - $proto_http = PhabricatorRepositoryURI::BUILTIN_PROTOCOL_HTTP; - $can_http = $repository->canServeProtocol($proto_http, false) || - $repository->canServeProtocol($proto_https, false); - - if ($can_http) { - switch ($repository->getVersionControlSystem()) { - case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: - $binaries[] = 'git-http-backend'; - break; - case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: - $binaries[] = 'svnserve'; - $binaries[] = 'svnadmin'; - $binaries[] = 'svnlook'; - $svnlook_check = true; - break; - case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: - $binaries[] = 'hg'; - break; - } - } - - - $proto_ssh = PhabricatorRepositoryURI::BUILTIN_PROTOCOL_SSH; - $can_ssh = $repository->canServeProtocol($proto_ssh, false); - - if ($can_ssh) { - switch ($repository->getVersionControlSystem()) { - case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: - $binaries[] = 'git-receive-pack'; - $binaries[] = 'git-upload-pack'; - break; - case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: - $binaries[] = 'svnserve'; - $binaries[] = 'svnadmin'; - $binaries[] = 'svnlook'; - $svnlook_check = true; - break; - case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: - $binaries[] = 'hg'; - break; - } - } - } - - $binaries = array_unique($binaries); - if (!$is_cluster) { - // We're only checking for binaries if we aren't running with a cluster - // configuration. In theory, we could check for binaries on the - // repository host machine, but we'd need to make this more complicated - // to do that. - - foreach ($binaries as $binary) { - $where = Filesystem::resolveBinary($binary); - if (!$where) { - $view->addItem( - id(new PHUIStatusItemView()) - ->setIcon(PHUIStatusItemView::ICON_WARNING, 'red') - ->setTarget( - pht('Missing Binary %s', phutil_tag('tt', array(), $binary))) - ->setNote(pht( - "Unable to find this binary in the webserver's PATH. You may ". - "need to configure %s.", - $this->getEnvConfigLink()))); - } else { - $view->addItem( - id(new PHUIStatusItemView()) - ->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green') - ->setTarget( - pht('Found Binary %s', phutil_tag('tt', array(), $binary))) - ->setNote(phutil_tag('tt', array(), $where))); - } - } - - // This gets checked generically above. However, for svn commit hooks, we - // need this to be in environment.append-paths because subversion strips - // PATH. - if ($svnlook_check) { - $where = Filesystem::resolveBinary('svnlook'); - if ($where) { - $path = substr($where, 0, strlen($where) - strlen('svnlook')); - $dirs = PhabricatorEnv::getEnvConfig('environment.append-paths'); - $in_path = false; - foreach ($dirs as $dir) { - if (Filesystem::isDescendant($path, $dir)) { - $in_path = true; - break; - } - } - if (!$in_path) { - $view->addItem( - id(new PHUIStatusItemView()) - ->setIcon(PHUIStatusItemView::ICON_WARNING, 'red') - ->setTarget( - pht('Missing Binary %s', phutil_tag('tt', array(), $binary))) - ->setNote(pht( - 'Unable to find this binary in `%s`. '. - 'You need to configure %s and include %s.', - 'environment.append-paths', - $this->getEnvConfigLink(), - $path))); - } - } - } - } - - $doc_href = PhabricatorEnv::getDoclink('Managing Daemons with phd'); - - $daemon_instructions = pht( - 'Use %s to start daemons. See %s.', - phutil_tag('tt', array(), 'bin/phd start'), - phutil_tag( - 'a', - array( - 'href' => $doc_href, - ), - pht('Managing Daemons with phd'))); - - - $pull_daemon = id(new PhabricatorDaemonLogQuery()) - ->setViewer(PhabricatorUser::getOmnipotentUser()) - ->withStatus(PhabricatorDaemonLogQuery::STATUS_ALIVE) - ->withDaemonClasses(array('PhabricatorRepositoryPullLocalDaemon')) - ->setLimit(1) - ->execute(); - - if ($pull_daemon) { - - // TODO: In a cluster environment, we need a daemon on this repository's - // host, specifically, and we aren't checking for that right now. This - // is a reasonable proxy for things being more-or-less correctly set up, - // though. - - $view->addItem( - id(new PHUIStatusItemView()) - ->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green') - ->setTarget(pht('Pull Daemon Running'))); - } else { - $view->addItem( - id(new PHUIStatusItemView()) - ->setIcon(PHUIStatusItemView::ICON_WARNING, 'red') - ->setTarget(pht('Pull Daemon Not Running')) - ->setNote($daemon_instructions)); - } - - - $task_daemon = id(new PhabricatorDaemonLogQuery()) - ->setViewer(PhabricatorUser::getOmnipotentUser()) - ->withStatus(PhabricatorDaemonLogQuery::STATUS_ALIVE) - ->withDaemonClasses(array('PhabricatorTaskmasterDaemon')) - ->setLimit(1) - ->execute(); - if ($task_daemon) { - $view->addItem( - id(new PHUIStatusItemView()) - ->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green') - ->setTarget(pht('Task Daemon Running'))); - } else { - $view->addItem( - id(new PHUIStatusItemView()) - ->setIcon(PHUIStatusItemView::ICON_WARNING, 'red') - ->setTarget(pht('Task Daemon Not Running')) - ->setNote($daemon_instructions)); - } - - - if ($is_cluster) { - // Just omit this status check for now in cluster environments. We - // could make a service call and pull it from the repository host - // eventually. - } else if ($repository->usesLocalWorkingCopy()) { - $local_parent = dirname($repository->getLocalPath()); - if (Filesystem::pathExists($local_parent)) { - $view->addItem( - id(new PHUIStatusItemView()) - ->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green') - ->setTarget(pht('Storage Directory OK')) - ->setNote(phutil_tag('tt', array(), $local_parent))); - } else { - $view->addItem( - id(new PHUIStatusItemView()) - ->setIcon(PHUIStatusItemView::ICON_WARNING, 'red') - ->setTarget(pht('No Storage Directory')) - ->setNote( - pht( - 'Storage directory %s does not exist, or is not readable by '. - 'the webserver. Create this directory or make it readable.', - phutil_tag('tt', array(), $local_parent)))); - return $view; - } - - $local_path = $repository->getLocalPath(); - $message = idx($messages, PhabricatorRepositoryStatusMessage::TYPE_INIT); - if ($message) { - switch ($message->getStatusCode()) { - case PhabricatorRepositoryStatusMessage::CODE_ERROR: - $view->addItem( - id(new PHUIStatusItemView()) - ->setIcon(PHUIStatusItemView::ICON_WARNING, 'red') - ->setTarget(pht('Initialization Error')) - ->setNote($message->getParameter('message'))); - return $view; - case PhabricatorRepositoryStatusMessage::CODE_OKAY: - if (Filesystem::pathExists($local_path)) { - $view->addItem( - id(new PHUIStatusItemView()) - ->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green') - ->setTarget(pht('Working Copy OK')) - ->setNote(phutil_tag('tt', array(), $local_path))); - } else { - $view->addItem( - id(new PHUIStatusItemView()) - ->setIcon(PHUIStatusItemView::ICON_WARNING, 'red') - ->setTarget(pht('Working Copy Error')) - ->setNote( - pht( - 'Working copy %s has been deleted, or is not '. - 'readable by the webserver. Make this directory '. - 'readable. If it has been deleted, the daemons should '. - 'restore it automatically.', - phutil_tag('tt', array(), $local_path)))); - return $view; - } - break; - default: - $view->addItem( - id(new PHUIStatusItemView()) - ->setIcon(PHUIStatusItemView::ICON_CLOCK, 'green') - ->setTarget(pht('Initializing Working Copy')) - ->setNote(pht('Daemons are initializing the working copy.'))); - return $view; - } - } else { - $view->addItem( - id(new PHUIStatusItemView()) - ->setIcon(PHUIStatusItemView::ICON_CLOCK, 'orange') - ->setTarget(pht('No Working Copy Yet')) - ->setNote( - pht('Waiting for daemons to build a working copy.'))); - return $view; - } - } - - $message = idx($messages, PhabricatorRepositoryStatusMessage::TYPE_FETCH); - if ($message) { - switch ($message->getStatusCode()) { - case PhabricatorRepositoryStatusMessage::CODE_ERROR: - $message = $message->getParameter('message'); - - $suggestion = null; - if (preg_match('/Permission denied \(publickey\)./', $message)) { - $suggestion = pht( - 'Public Key Error: This error usually indicates that the '. - 'keypair you have configured does not have permission to '. - 'access the repository.'); - } - - $view->addItem( - id(new PHUIStatusItemView()) - ->setIcon(PHUIStatusItemView::ICON_WARNING, 'red') - ->setTarget(pht('Update Error')) - ->setNote($suggestion)); - return $view; - case PhabricatorRepositoryStatusMessage::CODE_OKAY: - $ago = (PhabricatorTime::getNow() - $message->getEpoch()); - $view->addItem( - id(new PHUIStatusItemView()) - ->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green') - ->setTarget(pht('Updates OK')) - ->setNote( - pht( - 'Last updated %s (%s ago).', - phabricator_datetime($message->getEpoch(), $viewer), - phutil_format_relative_time_detailed($ago)))); - break; - } - } else { - $view->addItem( - id(new PHUIStatusItemView()) - ->setIcon(PHUIStatusItemView::ICON_CLOCK, 'orange') - ->setTarget(pht('Waiting For Update')) - ->setNote( - pht('Waiting for daemons to read updates.'))); - } - - if ($repository->isImporting()) { - $ratio = $repository->loadImportProgress(); - $percentage = sprintf('%.2f%%', 100 * $ratio); - - $view->addItem( - id(new PHUIStatusItemView()) - ->setIcon(PHUIStatusItemView::ICON_CLOCK, 'green') - ->setTarget(pht('Importing')) - ->setNote( - pht('%s Complete', $percentage))); - } else { - $view->addItem( - id(new PHUIStatusItemView()) - ->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green') - ->setTarget(pht('Fully Imported'))); - } - - if (idx($messages, PhabricatorRepositoryStatusMessage::TYPE_NEEDS_UPDATE)) { - $view->addItem( - id(new PHUIStatusItemView()) - ->setIcon(PHUIStatusItemView::ICON_UP, 'indigo') - ->setTarget(pht('Prioritized')) - ->setNote(pht('This repository will be updated soon!'))); - } - - return $view; - } - - private function buildRepositoryRawError( - PhabricatorRepository $repository, - array $messages) { - $viewer = $this->getViewer(); - - $can_edit = PhabricatorPolicyFilter::hasCapability( - $viewer, - $repository, - PhabricatorPolicyCapability::CAN_EDIT); - - $raw_error = null; - - $message = idx($messages, PhabricatorRepositoryStatusMessage::TYPE_FETCH); - if ($message) { - switch ($message->getStatusCode()) { - case PhabricatorRepositoryStatusMessage::CODE_ERROR: - $raw_error = $message->getParameter('message'); - break; - } - } - - if ($raw_error !== null) { - if (!$can_edit) { - $raw_message = pht( - 'You must be able to edit a repository to see raw error messages '. - 'because they sometimes disclose sensitive information.'); - $raw_message = phutil_tag('em', array(), $raw_message); - } else { - $raw_message = phutil_escape_html_newlines($raw_error); - } - } else { - $raw_message = null; - } - - return $raw_message; - } - - private function loadStatusMessages(PhabricatorRepository $repository) { - $messages = id(new PhabricatorRepositoryStatusMessage()) - ->loadAllWhere('repositoryID = %d', $repository->getID()); - $messages = mpull($messages, null, 'getStatusType'); - - return $messages; - } - - private function getEnvConfigLink() { - $config_href = '/config/edit/environment.append-paths/'; - return phutil_tag( - 'a', - array( - 'href' => $config_href, - ), - 'environment.append-paths'); - } - -} diff --git a/src/applications/diffusion/management/DiffusionRepositoryStorageManagementPanel.php b/src/applications/diffusion/management/DiffusionRepositoryStorageManagementPanel.php index 3d6733d5d3..a39dfaa632 100644 --- a/src/applications/diffusion/management/DiffusionRepositoryStorageManagementPanel.php +++ b/src/applications/diffusion/management/DiffusionRepositoryStorageManagementPanel.php @@ -14,31 +14,7 @@ final class DiffusionRepositoryStorageManagementPanel } public function getManagementPanelIcon() { - $repository = $this->getRepository(); - - if ($repository->getAlmanacServicePHID()) { - return 'fa-sitemap'; - } else if ($repository->isHosted()) { - return 'fa-folder'; - } else { - return 'fa-download'; - } - } - - public function buildManagementPanelCurtain() { - $repository = $this->getRepository(); - $viewer = $this->getViewer(); - $action_list = $this->getNewActionList(); - - $doc_href = PhabricatorEnv::getDoclink('Cluster: Repositories'); - - $action_list->addAction( - id(new PhabricatorActionView()) - ->setIcon('fa-book') - ->setHref($doc_href) - ->setName(pht('Cluster Documentation'))); - - return $this->getNewCurtainView($action_list); + return 'fa-database'; } public function buildManagementPanelContent() { @@ -71,9 +47,15 @@ final class DiffusionRepositoryStorageManagementPanel $view->addProperty(pht('Storage Path'), $storage_path); $view->addProperty(pht('Storage Cluster'), $storage_service); - $box = $this->newBox(pht('Storage'), null); - $box->addPropertyList($view); - return $box; + $doc_href = PhabricatorEnv::getDoclink('Cluster: Repositories'); + + $button = id(new PHUIButtonView()) + ->setTag('a') + ->setIcon('fa-book') + ->setHref($doc_href) + ->setText(pht('Help')); + + return $this->newBox(pht('Storage'), $view, array($button)); } private function buildClusterStatusPanel() { @@ -243,9 +225,7 @@ final class DiffusionRepositoryStorageManagementPanel 'date', )); - $box = $this->newBox(pht('Cluster Status'), null); - $box->setTable($table); - return $box; + return $this->newBox(pht('Cluster Status'), $table); } } diff --git a/src/applications/diffusion/management/DiffusionRepositorySubversionManagementPanel.php b/src/applications/diffusion/management/DiffusionRepositorySubversionManagementPanel.php index 5b9384d195..cd6e2c5be0 100644 --- a/src/applications/diffusion/management/DiffusionRepositorySubversionManagementPanel.php +++ b/src/applications/diffusion/management/DiffusionRepositorySubversionManagementPanel.php @@ -19,15 +19,7 @@ final class DiffusionRepositorySubversionManagementPanel } public function getManagementPanelIcon() { - $repository = $this->getRepository(); - - $has_any = (bool)$repository->getDetail('svn-subpath'); - - if ($has_any) { - return 'fa-database'; - } else { - return 'fa-database grey'; - } + return 'fa-folder'; } protected function getEditEngineFieldKeys() { @@ -36,29 +28,6 @@ final class DiffusionRepositorySubversionManagementPanel ); } - public function buildManagementPanelCurtain() { - $repository = $this->getRepository(); - $viewer = $this->getViewer(); - $action_list = $this->getNewActionList(); - - $can_edit = PhabricatorPolicyFilter::hasCapability( - $viewer, - $repository, - PhabricatorPolicyCapability::CAN_EDIT); - - $subversion_uri = $this->getEditPageURI(); - - $action_list->addAction( - id(new PhabricatorActionView()) - ->setIcon('fa-pencil') - ->setName(pht('Edit Properties')) - ->setHref($subversion_uri) - ->setDisabled(!$can_edit) - ->setWorkflow(!$can_edit)); - - return $this->getNewCurtainView($action_list); - } - public function buildManagementPanelContent() { $repository = $this->getRepository(); $viewer = $this->getViewer(); @@ -71,8 +40,22 @@ final class DiffusionRepositorySubversionManagementPanel phutil_tag('em', array(), pht('Import Entire Repository'))); $view->addProperty(pht('Import Only'), $default_branch); + $can_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + $repository, + PhabricatorPolicyCapability::CAN_EDIT); - return $this->newBox(pht('Subversion'), $view); + $subversion_uri = $this->getEditPageURI(); + + $button = id(new PHUIButtonView()) + ->setTag('a') + ->setIcon('fa-pencil') + ->setText(pht('Edit')) + ->setHref($subversion_uri) + ->setDisabled(!$can_edit) + ->setWorkflow(!$can_edit); + + return $this->newBox(pht('Subversion'), $view, array($button)); } } diff --git a/src/applications/diffusion/management/DiffusionRepositorySymbolsManagementPanel.php b/src/applications/diffusion/management/DiffusionRepositorySymbolsManagementPanel.php index 22d8780077..f64fbf8d6e 100644 --- a/src/applications/diffusion/management/DiffusionRepositorySymbolsManagementPanel.php +++ b/src/applications/diffusion/management/DiffusionRepositorySymbolsManagementPanel.php @@ -14,17 +14,7 @@ final class DiffusionRepositorySymbolsManagementPanel } public function getManagementPanelIcon() { - $repository = $this->getRepository(); - - $has_any = - $repository->getSymbolLanguages() || - $repository->getSymbolSources(); - - if ($has_any) { - return 'fa-link'; - } else { - return 'fa-link grey'; - } + return 'fa-bullseye'; } protected function getEditEngineFieldKeys() { @@ -34,29 +24,6 @@ final class DiffusionRepositorySymbolsManagementPanel ); } - public function buildManagementPanelCurtain() { - $repository = $this->getRepository(); - $viewer = $this->getViewer(); - $action_list = $this->getNewActionList(); - - $can_edit = PhabricatorPolicyFilter::hasCapability( - $viewer, - $repository, - PhabricatorPolicyCapability::CAN_EDIT); - - $symbols_uri = $this->getEditPageURI(); - - $action_list->addAction( - id(new PhabricatorActionView()) - ->setIcon('fa-pencil') - ->setName(pht('Edit Symbols')) - ->setHref($symbols_uri) - ->setDisabled(!$can_edit) - ->setWorkflow(!$can_edit)); - - return $this->getNewCurtainView($action_list); - } - public function buildManagementPanelContent() { $repository = $this->getRepository(); $viewer = $this->getViewer(); @@ -80,7 +47,22 @@ final class DiffusionRepositorySymbolsManagementPanel } $view->addProperty(pht('Uses Symbols From'), $sources); - return $this->newBox(pht('Symbols'), $view); + $can_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + $repository, + PhabricatorPolicyCapability::CAN_EDIT); + + $symbols_uri = $this->getEditPageURI(); + + $button = id(new PHUIButtonView()) + ->setTag('a') + ->setIcon('fa-pencil') + ->setText(pht('Edit')) + ->setHref($symbols_uri) + ->setDisabled(!$can_edit) + ->setWorkflow(!$can_edit); + + return $this->newBox(pht('Symbols'), $view, array($button)); } } diff --git a/src/applications/diffusion/management/DiffusionRepositoryURIsManagementPanel.php b/src/applications/diffusion/management/DiffusionRepositoryURIsManagementPanel.php index 4fe9e00475..220bf4e2c1 100644 --- a/src/applications/diffusion/management/DiffusionRepositoryURIsManagementPanel.php +++ b/src/applications/diffusion/management/DiffusionRepositoryURIsManagementPanel.php @@ -10,42 +10,13 @@ final class DiffusionRepositoryURIsManagementPanel } public function getManagementPanelIcon() { - return 'fa-cogs'; + return 'fa-globe'; } public function getManagementPanelOrder() { return 400; } - public function buildManagementPanelCurtain() { - $repository = $this->getRepository(); - $viewer = $this->getViewer(); - $action_list = $this->getNewActionList(); - - $can_edit = PhabricatorPolicyFilter::hasCapability( - $viewer, - $repository, - PhabricatorPolicyCapability::CAN_EDIT); - - $doc_href = PhabricatorEnv::getDoclink('Diffusion User Guide: URIs'); - $add_href = $repository->getPathURI('uri/edit/'); - - $action_list->addAction( - id(new PhabricatorActionView()) - ->setIcon('fa-plus') - ->setHref($add_href) - ->setDisabled(!$can_edit) - ->setName(pht('Add New URI'))); - - $action_list->addAction( - id(new PhabricatorActionView()) - ->setIcon('fa-book') - ->setHref($doc_href) - ->setName(pht('URI Documentation'))); - - return $this->getNewCurtainView($action_list); - } - public function buildManagementPanelContent() { $repository = $this->getRepository(); $viewer = $this->getViewer(); @@ -151,10 +122,30 @@ final class DiffusionRepositoryURIsManagementPanel ->setSeverity(PHUIInfoView::SEVERITY_NOTICE) ->setErrors($messages); - $box = $this->newBox(pht('Repository URIs'), null); - $box->setTable($table); + $can_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + $repository, + PhabricatorPolicyCapability::CAN_EDIT); - return array($info_view, $box); + $doc_href = PhabricatorEnv::getDoclink('Diffusion User Guide: URIs'); + $add_href = $repository->getPathURI('uri/edit/'); + + $add = id(new PHUIButtonView()) + ->setTag('a') + ->setIcon('fa-plus') + ->setHref($add_href) + ->setDisabled(!$can_edit) + ->setText(pht('New URI')); + + $help = id(new PHUIButtonView()) + ->setTag('a') + ->setIcon('fa-book') + ->setHref($doc_href) + ->setText(pht('Help')); + + $box = $this->newBox(pht('Repository URIs'), $table, array($add, $help)); + + return array($box, $info_view); } } diff --git a/webroot/rsrc/css/phui/phui-box.css b/webroot/rsrc/css/phui/phui-box.css index 2477437c06..278f1365e8 100644 --- a/webroot/rsrc/css/phui/phui-box.css +++ b/webroot/rsrc/css/phui/phui-box.css @@ -136,3 +136,8 @@ body .phui-box-blue-property .phui-header-shell + .phui-object-box { .phui-box-white-config .phui-header-header { color: {$bluetext}; } + +.phui-box-white-config .phui-header-action-links .button { + margin-top: 0; + margin-bottom: 0; +} diff --git a/webroot/rsrc/css/phui/phui-header-view.css b/webroot/rsrc/css/phui/phui-header-view.css index 82816b0220..e0fae307e2 100644 --- a/webroot/rsrc/css/phui/phui-header-view.css +++ b/webroot/rsrc/css/phui/phui-header-view.css @@ -337,6 +337,10 @@ body .phui-header-shell.phui-bleed-header color: {$blacktext}; } +.phui-profile-header.phui-header-shell .phui-header-header a { + color: {$blacktext}; +} + .phui-profile-header .phui-header-col3 { vertical-align: top; } From fc893658b8b668850fd349457aaf95c0670a0416 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Mon, 4 Sep 2017 09:20:10 -0700 Subject: [PATCH 12/54] Update menu item names for Applications -> Favorites Summary: Adds a `MenuName` method to applications that `ProfileMenuItem` uses instead of the application name if set. This improves the home/menu/new user experience at little cost. Also renamed the label from Applications to Favorites, since this menu gets altered to provide more than just applications. This also allows instances to set back to Maniphest if they so choose. Overall I think this direction resolves 95% of my concerns, with maybe a small potential downside which I don't really anticipate. We already name Dashboard panels by their object, and that hasn't really caused confusion. I think these links are similar. I click 'Tasks' and get presented a list of my tasks from Maniphest. Test Plan: Review each of the name changes as a default new install and a modified install. Reviewers: epriestley, amckinley Reviewed By: epriestley Spies: Korvin Differential Revision: https://secure.phabricator.com/D18524 --- src/applications/base/PhabricatorApplication.php | 4 ++++ .../application/PhabricatorDifferentialApplication.php | 6 +++++- .../application/PhabricatorDiffusionApplication.php | 4 ++++ .../home/engine/PhabricatorHomeProfileMenuEngine.php | 2 +- .../application/PhabricatorManiphestApplication.php | 4 ++++ .../phame/application/PhabricatorPhameApplication.php | 6 +++++- .../pholio/application/PhabricatorPholioApplication.php | 4 ++++ .../application/PhabricatorPhrictionApplication.php | 6 +++++- .../menuitem/PhabricatorApplicationProfileMenuItem.php | 2 +- 9 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/applications/base/PhabricatorApplication.php b/src/applications/base/PhabricatorApplication.php index f525d0ec97..72b577771f 100644 --- a/src/applications/base/PhabricatorApplication.php +++ b/src/applications/base/PhabricatorApplication.php @@ -57,6 +57,10 @@ abstract class PhabricatorApplication abstract public function getName(); + public function getMenuName() { + return $this->getName(); + } + public function getShortDescription() { return pht('%s Application', $this->getName()); } diff --git a/src/applications/differential/application/PhabricatorDifferentialApplication.php b/src/applications/differential/application/PhabricatorDifferentialApplication.php index e259c2f112..1c8926f585 100644 --- a/src/applications/differential/application/PhabricatorDifferentialApplication.php +++ b/src/applications/differential/application/PhabricatorDifferentialApplication.php @@ -10,8 +10,12 @@ final class PhabricatorDifferentialApplication extends PhabricatorApplication { return pht('Differential'); } + public function getMenuName() { + return pht('Code Review'); + } + public function getShortDescription() { - return pht('Review Code'); + return pht('Pre-Commit Review'); } public function getIcon() { diff --git a/src/applications/diffusion/application/PhabricatorDiffusionApplication.php b/src/applications/diffusion/application/PhabricatorDiffusionApplication.php index b00fcce77f..cf9c14aa8b 100644 --- a/src/applications/diffusion/application/PhabricatorDiffusionApplication.php +++ b/src/applications/diffusion/application/PhabricatorDiffusionApplication.php @@ -6,6 +6,10 @@ final class PhabricatorDiffusionApplication extends PhabricatorApplication { return pht('Diffusion'); } + public function getMenuName() { + return pht('Repositories'); + } + public function getShortDescription() { return pht('Host and Browse Repositories'); } diff --git a/src/applications/home/engine/PhabricatorHomeProfileMenuEngine.php b/src/applications/home/engine/PhabricatorHomeProfileMenuEngine.php index cbfe62aaa6..e380af2b6a 100644 --- a/src/applications/home/engine/PhabricatorHomeProfileMenuEngine.php +++ b/src/applications/home/engine/PhabricatorHomeProfileMenuEngine.php @@ -49,7 +49,7 @@ final class PhabricatorHomeProfileMenuEngine $items[] = $this->newItem() ->setBuiltinKey(PhabricatorHomeConstants::ITEM_APPS_LABEL) ->setMenuItemKey(PhabricatorLabelProfileMenuItem::MENUITEMKEY) - ->setMenuItemProperties(array('name' => pht('Applications'))); + ->setMenuItemProperties(array('name' => pht('Favorites'))); foreach ($applications as $application) { if (!$application->isPinnedByDefault($viewer)) { diff --git a/src/applications/maniphest/application/PhabricatorManiphestApplication.php b/src/applications/maniphest/application/PhabricatorManiphestApplication.php index 6cb9626d5a..3076354599 100644 --- a/src/applications/maniphest/application/PhabricatorManiphestApplication.php +++ b/src/applications/maniphest/application/PhabricatorManiphestApplication.php @@ -6,6 +6,10 @@ final class PhabricatorManiphestApplication extends PhabricatorApplication { return pht('Maniphest'); } + public function getMenuName() { + return pht('Tasks'); + } + public function getShortDescription() { return pht('Tasks and Bugs'); } diff --git a/src/applications/phame/application/PhabricatorPhameApplication.php b/src/applications/phame/application/PhabricatorPhameApplication.php index 677872ba1e..f9ee2831b2 100644 --- a/src/applications/phame/application/PhabricatorPhameApplication.php +++ b/src/applications/phame/application/PhabricatorPhameApplication.php @@ -6,6 +6,10 @@ final class PhabricatorPhameApplication extends PhabricatorApplication { return pht('Phame'); } + public function getMenuName() { + return pht('Blogs'); + } + public function getBaseURI() { return '/phame/'; } @@ -15,7 +19,7 @@ final class PhabricatorPhameApplication extends PhabricatorApplication { } public function getShortDescription() { - return pht('Blog'); + return pht('Internal and External Blogs'); } public function getTitleGlyph() { diff --git a/src/applications/pholio/application/PhabricatorPholioApplication.php b/src/applications/pholio/application/PhabricatorPholioApplication.php index 4d80dd12ae..4afaeba263 100644 --- a/src/applications/pholio/application/PhabricatorPholioApplication.php +++ b/src/applications/pholio/application/PhabricatorPholioApplication.php @@ -6,6 +6,10 @@ final class PhabricatorPholioApplication extends PhabricatorApplication { return pht('Pholio'); } + public function getMenuName() { + return pht('Design Review'); + } + public function getBaseURI() { return '/pholio/'; } diff --git a/src/applications/phriction/application/PhabricatorPhrictionApplication.php b/src/applications/phriction/application/PhabricatorPhrictionApplication.php index d0eb46a069..1b06fd197c 100644 --- a/src/applications/phriction/application/PhabricatorPhrictionApplication.php +++ b/src/applications/phriction/application/PhabricatorPhrictionApplication.php @@ -6,10 +6,14 @@ final class PhabricatorPhrictionApplication extends PhabricatorApplication { return pht('Phriction'); } - public function getShortDescription() { + public function getMenuName() { return pht('Wiki'); } + public function getShortDescription() { + return pht('Wiki Documents'); + } + public function getBaseURI() { return '/w/'; } diff --git a/src/applications/search/menuitem/PhabricatorApplicationProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorApplicationProfileMenuItem.php index aa42d56cfb..40275a8d7a 100644 --- a/src/applications/search/menuitem/PhabricatorApplicationProfileMenuItem.php +++ b/src/applications/search/menuitem/PhabricatorApplicationProfileMenuItem.php @@ -31,7 +31,7 @@ final class PhabricatorApplicationProfileMenuItem return $name; } - return $application->getName(); + return $application->getMenuName(); } public function buildEditEngineFields( From 6e25d4c67b1a158c86c275b4e9c76288b2f297cf Mon Sep 17 00:00:00 2001 From: Chad Little Date: Tue, 5 Sep 2017 19:30:52 -0700 Subject: [PATCH 13/54] Update Settings for WHITE_CONFIG style boxes Summary: Updates settings panel UI for new white box, cleans up other various UI nitpicks. Test Plan: Click through each setting that had a local setting page. Edit Engine pages will follow up on another diff. Reviewers: epriestley Reviewed By: epriestley Spies: Korvin Differential Revision: https://secure.phabricator.com/D18526 --- resources/celerity/map.php | 6 +-- .../PhabricatorConduitTokensSettingsPanel.php | 11 ++--- ...OAuthServerAuthorizationsSettingsPanel.php | 4 +- .../PhabricatorActivitySettingsPanel.php | 5 +-- ...PhabricatorEmailAddressesSettingsPanel.php | 24 +++++------ ...abricatorEmailPreferencesSettingsPanel.php | 2 +- ...abricatorExternalAccountsSettingsPanel.php | 35 ++++++---------- .../PhabricatorMultiFactorSettingsPanel.php | 37 +++++++---------- .../PhabricatorNotificationsSettingsPanel.php | 19 +++------ .../PhabricatorPasswordSettingsPanel.php | 40 ++++++++++--------- .../panel/PhabricatorSSHKeysSettingsPanel.php | 9 +---- .../PhabricatorSessionsSettingsPanel.php | 27 +++++-------- .../panel/PhabricatorSettingsPanel.php | 17 ++++++++ .../panel/PhabricatorTokensSettingsPanel.php | 18 +++------ webroot/rsrc/css/phui/phui-header-view.css | 4 -- 15 files changed, 109 insertions(+), 149 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 8ca8f081df..d82341b47d 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -9,7 +9,7 @@ return array( 'names' => array( 'conpherence.pkg.css' => 'e68cf1fa', 'conpherence.pkg.js' => 'b5b51108', - 'core.pkg.css' => 'ebbf04f7', + 'core.pkg.css' => '03264689', 'core.pkg.js' => '6c085267', 'darkconsole.pkg.js' => '1f9a31bc', 'differential.pkg.css' => '45951e9e', @@ -157,7 +157,7 @@ return array( 'rsrc/css/phui/phui-form-view.css' => 'ae9f8d16', 'rsrc/css/phui/phui-form.css' => '7aaa04e3', 'rsrc/css/phui/phui-head-thing.css' => 'fd311e5f', - 'rsrc/css/phui/phui-header-view.css' => '369275d6', + 'rsrc/css/phui/phui-header-view.css' => '67fab16d', 'rsrc/css/phui/phui-hovercard.css' => 'f0592bcf', 'rsrc/css/phui/phui-icon-set-selector.css' => '87db8fee', 'rsrc/css/phui/phui-icon.css' => '5c4a5de6', @@ -843,7 +843,7 @@ return array( 'phui-form-css' => '7aaa04e3', 'phui-form-view-css' => 'ae9f8d16', 'phui-head-thing-view-css' => 'fd311e5f', - 'phui-header-view-css' => '369275d6', + 'phui-header-view-css' => '67fab16d', 'phui-hovercard' => '1bd28176', 'phui-hovercard-view-css' => 'f0592bcf', 'phui-icon-set-selector-css' => '87db8fee', diff --git a/src/applications/conduit/settings/PhabricatorConduitTokensSettingsPanel.php b/src/applications/conduit/settings/PhabricatorConduitTokensSettingsPanel.php index 3da467e4f4..2075582386 100644 --- a/src/applications/conduit/settings/PhabricatorConduitTokensSettingsPanel.php +++ b/src/applications/conduit/settings/PhabricatorConduitTokensSettingsPanel.php @@ -88,18 +88,19 @@ final class PhabricatorConduitTokensSettingsPanel )); $generate_button = id(new PHUIButtonView()) - ->setText(pht('Generate API Token')) + ->setText(pht('Generate Token')) ->setHref('/conduit/token/edit/?objectPHID='.$user->getPHID()) ->setTag('a') ->setWorkflow(true) ->setIcon('fa-plus'); $terminate_button = id(new PHUIButtonView()) - ->setText(pht('Terminate All Tokens')) + ->setText(pht('Terminate Tokens')) ->setHref('/conduit/token/terminate/?objectPHID='.$user->getPHID()) ->setTag('a') ->setWorkflow(true) - ->setIcon('fa-exclamation-triangle'); + ->setIcon('fa-exclamation-triangle') + ->setColor(PHUIButtonView::RED); $header = id(new PHUIHeaderView()) ->setHeader(pht('Active API Tokens')) @@ -108,8 +109,8 @@ final class PhabricatorConduitTokensSettingsPanel $panel = id(new PHUIObjectBoxView()) ->setHeader($header) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) - ->setTable($table); + ->setBackground(PHUIObjectBoxView::WHITE_CONFIG) + ->appendChild($table); return $panel; } diff --git a/src/applications/oauthserver/panel/PhabricatorOAuthServerAuthorizationsSettingsPanel.php b/src/applications/oauthserver/panel/PhabricatorOAuthServerAuthorizationsSettingsPanel.php index cfc0bc91a8..37e85ab53b 100644 --- a/src/applications/oauthserver/panel/PhabricatorOAuthServerAuthorizationsSettingsPanel.php +++ b/src/applications/oauthserver/panel/PhabricatorOAuthServerAuthorizationsSettingsPanel.php @@ -134,8 +134,8 @@ final class PhabricatorOAuthServerAuthorizationsSettingsPanel $panel = id(new PHUIObjectBoxView()) ->setHeader($header) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) - ->setTable($table); + ->setBackground(PHUIObjectBoxView::WHITE_CONFIG) + ->appendChild($table); return $panel; } diff --git a/src/applications/settings/panel/PhabricatorActivitySettingsPanel.php b/src/applications/settings/panel/PhabricatorActivitySettingsPanel.php index 0b3533f287..50f951d661 100644 --- a/src/applications/settings/panel/PhabricatorActivitySettingsPanel.php +++ b/src/applications/settings/panel/PhabricatorActivitySettingsPanel.php @@ -46,10 +46,7 @@ final class PhabricatorActivitySettingsPanel extends PhabricatorSettingsPanel { ->setLogs($logs) ->setHandles($handles); - $panel = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Account Activity Logs')) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) - ->setTable($table); + $panel = $this->newBox(pht('Account Activity Logs'), $table); $pager_box = id(new PHUIBoxView()) ->addMargin(PHUI::MARGIN_LARGE) diff --git a/src/applications/settings/panel/PhabricatorEmailAddressesSettingsPanel.php b/src/applications/settings/panel/PhabricatorEmailAddressesSettingsPanel.php index 66fd0396ad..1bdb95f568 100644 --- a/src/applications/settings/panel/PhabricatorEmailAddressesSettingsPanel.php +++ b/src/applications/settings/panel/PhabricatorEmailAddressesSettingsPanel.php @@ -138,24 +138,18 @@ final class PhabricatorEmailAddressesSettingsPanel $editable, )); - $view = new PHUIObjectBoxView(); - $header = new PHUIHeaderView(); - $header->setHeader(pht('Email Addresses')); - + $button = null; if ($editable) { - $button = new PHUIButtonView(); - $button->setText(pht('Add New Address')); - $button->setTag('a'); - $button->setHref($uri->alter('new', 'true')); - $button->setIcon('fa-plus'); - $button->addSigil('workflow'); - $header->addActionLink($button); + $button = id(new PHUIButtonView()) + ->setTag('a') + ->setIcon('fa-plus') + ->setText(pht('Add New Address')) + ->setHref($uri->alter('new', 'true')) + ->addSigil('workflow') + ->setColor(PHUIButtonView::GREY); } - $view->setHeader($header); - $view->setTable($table); - $view->setBackground(PHUIObjectBoxView::BLUE_PROPERTY); - return $view; + return $this->newBox(pht('Email Addresses'), $table, array($button)); } private function returnNewAddressResponse( diff --git a/src/applications/settings/panel/PhabricatorEmailPreferencesSettingsPanel.php b/src/applications/settings/panel/PhabricatorEmailPreferencesSettingsPanel.php index 77364e0aa0..faa79889ed 100644 --- a/src/applications/settings/panel/PhabricatorEmailPreferencesSettingsPanel.php +++ b/src/applications/settings/panel/PhabricatorEmailPreferencesSettingsPanel.php @@ -136,7 +136,7 @@ final class PhabricatorEmailPreferencesSettingsPanel ->setHeaderText(pht('Email Preferences')) ->setFormSaved($request->getStr('saved')) ->setFormErrors($errors) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) + ->setBackground(PHUIObjectBoxView::WHITE_CONFIG) ->setForm($form); return $form_box; diff --git a/src/applications/settings/panel/PhabricatorExternalAccountsSettingsPanel.php b/src/applications/settings/panel/PhabricatorExternalAccountsSettingsPanel.php index 068c58d549..e380248a83 100644 --- a/src/applications/settings/panel/PhabricatorExternalAccountsSettingsPanel.php +++ b/src/applications/settings/panel/PhabricatorExternalAccountsSettingsPanel.php @@ -31,12 +31,10 @@ final class PhabricatorExternalAccountsSettingsPanel )) ->execute(); - $linked_head = id(new PHUIHeaderView()) - ->setHeader(pht('Linked Accounts and Authentication')); + $linked_head = pht('Linked Accounts and Authentication'); $linked = id(new PHUIObjectItemListView()) ->setUser($viewer) - ->setFlush(true) ->setNoDataString(pht('You have no linked accounts.')); $login_accounts = 0; @@ -47,7 +45,7 @@ final class PhabricatorExternalAccountsSettingsPanel } foreach ($accounts as $account) { - $item = id(new PHUIObjectItemView()); + $item = new PHUIObjectItemView(); $provider = idx($providers, $account->getProviderKey()); if ($provider) { @@ -94,12 +92,10 @@ final class PhabricatorExternalAccountsSettingsPanel $linked->addItem($item); } - $linkable_head = id(new PHUIHeaderView()) - ->setHeader(pht('Add External Account')); + $linkable_head = pht('Add External Account'); $linkable = id(new PHUIObjectItemListView()) ->setUser($viewer) - ->setFlush(true) ->setNoDataString( pht('Your account is linked with all available providers.')); @@ -118,26 +114,19 @@ final class PhabricatorExternalAccountsSettingsPanel $link_uri = '/auth/link/'.$provider->getProviderKey().'/'; - $item = id(new PHUIObjectItemView()); - $item->setHeader($provider->getProviderName()); - $item->setHref($link_uri); - $item->addAction( - id(new PHUIListItemView()) - ->setIcon('fa-link') - ->setHref($link_uri)); + $item = id(new PHUIObjectItemView()) + ->setHeader($provider->getProviderName()) + ->setHref($link_uri) + ->addAction( + id(new PHUIListItemView()) + ->setIcon('fa-link') + ->setHref($link_uri)); $linkable->addItem($item); } - $linked_box = id(new PHUIObjectBoxView()) - ->setHeader($linked_head) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) - ->setObjectList($linked); - - $linkable_box = id(new PHUIObjectBoxView()) - ->setHeader($linkable_head) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) - ->setObjectList($linkable); + $linked_box = $this->newBox($linked_head, $linked); + $linkable_box = $this->newBox($linkable_head, $linkable); return array( $linked_box, diff --git a/src/applications/settings/panel/PhabricatorMultiFactorSettingsPanel.php b/src/applications/settings/panel/PhabricatorMultiFactorSettingsPanel.php index 68d1812616..ae653e0f70 100644 --- a/src/applications/settings/panel/PhabricatorMultiFactorSettingsPanel.php +++ b/src/applications/settings/panel/PhabricatorMultiFactorSettingsPanel.php @@ -101,34 +101,27 @@ final class PhabricatorMultiFactorSettingsPanel true, )); - $panel = new PHUIObjectBoxView(); - $header = new PHUIHeaderView(); - $help_uri = PhabricatorEnv::getDoclink( 'User Guide: Multi-Factor Authentication'); - $help_button = id(new PHUIButtonView()) + $buttons = array(); + + $buttons[] = id(new PHUIButtonView()) + ->setTag('a') + ->setIcon('fa-plus') + ->setText(pht('Add Auth Factor')) + ->setHref($this->getPanelURI('?new=true')) + ->setWorkflow(true) + ->setColor(PHUIButtonView::GREY); + + $buttons[] = id(new PHUIButtonView()) + ->setTag('a') + ->setIcon('fa-book') ->setText(pht('Help')) ->setHref($help_uri) - ->setTag('a') - ->setIcon('fa-info-circle'); + ->setColor(PHUIButtonView::GREY); - $create_button = id(new PHUIButtonView()) - ->setText(pht('Add Authentication Factor')) - ->setHref($this->getPanelURI('?new=true')) - ->setTag('a') - ->setWorkflow(true) - ->setIcon('fa-plus'); - - $header->setHeader(pht('Authentication Factors')); - $header->addActionLink($help_button); - $header->addActionLink($create_button); - - $panel->setHeader($header); - $panel->setTable($table); - $panel->setBackground(PHUIObjectBoxView::BLUE_PROPERTY); - - return $panel; + return $this->newBox(pht('Authentication Factors'), $table, $buttons); } private function processNew(AphrontRequest $request) { diff --git a/src/applications/settings/panel/PhabricatorNotificationsSettingsPanel.php b/src/applications/settings/panel/PhabricatorNotificationsSettingsPanel.php index d61ece6da5..e75c2b99ee 100644 --- a/src/applications/settings/panel/PhabricatorNotificationsSettingsPanel.php +++ b/src/applications/settings/panel/PhabricatorNotificationsSettingsPanel.php @@ -152,24 +152,17 @@ final class PhabricatorNotificationsSettingsPanel id(new AphrontFormSubmitControl()) ->setValue(pht('Save Preference'))); - $test_button = id(new PHUIButtonView()) + $button = id(new PHUIButtonView()) ->setTag('a') + ->setIcon('fa-send-o') ->setWorkflow(true) ->setText(pht('Send Test Notification')) ->setHref('/notification/test/') - ->setIcon('fa-exclamation-triangle'); + ->setColor(PHUIButtonView::GREY); - $form_box = id(new PHUIObjectBoxView()) - ->setHeader( - id(new PHUIHeaderView()) - ->setHeader(pht('Notifications')) - ->addActionLink($test_button)) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) - ->appendChild(array( - $saved_box, - $status_box, - $form, - )); + $form_content = array($saved_box, $status_box, $form); + $form_box = $this->newBox( + pht('Notifications'), $form_content, array($button)); $browser_status_box = id(new PHUIInfoView()) ->setID($browser_status_id) diff --git a/src/applications/settings/panel/PhabricatorPasswordSettingsPanel.php b/src/applications/settings/panel/PhabricatorPasswordSettingsPanel.php index 2a1b482c80..c1250fca23 100644 --- a/src/applications/settings/panel/PhabricatorPasswordSettingsPanel.php +++ b/src/applications/settings/panel/PhabricatorPasswordSettingsPanel.php @@ -91,7 +91,7 @@ final class PhabricatorPasswordSettingsPanel extends PhabricatorSettingsPanel { // is changed here the CSRF token check will fail. $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); - $envelope = new PhutilOpaqueEnvelope($pass); + $envelope = new PhutilOpaqueEnvelope($pass); id(new PhabricatorUserEditor()) ->setActor($user) ->changePassword($user, $envelope); @@ -172,45 +172,47 @@ final class PhabricatorPasswordSettingsPanel extends PhabricatorSettingsPanel { ->setDisableAutocomplete(true) ->setLabel(pht('New Password')) ->setError($e_new) - ->setName('new_pw')); - $form + ->setName('new_pw')) ->appendChild( id(new AphrontFormPasswordControl()) ->setDisableAutocomplete(true) ->setLabel(pht('Confirm Password')) ->setCaption($len_caption) ->setError($e_conf) - ->setName('conf_pw')); - $form + ->setName('conf_pw')) ->appendChild( id(new AphrontFormSubmitControl()) ->setValue(pht('Change Password'))); - $form->appendChild( - id(new AphrontFormStaticControl()) - ->setLabel(pht('Current Algorithm')) - ->setValue(PhabricatorPasswordHasher::getCurrentAlgorithmName( - new PhutilOpaqueEnvelope($user->getPasswordHash())))); + $properties = id(new PHUIPropertyListView()); - $form->appendChild( - id(new AphrontFormStaticControl()) - ->setLabel(pht('Best Available Algorithm')) - ->setValue(PhabricatorPasswordHasher::getBestAlgorithmName())); + $properties->addProperty( + pht('Current Algorithm'), + PhabricatorPasswordHasher::getCurrentAlgorithmName( + new PhutilOpaqueEnvelope($user->getPasswordHash()))); - $form->appendRemarkupInstructions( - pht( - 'NOTE: Changing your password will terminate any other outstanding '. - 'login sessions.')); + $properties->addProperty( + pht('Best Available Algorithm'), + PhabricatorPasswordHasher::getBestAlgorithmName()); + $info_view = id(new PHUIInfoView()) + ->setSeverity(PHUIInfoView::SEVERITY_NOTICE) + ->appendChild( + pht('Changing your password will terminate any other outstanding '. + 'login sessions.')); + + $algo_box = $this->newBox(pht('Password Algorithms'), $properties); $form_box = id(new PHUIObjectBoxView()) ->setHeaderText(pht('Change Password')) ->setFormSaved($request->getStr('saved')) ->setFormErrors($errors) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) + ->setBackground(PHUIObjectBoxView::WHITE_CONFIG) ->setForm($form); return array( $form_box, + $algo_box, + $info_view, ); } diff --git a/src/applications/settings/panel/PhabricatorSSHKeysSettingsPanel.php b/src/applications/settings/panel/PhabricatorSSHKeysSettingsPanel.php index 3e339e9145..13944411ed 100644 --- a/src/applications/settings/panel/PhabricatorSSHKeysSettingsPanel.php +++ b/src/applications/settings/panel/PhabricatorSSHKeysSettingsPanel.php @@ -45,14 +45,7 @@ final class PhabricatorSSHKeysSettingsPanel extends PhabricatorSettingsPanel { $viewer, $user); - $header->setHeader(pht('SSH Public Keys')); - $header->addActionLink($ssh_actions); - - $panel->setHeader($header); - $panel->setTable($table); - $panel->setBackground(PHUIObjectBoxView::BLUE_PROPERTY); - - return $panel; + return $this->newBox(pht('SSH Public Keys'), $table, array($ssh_actions)); } } diff --git a/src/applications/settings/panel/PhabricatorSessionsSettingsPanel.php b/src/applications/settings/panel/PhabricatorSessionsSettingsPanel.php index fb60e40d81..eab18002a1 100644 --- a/src/applications/settings/panel/PhabricatorSessionsSettingsPanel.php +++ b/src/applications/settings/panel/PhabricatorSessionsSettingsPanel.php @@ -112,34 +112,27 @@ final class PhabricatorSessionsSettingsPanel extends PhabricatorSettingsPanel { 'action', )); - $terminate_button = id(new PHUIButtonView()) + $buttons = array(); + $buttons[] = id(new PHUIButtonView()) + ->setTag('a') + ->setIcon('fa-warning') ->setText(pht('Terminate All Sessions')) ->setHref('/auth/session/terminate/all/') - ->setTag('a') ->setWorkflow(true) - ->setIcon('fa-exclamation-triangle'); - - $header = id(new PHUIHeaderView()) - ->setHeader(pht('Active Login Sessions')) - ->addActionLink($terminate_button); + ->setColor(PHUIButtonView::RED); $hisec = ($viewer->getSession()->getHighSecurityUntil() - time()); if ($hisec > 0) { - $hisec_button = id(new PHUIButtonView()) + $buttons[] = id(new PHUIButtonView()) + ->setTag('a') + ->setIcon('fa-lock') ->setText(pht('Leave High Security')) ->setHref('/auth/session/downgrade/') - ->setTag('a') ->setWorkflow(true) - ->setIcon('fa-lock'); - $header->addActionLink($hisec_button); + ->setColor(PHUIButtonView::RED); } - $panel = id(new PHUIObjectBoxView()) - ->setHeader($header) - ->setTable($table) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY); - - return $panel; + return $this->newBox(pht('Active Login Sessions'), $table, $buttons); } } diff --git a/src/applications/settings/panel/PhabricatorSettingsPanel.php b/src/applications/settings/panel/PhabricatorSettingsPanel.php index eea48e540f..d2008f8857 100644 --- a/src/applications/settings/panel/PhabricatorSettingsPanel.php +++ b/src/applications/settings/panel/PhabricatorSettingsPanel.php @@ -281,4 +281,21 @@ abstract class PhabricatorSettingsPanel extends Phobject { $editor->applyTransactions($preferences, $xactions); } + + public function newBox($title, $content, $actions = array()) { + $header = id(new PHUIHeaderView()) + ->setHeader($title); + + foreach ($actions as $action) { + $header->addActionLink($action); + } + + $view = id(new PHUIObjectBoxView()) + ->setHeader($header) + ->appendChild($content) + ->setBackground(PHUIObjectBoxView::WHITE_CONFIG); + + return $view; + } + } diff --git a/src/applications/settings/panel/PhabricatorTokensSettingsPanel.php b/src/applications/settings/panel/PhabricatorTokensSettingsPanel.php index d2cc0dedb6..f2021bafa5 100644 --- a/src/applications/settings/panel/PhabricatorTokensSettingsPanel.php +++ b/src/applications/settings/panel/PhabricatorTokensSettingsPanel.php @@ -71,23 +71,15 @@ final class PhabricatorTokensSettingsPanel extends PhabricatorSettingsPanel { 'action', )); - $terminate_button = id(new PHUIButtonView()) + $button = id(new PHUIButtonView()) + ->setTag('a') + ->setIcon('fa-warning') ->setText(pht('Revoke All')) ->setHref('/auth/token/revoke/all/') - ->setTag('a') ->setWorkflow(true) - ->setIcon('fa-exclamation-triangle'); + ->setColor(PHUIButtonView::RED); - $header = id(new PHUIHeaderView()) - ->setHeader(pht('Temporary Tokens')) - ->addActionLink($terminate_button); - - $panel = id(new PHUIObjectBoxView()) - ->setHeader($header) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) - ->setTable($table); - - return $panel; + return $this->newBox(pht('Temporary Tokens'), $table, array($button)); } } diff --git a/webroot/rsrc/css/phui/phui-header-view.css b/webroot/rsrc/css/phui/phui-header-view.css index e0fae307e2..18b1464e53 100644 --- a/webroot/rsrc/css/phui/phui-header-view.css +++ b/webroot/rsrc/css/phui/phui-header-view.css @@ -341,10 +341,6 @@ body .phui-header-shell.phui-bleed-header color: {$blacktext}; } -.phui-profile-header .phui-header-col3 { - vertical-align: top; -} - .phui-header-view .phui-tag-indigo a { color: {$sh-indigotext}; } From a903388d4f891716c1069fd04f2220266897e4ec Mon Sep 17 00:00:00 2001 From: Chad Little Date: Tue, 5 Sep 2017 20:02:11 -0700 Subject: [PATCH 14/54] Update EditEngine pages to take a page header separate Summary: This simplifies EditEngine pages in general by removing the dual header, and extending to allow setting of a custom PHUIHeaderView if needed (like settings). Test Plan: Review all settings pages, review task, project pages. This should all be fine, but is a big change maybe some layouts I'm not considering. Tested these all mobile, destkop as well. {F5166181} Reviewers: epriestley Reviewed By: epriestley Spies: Korvin Differential Revision: https://secure.phabricator.com/D18527 --- resources/celerity/map.php | 6 ++-- .../editor/PhabricatorSettingsEditEngine.php | 25 +++++++++++++---- .../editengine/PhabricatorEditEngine.php | 28 +++++++++++++------ src/view/phui/PHUIInfoView.php | 1 - src/view/phui/PHUITwoColumnView.php | 4 +++ .../rsrc/css/phui/phui-two-column-view.css | 4 +++ 6 files changed, 50 insertions(+), 18 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index d82341b47d..aef701f7bc 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -9,7 +9,7 @@ return array( 'names' => array( 'conpherence.pkg.css' => 'e68cf1fa', 'conpherence.pkg.js' => 'b5b51108', - 'core.pkg.css' => '03264689', + 'core.pkg.css' => 'b2235af0', 'core.pkg.js' => '6c085267', 'darkconsole.pkg.js' => '1f9a31bc', 'differential.pkg.css' => '45951e9e', @@ -177,7 +177,7 @@ return array( 'rsrc/css/phui/phui-status.css' => 'd5263e49', 'rsrc/css/phui/phui-tag-view.css' => 'b4719c50', 'rsrc/css/phui/phui-timeline-view.css' => 'f21db7ca', - 'rsrc/css/phui/phui-two-column-view.css' => 'bf86c483', + 'rsrc/css/phui/phui-two-column-view.css' => '1ade9c5f', 'rsrc/css/phui/workboards/phui-workboard-color.css' => '783cdff5', 'rsrc/css/phui/workboards/phui-workboard.css' => '3bc85455', 'rsrc/css/phui/workboards/phui-workcard.css' => 'cca5fa92', @@ -872,7 +872,7 @@ return array( 'phui-tag-view-css' => 'b4719c50', 'phui-theme-css' => '9f261c6b', 'phui-timeline-view-css' => 'f21db7ca', - 'phui-two-column-view-css' => 'bf86c483', + 'phui-two-column-view-css' => '1ade9c5f', 'phui-workboard-color-css' => '783cdff5', 'phui-workboard-view-css' => '3bc85455', 'phui-workcard-view-css' => 'cca5fa92', diff --git a/src/applications/settings/editor/PhabricatorSettingsEditEngine.php b/src/applications/settings/editor/PhabricatorSettingsEditEngine.php index e12654e1a4..30e831543d 100644 --- a/src/applications/settings/editor/PhabricatorSettingsEditEngine.php +++ b/src/applications/settings/editor/PhabricatorSettingsEditEngine.php @@ -63,12 +63,13 @@ final class PhabricatorSettingsEditEngine } protected function getObjectEditTitleText($object) { - $user = $object->getUser(); - if ($user) { - return pht('Edit Settings (%s)', $user->getUserName()); - } else { - return pht('Edit Global Settings'); + $page = $this->getSelectedPage(); + + if ($page) { + return $page->getLabel(); } + + return pht('Settings'); } protected function getObjectEditShortText($object) { @@ -97,6 +98,20 @@ final class PhabricatorSettingsEditEngine return pht('Settings'); } + protected function getPageHeader($object) { + $user = $object->getUser(); + if ($user) { + $text = pht('Edit Settings (%s)', $user->getUserName()); + } else { + $text = pht('Edit Global Settings'); + } + + $header = id(new PHUIHeaderView()) + ->setHeader($text); + + return $header; + } + protected function getEditorURI() { throw new PhutilMethodNotImplementedException(); } diff --git a/src/applications/transactions/editengine/PhabricatorEditEngine.php b/src/applications/transactions/editengine/PhabricatorEditEngine.php index d09e2450a1..e1d6812778 100644 --- a/src/applications/transactions/editengine/PhabricatorEditEngine.php +++ b/src/applications/transactions/editengine/PhabricatorEditEngine.php @@ -312,6 +312,15 @@ abstract class PhabricatorEditEngine } + /** + * @task text + */ + protected function getPageHeader($object) { + return null; + } + + + /** * Return a human-readable header describing what this engine is used to do, * like "Configure Maniphest Task Forms". @@ -1169,6 +1178,9 @@ abstract class PhabricatorEditEngine $form = $this->buildEditForm($object, $fields); + $crumbs = $this->buildCrumbs($object, $final = true); + $crumbs->setBorder(true); + if ($request->isAjax()) { return $this->getController() ->newDialog() @@ -1180,21 +1192,18 @@ abstract class PhabricatorEditEngine ->addSubmitButton($submit_button); } - $crumbs = $this->buildCrumbs($object, $final = true); - - $header = id(new PHUIHeaderView()) + $box_header = id(new PHUIHeaderView()) ->setHeader($header_text); - $crumbs->setBorder(true); if ($action_button) { - $header->addActionLink($action_button); + $box_header->addActionLink($action_button); } $box = id(new PHUIObjectBoxView()) ->setUser($viewer) - ->setHeaderText($this->getObjectName()) + ->setHeader($box_header) ->setValidationException($validation_exception) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) + ->setBackground(PHUIObjectBoxView::WHITE_CONFIG) ->appendChild($form); // This is fairly questionable, but in use by Settings. @@ -1209,8 +1218,9 @@ abstract class PhabricatorEditEngine $view = new PHUITwoColumnView(); - if ($header) { - $view->setHeader($header); + $page_header = $this->getPageHeader($object); + if ($page_header) { + $view->setHeader($page_header); } $page = $controller->newPage() diff --git a/src/view/phui/PHUIInfoView.php b/src/view/phui/PHUIInfoView.php index 161e49108b..18f5af3374 100644 --- a/src/view/phui/PHUIInfoView.php +++ b/src/view/phui/PHUIInfoView.php @@ -59,7 +59,6 @@ final class PHUIInfoView extends AphrontTagView { } else { $icon = id(new PHUIIconView()) ->setIcon($icon); - $this->icon = $icon; } return $this; diff --git a/src/view/phui/PHUITwoColumnView.php b/src/view/phui/PHUITwoColumnView.php index 6e261ffeeb..9240887f4b 100644 --- a/src/view/phui/PHUITwoColumnView.php +++ b/src/view/phui/PHUITwoColumnView.php @@ -106,6 +106,10 @@ final class PHUITwoColumnView extends AphrontTagView { $classes[] = 'with-subheader'; } + if (!$this->header) { + $classes[] = 'without-header'; + } + return array( 'class' => implode(' ', $classes), ); diff --git a/webroot/rsrc/css/phui/phui-two-column-view.css b/webroot/rsrc/css/phui/phui-two-column-view.css index 73926be92a..2fb0eccee2 100644 --- a/webroot/rsrc/css/phui/phui-two-column-view.css +++ b/webroot/rsrc/css/phui/phui-two-column-view.css @@ -13,6 +13,10 @@ margin-bottom: 24px; } +.phui-two-column-view.without-header { + margin-top: 24px; +} + .device .phui-two-column-view .phui-two-column-header { margin-bottom: 12px; } From 20584a39d9e4c69584a8e18acf97aaf0223cca82 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Mon, 4 Sep 2017 16:38:45 -0700 Subject: [PATCH 15/54] Update Dashboards for new Edit UI Summary: Updates Dashboard create/edit pages Test Plan: Create a Dashboard, edit a dashboard Reviewers: epriestley Reviewed By: epriestley Spies: Korvin Differential Revision: https://secure.phabricator.com/D18528 --- .../controller/PhabricatorDashboardEditController.php | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/applications/dashboard/controller/PhabricatorDashboardEditController.php b/src/applications/dashboard/controller/PhabricatorDashboardEditController.php index 0edda37102..6b3a96d80c 100644 --- a/src/applications/dashboard/controller/PhabricatorDashboardEditController.php +++ b/src/applications/dashboard/controller/PhabricatorDashboardEditController.php @@ -184,19 +184,14 @@ final class PhabricatorDashboardEditController ->addCancelButton($cancel_uri)); $box = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Dashboard')) + ->setHeaderText($title) ->setForm($form) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) + ->setBackground(PHUIObjectBoxView::WHITE_CONFIG) ->setValidationException($validation_exception); $crumbs->setBorder(true); - $header = id(new PHUIHeaderView()) - ->setHeader($title) - ->setHeaderIcon($header_icon); - $view = id(new PHUITwoColumnView()) - ->setHeader($header) ->setFooter($box); return $this->newPage() From 818b90cf12d42a30ec73d24e484cddebd4bb42af Mon Sep 17 00:00:00 2001 From: Chad Little Date: Wed, 6 Sep 2017 10:11:14 -0700 Subject: [PATCH 16/54] Update Create Diff page for new Edit UI Summary: Create a diff page, new UI Test Plan: Create a diff from page Reviewers: epriestley Reviewed By: epriestley Spies: Korvin Differential Revision: https://secure.phabricator.com/D18529 --- .../controller/DifferentialDiffCreateController.php | 11 +++-------- src/view/phui/PHUIInfoView.php | 1 + 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/applications/differential/controller/DifferentialDiffCreateController.php b/src/applications/differential/controller/DifferentialDiffCreateController.php index 0e13ea08fd..36f0b86202 100644 --- a/src/applications/differential/controller/DifferentialDiffCreateController.php +++ b/src/applications/differential/controller/DifferentialDiffCreateController.php @@ -182,10 +182,10 @@ final class DifferentialDiffCreateController extends DifferentialController { ->setValue($button)); $form_box = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Diff')) + ->setHeaderText($title) ->setValidationException($validation_exception) ->setForm($form) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) + ->setBackground(PHUIObjectBoxView::WHITE_CONFIG) ->setFormErrors($errors); $crumbs = $this->buildApplicationCrumbs(); @@ -197,15 +197,10 @@ final class DifferentialDiffCreateController extends DifferentialController { $crumbs->addTextCrumb($title); $crumbs->setBorder(true); - $header = id(new PHUIHeaderView()) - ->setHeader($title) - ->setHeaderIcon($header_icon); - $view = id(new PHUITwoColumnView()) - ->setHeader($header) ->setFooter(array( - $info_view, $form_box, + $info_view, )); return $this->newPage() diff --git a/src/view/phui/PHUIInfoView.php b/src/view/phui/PHUIInfoView.php index 18f5af3374..161e49108b 100644 --- a/src/view/phui/PHUIInfoView.php +++ b/src/view/phui/PHUIInfoView.php @@ -59,6 +59,7 @@ final class PHUIInfoView extends AphrontTagView { } else { $icon = id(new PHUIIconView()) ->setIcon($icon); + $this->icon = $icon; } return $this; From e91d72fefbf995423e8dad3131cdb679b88fcee3 Mon Sep 17 00:00:00 2001 From: epriestley Date: Wed, 6 Sep 2017 09:25:31 -0700 Subject: [PATCH 17/54] Un-hide the "X added reviewers: ..." transactions in revision creation mail Summary: Fixes T12118. See PHI54. This adds a special case for the initial "reviewers" transactions, similar to the existing special case for "projects" transactions. Although these transactions are redudnant in the web view since you can see the information clearly on the page, they're more reasonably useful in mail. Test Plan: {F5168838} Reviewers: chad Reviewed By: chad Maniphest Tasks: T12118 Differential Revision: https://secure.phabricator.com/D18542 --- .../differential/storage/DifferentialTransaction.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/applications/differential/storage/DifferentialTransaction.php b/src/applications/differential/storage/DifferentialTransaction.php index 1cd1f2b062..ea0d7789cb 100644 --- a/src/applications/differential/storage/DifferentialTransaction.php +++ b/src/applications/differential/storage/DifferentialTransaction.php @@ -105,6 +105,18 @@ final class DifferentialTransaction return parent::shouldHide(); } + public function shouldHideForMail(array $xactions) { + switch ($this->getTransactionType()) { + case DifferentialRevisionReviewersTransaction::TRANSACTIONTYPE: + // Don't hide the initial "X added reviewers: ..." transaction during + // object creation from mail. See T12118 and PHI54. + return false; + } + + return parent::shouldHideForMail($xactions); + } + + public function isInlineCommentTransaction() { switch ($this->getTransactionType()) { case self::TYPE_INLINE: From 27ebd8a33b9b65db51367b562f46249b5df65f77 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Wed, 6 Sep 2017 11:02:24 -0700 Subject: [PATCH 18/54] Update Pholio Edit pages to new UI Summary: Updates the Pholio edit pages Test Plan: Create mock, Edit mock Reviewers: epriestley Reviewed By: epriestley Spies: Korvin Differential Revision: https://secure.phabricator.com/D18530 --- .../pholio/controller/PholioMockEditController.php | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/applications/pholio/controller/PholioMockEditController.php b/src/applications/pholio/controller/PholioMockEditController.php index 2d477c70aa..89d1fe2a50 100644 --- a/src/applications/pholio/controller/PholioMockEditController.php +++ b/src/applications/pholio/controller/PholioMockEditController.php @@ -23,7 +23,6 @@ final class PholioMockEditController extends PholioController { } $title = pht('Edit Mock: %s', $mock->getName()); - $header_icon = 'fa-pencil'; $is_new = false; $mock_images = $mock->getImages(); @@ -33,7 +32,6 @@ final class PholioMockEditController extends PholioController { $mock = PholioMock::initializeNewMock($viewer); $title = pht('Create Mock'); - $header_icon = 'fa-plus-square'; $is_new = true; $files = array(); @@ -347,9 +345,9 @@ final class PholioMockEditController extends PholioController { ->appendChild($submit); $form_box = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Mock')) + ->setHeaderText($title) ->setFormErrors($errors) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) + ->setBackground(PHUIObjectBoxView::WHITE_CONFIG) ->setForm($form); $crumbs = $this->buildApplicationCrumbs(); @@ -359,12 +357,7 @@ final class PholioMockEditController extends PholioController { $crumbs->addTextCrumb($title); $crumbs->setBorder(true); - $header = id(new PHUIHeaderView()) - ->setHeader($title) - ->setHeaderIcon($header_icon); - $view = id(new PHUITwoColumnView()) - ->setHeader($header) ->setFooter($form_box); return $this->newPage() From 571eb39bbc4442fc3915ad672c740af3cf35135c Mon Sep 17 00:00:00 2001 From: Chad Little Date: Wed, 6 Sep 2017 11:21:43 -0700 Subject: [PATCH 19/54] Update drydock console, edit pages to new UI Summary: Updates Drydock for the new UI Test Plan: Check console, edit pages Reviewers: epriestley, amckinley Reviewed By: epriestley Spies: Korvin, PHID-OPKG-gm6ozazyms6q6i22gyam Differential Revision: https://secure.phabricator.com/D18545 --- .../controller/DrydockBlueprintEditController.php | 7 ++++++- .../controller/DrydockConsoleController.php | 15 +++++++-------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/applications/drydock/controller/DrydockBlueprintEditController.php b/src/applications/drydock/controller/DrydockBlueprintEditController.php index f25dc01bff..8f066c708b 100644 --- a/src/applications/drydock/controller/DrydockBlueprintEditController.php +++ b/src/applications/drydock/controller/DrydockBlueprintEditController.php @@ -74,6 +74,7 @@ final class DrydockBlueprintEditController extends DrydockBlueprintController { $title = pht('Create New Blueprint'); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb(pht('New Blueprint')); + $crumbs->setBorder(true); $form = id(new AphrontFormView()) ->setUser($viewer) @@ -86,12 +87,16 @@ final class DrydockBlueprintEditController extends DrydockBlueprintController { $box = id(new PHUIObjectBoxView()) ->setFormErrors($errors) ->setHeaderText($title) + ->setBackground(PHUIObjectBoxView::WHITE_CONFIG) ->setForm($form); + $view = id(new PHUITwoColumnView()) + ->setFooter($box); + return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) - ->appendChild($box); + ->appendChild($view); } } diff --git a/src/applications/drydock/controller/DrydockConsoleController.php b/src/applications/drydock/controller/DrydockConsoleController.php index ac524cb8a5..54adcf5ca5 100644 --- a/src/applications/drydock/controller/DrydockConsoleController.php +++ b/src/applications/drydock/controller/DrydockConsoleController.php @@ -26,7 +26,8 @@ final class DrydockConsoleController extends DrydockController { $viewer = $request->getViewer(); $menu = id(new PHUIObjectItemListView()) - ->setUser($viewer); + ->setUser($viewer) + ->setBig(true); $menu->addItem( id(new PHUIObjectItemView()) @@ -64,17 +65,15 @@ final class DrydockConsoleController extends DrydockController { $crumbs->addTextCrumb(pht('Console')); $crumbs->setBorder(true); - $box = id(new PHUIObjectBoxView()) - ->setObjectList($menu); - $title = pht('Drydock Console'); - $header = id(new PHUIHeaderView()) - ->setHeader($title) - ->setHeaderIcon('fa-truck'); + $box = id(new PHUIObjectBoxView()) + ->setHeaderText($title) + ->setBackground(PHUIObjectBoxView::WHITE_CONFIG) + ->setObjectList($menu); $view = id(new PHUITwoColumnView()) - ->setHeader($header) + ->setFixed(true) ->setFooter($box); return $this->newPage() From faca1deea5b5a21aa936032114e7e1b1ba471884 Mon Sep 17 00:00:00 2001 From: epriestley Date: Wed, 6 Sep 2017 10:49:31 -0700 Subject: [PATCH 20/54] Remove the fulltext "reconstructDocument()" method Summary: Ref T12819. This was originally intended for debugging, but never actually used and not clearly useful. There are no callers and it probably does not work. Just get rid of it. Test Plan: Grepped for callers; none exist. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12819 Differential Revision: https://secure.phabricator.com/D18544 --- ...habricatorElasticFulltextStorageEngine.php | 36 ---------- .../PhabricatorFulltextStorageEngine.php | 9 --- .../PhabricatorMySQLFulltextStorageEngine.php | 67 ------------------- 3 files changed, 112 deletions(-) diff --git a/src/applications/search/fulltextstorage/PhabricatorElasticFulltextStorageEngine.php b/src/applications/search/fulltextstorage/PhabricatorElasticFulltextStorageEngine.php index 8c75c17e36..f6aead3759 100644 --- a/src/applications/search/fulltextstorage/PhabricatorElasticFulltextStorageEngine.php +++ b/src/applications/search/fulltextstorage/PhabricatorElasticFulltextStorageEngine.php @@ -105,42 +105,6 @@ class PhabricatorElasticFulltextStorageEngine $this->executeRequest($host, "/{$type}/{$phid}/", $spec, 'PUT'); } - public function reconstructDocument($phid) { - $type = phid_get_type($phid); - $host = $this->getHostForRead(); - $response = $this->executeRequest($host, "/{$type}/{$phid}", array()); - - if (empty($response['exists'])) { - return null; - } - - $hit = $response['_source']; - - $doc = new PhabricatorSearchAbstractDocument(); - $doc->setPHID($phid); - $doc->setDocumentType($response['_type']); - $doc->setDocumentTitle($hit['title']); - $doc->setDocumentCreated($hit['dateCreated']); - $doc->setDocumentModified($hit[$this->getTimestampField()]); - - foreach ($hit['field'] as $fdef) { - $field_type = $fdef['type']; - $doc->addField($field_type, $hit[$field_type], $fdef['aux']); - } - - foreach ($hit['relationship'] as $rtype => $rships) { - foreach ($rships as $rship) { - $doc->addRelationship( - $rtype, - $rship['phid'], - $rship['phidType'], - $rship['when']); - } - } - - return $doc; - } - private function buildSpec(PhabricatorSavedQuery $query) { $q = new PhabricatorElasticsearchQueryBuilder('bool'); $query_string = $query->getParameter('query'); diff --git a/src/applications/search/fulltextstorage/PhabricatorFulltextStorageEngine.php b/src/applications/search/fulltextstorage/PhabricatorFulltextStorageEngine.php index 588ccc3e5e..ba019ea593 100644 --- a/src/applications/search/fulltextstorage/PhabricatorFulltextStorageEngine.php +++ b/src/applications/search/fulltextstorage/PhabricatorFulltextStorageEngine.php @@ -53,15 +53,6 @@ abstract class PhabricatorFulltextStorageEngine extends Phobject { abstract public function reindexAbstractDocument( PhabricatorSearchAbstractDocument $document); - /** - * Reconstruct the document for a given PHID. This is used for debugging - * and does not need to be perfect if it is unreasonable to implement it. - * - * @param phid Document PHID to reconstruct. - * @return PhabricatorSearchAbstractDocument Abstract document. - */ - abstract public function reconstructDocument($phid); - /** * Execute a search query. * diff --git a/src/applications/search/fulltextstorage/PhabricatorMySQLFulltextStorageEngine.php b/src/applications/search/fulltextstorage/PhabricatorMySQLFulltextStorageEngine.php index fe526a8133..c2e38d2db7 100644 --- a/src/applications/search/fulltextstorage/PhabricatorMySQLFulltextStorageEngine.php +++ b/src/applications/search/fulltextstorage/PhabricatorMySQLFulltextStorageEngine.php @@ -91,73 +91,6 @@ final class PhabricatorMySQLFulltextStorageEngine } - /** - * Rebuild the PhabricatorSearchAbstractDocument that was used to index - * an object out of the index itself. This is primarily useful for debugging, - * as it allows you to inspect the search index representation of a - * document. - * - * @param phid PHID of a document which exists in the search index. - * @return null|PhabricatorSearchAbstractDocument Abstract document object - * which corresponds to the original abstract document used to - * build the document index. - */ - public function reconstructDocument($phid) { - $dao_doc = new PhabricatorSearchDocument(); - $dao_field = new PhabricatorSearchDocumentField(); - $dao_relationship = new PhabricatorSearchDocumentRelationship(); - - $t_doc = $dao_doc->getTableName(); - $t_field = $dao_field->getTableName(); - $t_relationship = $dao_relationship->getTableName(); - - $doc = queryfx_one( - $dao_doc->establishConnection('r'), - 'SELECT * FROM %T WHERE phid = %s', - $t_doc, - $phid); - - if (!$doc) { - return null; - } - - $fields = queryfx_all( - $dao_field->establishConnection('r'), - 'SELECT * FROM %T WHERE phid = %s', - $t_field, - $phid); - - $relationships = queryfx_all( - $dao_relationship->establishConnection('r'), - 'SELECT * FROM %T WHERE phid = %s', - $t_relationship, - $phid); - - $adoc = id(new PhabricatorSearchAbstractDocument()) - ->setPHID($phid) - ->setDocumentType($doc['documentType']) - ->setDocumentTitle($doc['documentTitle']) - ->setDocumentCreated($doc['documentCreated']) - ->setDocumentModified($doc['documentModified']); - - foreach ($fields as $field) { - $adoc->addField( - $field['field'], - $field['corpus'], - $field['auxPHID']); - } - - foreach ($relationships as $relationship) { - $adoc->addRelationship( - $relationship['relation'], - $relationship['relatedPHID'], - $relationship['relatedType'], - $relationship['relatedTime']); - } - - return $adoc; - } - public function executeSearch(PhabricatorSavedQuery $query) { $table = new PhabricatorSearchDocument(); $document_table = $table->getTableName(); From 2abbb59cb4c1be22857126f769489310d5428c77 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Wed, 6 Sep 2017 11:31:07 -0700 Subject: [PATCH 21/54] Update Phriction Edit page to new UI Summary: Updates document edit page Test Plan: review Reviewers: epriestley, amckinley Reviewed By: epriestley Spies: Korvin Differential Revision: https://secure.phabricator.com/D18546 --- .../controller/PhrictionEditController.php | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/src/applications/phriction/controller/PhrictionEditController.php b/src/applications/phriction/controller/PhrictionEditController.php index 17d11fdf3c..0ac3fc35bb 100644 --- a/src/applications/phriction/controller/PhrictionEditController.php +++ b/src/applications/phriction/controller/PhrictionEditController.php @@ -195,19 +195,15 @@ final class PhrictionEditController } if ($document->getID()) { - $panel_header = pht('Edit Document: %s', $content->getTitle()); - $page_title = pht('Edit Document'); - $header_icon = 'fa-pencil'; + $page_title = pht('Edit Document: %s', $content->getTitle()); if ($overwrite) { $submit_button = pht('Overwrite Changes'); } else { $submit_button = pht('Save Changes'); } } else { - $panel_header = pht('Create New Phriction Document'); $submit_button = pht('Create Document'); $page_title = pht('Create Document'); - $header_icon = 'fa-plus-square'; } $uri = $document->getSlug(); @@ -289,9 +285,9 @@ final class PhrictionEditController ->setValue($submit_button)); $form_box = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Document')) + ->setHeaderText($page_title) ->setValidationException($validation_exception) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) + ->setBackground(PHUIObjectBoxView::WHITE_CONFIG) ->setForm($form); $preview = id(new PHUIRemarkupPreviewPanel()) @@ -311,12 +307,7 @@ final class PhrictionEditController } $crumbs->setBorder(true); - $header = id(new PHUIHeaderView()) - ->setHeader($panel_header) - ->setHeaderIcon($header_icon); - $view = id(new PHUITwoColumnView()) - ->setHeader($header) ->setFooter(array( $draft_note, $form_box, From 395a2ed6d127559685158433fd0b7fab88e8a398 Mon Sep 17 00:00:00 2001 From: epriestley Date: Wed, 6 Sep 2017 10:02:13 -0700 Subject: [PATCH 22/54] Add an "only()" edge logic constraint, meaning "only the other constraints, exactly" Summary: See PHI57. For example, a query for "ios, only()" finds tags tasked with iOS, exactly, and no other tags. I called this "only()" instead of "exact()" because we use the term/function "Exact" elsewhere with a different meaning, e.g. in Differential. Test Plan: Basic query for a tag: {F5168857} Same query with "only", finds tasks tagged with only that tag: {F5168858} Reviewers: chad Reviewed By: chad Differential Revision: https://secure.phabricator.com/D18543 --- src/__phutil_library_map__.php | 2 + .../PhabricatorProjectLogicalDatasource.php | 1 + ...habricatorProjectLogicalOnlyDatasource.php | 76 +++++++++++++++++++ ...bricatorProjectLogicalViewerDatasource.php | 2 +- .../constraint/PhabricatorQueryConstraint.php | 1 + ...PhabricatorCursorPagedPolicyAwareQuery.php | 65 ++++++++++++++++ 6 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 src/applications/project/typeahead/PhabricatorProjectLogicalOnlyDatasource.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index e9244fd7ca..b413985624 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -3686,6 +3686,7 @@ phutil_register_library_map(array( 'PhabricatorProjectLockTransaction' => 'applications/project/xaction/PhabricatorProjectLockTransaction.php', 'PhabricatorProjectLogicalAncestorDatasource' => 'applications/project/typeahead/PhabricatorProjectLogicalAncestorDatasource.php', 'PhabricatorProjectLogicalDatasource' => 'applications/project/typeahead/PhabricatorProjectLogicalDatasource.php', + 'PhabricatorProjectLogicalOnlyDatasource' => 'applications/project/typeahead/PhabricatorProjectLogicalOnlyDatasource.php', 'PhabricatorProjectLogicalOrNotDatasource' => 'applications/project/typeahead/PhabricatorProjectLogicalOrNotDatasource.php', 'PhabricatorProjectLogicalUserDatasource' => 'applications/project/typeahead/PhabricatorProjectLogicalUserDatasource.php', 'PhabricatorProjectLogicalViewerDatasource' => 'applications/project/typeahead/PhabricatorProjectLogicalViewerDatasource.php', @@ -9179,6 +9180,7 @@ phutil_register_library_map(array( 'PhabricatorProjectLockTransaction' => 'PhabricatorProjectTransactionType', 'PhabricatorProjectLogicalAncestorDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'PhabricatorProjectLogicalDatasource' => 'PhabricatorTypeaheadCompositeDatasource', + 'PhabricatorProjectLogicalOnlyDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorProjectLogicalOrNotDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'PhabricatorProjectLogicalUserDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'PhabricatorProjectLogicalViewerDatasource' => 'PhabricatorTypeaheadDatasource', diff --git a/src/applications/project/typeahead/PhabricatorProjectLogicalDatasource.php b/src/applications/project/typeahead/PhabricatorProjectLogicalDatasource.php index b724e9f8ca..b7003cb69e 100644 --- a/src/applications/project/typeahead/PhabricatorProjectLogicalDatasource.php +++ b/src/applications/project/typeahead/PhabricatorProjectLogicalDatasource.php @@ -21,6 +21,7 @@ final class PhabricatorProjectLogicalDatasource new PhabricatorProjectLogicalAncestorDatasource(), new PhabricatorProjectLogicalOrNotDatasource(), new PhabricatorProjectLogicalViewerDatasource(), + new PhabricatorProjectLogicalOnlyDatasource(), new PhabricatorProjectLogicalUserDatasource(), ); } diff --git a/src/applications/project/typeahead/PhabricatorProjectLogicalOnlyDatasource.php b/src/applications/project/typeahead/PhabricatorProjectLogicalOnlyDatasource.php new file mode 100644 index 0000000000..fe521fc6d8 --- /dev/null +++ b/src/applications/project/typeahead/PhabricatorProjectLogicalOnlyDatasource.php @@ -0,0 +1,76 @@ + array( + 'name' => pht('Only Match Other Constraints'), + 'summary' => pht( + 'Find results with only the specified tags.'), + 'description' => pht( + "This function is used with other tags, and causes the query to ". + "match only results with exactly those tags. For example, to find ". + "tasks tagged only iOS:". + "\n\n". + "> ios, only()". + "\n\n". + "This will omit results with any other project tag."), + ), + ); + } + + public function loadResults() { + $results = array( + $this->renderOnlyFunctionToken(), + ); + return $this->filterResultsAgainstTokens($results); + } + + protected function evaluateFunction($function, array $argv_list) { + $results = array(); + + $results[] = new PhabricatorQueryConstraint( + PhabricatorQueryConstraint::OPERATOR_ONLY, + null); + + return $results; + } + + public function renderFunctionTokens( + $function, + array $argv_list) { + + $tokens = array(); + foreach ($argv_list as $argv) { + $tokens[] = PhabricatorTypeaheadTokenView::newFromTypeaheadResult( + $this->renderOnlyFunctionToken()); + } + + return $tokens; + } + + private function renderOnlyFunctionToken() { + return $this->newFunctionResult() + ->setName(pht('Only')) + ->setPHID('only()') + ->setIcon('fa-asterisk') + ->setUnique(true) + ->addAttribute( + pht('Select only results with exactly the other specified tags.')); + } + +} diff --git a/src/applications/project/typeahead/PhabricatorProjectLogicalViewerDatasource.php b/src/applications/project/typeahead/PhabricatorProjectLogicalViewerDatasource.php index 9bb15ed180..807986457a 100644 --- a/src/applications/project/typeahead/PhabricatorProjectLogicalViewerDatasource.php +++ b/src/applications/project/typeahead/PhabricatorProjectLogicalViewerDatasource.php @@ -29,7 +29,7 @@ final class PhabricatorProjectLogicalViewerDatasource "\n\n". "This normally means //your// projects, but if you save a query ". "using this function and send it to someone else, it will mean ". - "//their// projects when they run it (they become the currnet ". + "//their// projects when they run it (they become the current ". "viewer). This can be useful for building dashboard panels."), ), ); diff --git a/src/infrastructure/query/constraint/PhabricatorQueryConstraint.php b/src/infrastructure/query/constraint/PhabricatorQueryConstraint.php index 74b3830676..54cd7ae51f 100644 --- a/src/infrastructure/query/constraint/PhabricatorQueryConstraint.php +++ b/src/infrastructure/query/constraint/PhabricatorQueryConstraint.php @@ -8,6 +8,7 @@ final class PhabricatorQueryConstraint extends Phobject { const OPERATOR_NULL = 'null'; const OPERATOR_ANCESTOR = 'ancestor'; const OPERATOR_EMPTY = 'empty'; + const OPERATOR_ONLY = 'only'; private $operator; private $value; diff --git a/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php b/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php index 04fafa7cd2..1411095f36 100644 --- a/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php +++ b/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php @@ -2069,6 +2069,27 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery $op_null = PhabricatorQueryConstraint::OPERATOR_NULL; $has_null = isset($constraints[$op_null]); + // If we're going to process an only() operator, build a list of the + // acceptable set of PHIDs first. We'll only match results which have + // no edges to any other PHIDs. + $all_phids = array(); + if (isset($constraints[PhabricatorQueryConstraint::OPERATOR_ONLY])) { + foreach ($constraints as $operator => $list) { + switch ($operator) { + case PhabricatorQueryConstraint::OPERATOR_ANCESTOR: + case PhabricatorQueryConstraint::OPERATOR_AND: + case PhabricatorQueryConstraint::OPERATOR_OR: + foreach ($list as $constraint) { + $value = (array)$constraint->getValue(); + foreach ($value as $v) { + $all_phids[$v] = $v; + } + } + break; + } + } + } + foreach ($constraints as $operator => $list) { $alias = $this->getEdgeLogicTableAlias($operator, $type); @@ -2133,6 +2154,20 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery $alias, $type); break; + case PhabricatorQueryConstraint::OPERATOR_ONLY: + $joins[] = qsprintf( + $conn, + 'LEFT JOIN %T %T ON %Q = %T.src AND %T.type = %d + AND %T.dst NOT IN (%Ls)', + $edge_table, + $alias, + $phid_column, + $alias, + $alias, + $type, + $alias, + $all_phids); + break; } } } @@ -2159,6 +2194,7 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery $alias = $this->getEdgeLogicTableAlias($operator, $type); switch ($operator) { case PhabricatorQueryConstraint::OPERATOR_NOT: + case PhabricatorQueryConstraint::OPERATOR_ONLY: $full[] = qsprintf( $conn, '%T.dst IS NULL', @@ -2258,6 +2294,7 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery // discussion, see T12753. return true; case PhabricatorQueryConstraint::OPERATOR_NULL: + case PhabricatorQueryConstraint::OPERATOR_ONLY: return true; } } @@ -2375,6 +2412,34 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery } } + $op_and = PhabricatorQueryConstraint::OPERATOR_AND; + $op_or = PhabricatorQueryConstraint::OPERATOR_OR; + $op_ancestor = PhabricatorQueryConstraint::OPERATOR_ANCESTOR; + + foreach ($this->edgeLogicConstraints as $type => $constraints) { + foreach ($constraints as $operator => $list) { + switch ($operator) { + case PhabricatorQueryConstraint::OPERATOR_ONLY: + if (count($list) > 1) { + throw new PhabricatorEmptyQueryException( + pht( + 'This query specifies only() more than once.')); + } + + $have_and = idx($constraints, $op_and); + $have_or = idx($constraints, $op_or); + $have_ancestor = idx($constraints, $op_ancestor); + if (!$have_and && !$have_or && !$have_ancestor) { + throw new PhabricatorEmptyQueryException( + pht( + 'This query specifies only(), but no other constraints '. + 'which it can apply to.')); + } + break; + } + } + } + $this->edgeLogicConstraintsAreValid = true; return $this; From 551c62b91af51f79faa431579fb13e5a3841b876 Mon Sep 17 00:00:00 2001 From: epriestley Date: Wed, 6 Sep 2017 12:13:50 -0700 Subject: [PATCH 23/54] Support Ferret engine queries in ApplicationSearch via extension instead of hard-code Summary: Ref T12819. Uses an extension rather than hard-coding support into Maniphest. Test Plan: Saw "Query" field appear in Differential, which also implements the interface and has support. Used field in both applications. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12819 Differential Revision: https://secure.phabricator.com/D18547 --- src/__phutil_library_map__.php | 2 + .../query/ManiphestTaskSearchEngine.php | 28 -------- ...PhabricatorFerretSearchEngineExtension.php | 70 +++++++++++++++++++ 3 files changed, 72 insertions(+), 28 deletions(-) create mode 100644 src/applications/search/engineextension/PhabricatorFerretSearchEngineExtension.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index b413985624..b9c2dedf1d 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -2840,6 +2840,7 @@ phutil_register_library_map(array( 'PhabricatorFerretFulltextEngineExtension' => 'applications/search/engineextension/PhabricatorFerretFulltextEngineExtension.php', 'PhabricatorFerretInterface' => 'applications/search/ferret/PhabricatorFerretInterface.php', 'PhabricatorFerretNgrams' => 'applications/search/ferret/PhabricatorFerretNgrams.php', + 'PhabricatorFerretSearchEngineExtension' => 'applications/search/engineextension/PhabricatorFerretSearchEngineExtension.php', 'PhabricatorFile' => 'applications/files/storage/PhabricatorFile.php', 'PhabricatorFileAES256StorageFormat' => 'applications/files/format/PhabricatorFileAES256StorageFormat.php', 'PhabricatorFileBundleLoader' => 'applications/files/query/PhabricatorFileBundleLoader.php', @@ -8173,6 +8174,7 @@ phutil_register_library_map(array( 'PhabricatorFerretField' => 'PhabricatorSearchDAO', 'PhabricatorFerretFulltextEngineExtension' => 'PhabricatorFulltextEngineExtension', 'PhabricatorFerretNgrams' => 'PhabricatorSearchDAO', + 'PhabricatorFerretSearchEngineExtension' => 'PhabricatorSearchEngineExtension', 'PhabricatorFile' => array( 'PhabricatorFileDAO', 'PhabricatorApplicationTransactionInterface', diff --git a/src/applications/maniphest/query/ManiphestTaskSearchEngine.php b/src/applications/maniphest/query/ManiphestTaskSearchEngine.php index 0e3e0db69f..150ec81def 100644 --- a/src/applications/maniphest/query/ManiphestTaskSearchEngine.php +++ b/src/applications/maniphest/query/ManiphestTaskSearchEngine.php @@ -49,8 +49,6 @@ final class ManiphestTaskSearchEngine $subtype_map = id(new ManiphestTask())->newEditEngineSubtypeMap(); $hide_subtypes = (count($subtype_map) == 1); - $hide_ferret = !PhabricatorEnv::getEnvConfig('phabricator.show-prototypes'); - return array( id(new PhabricatorOwnersSearchField()) ->setLabel(pht('Assigned To')) @@ -91,10 +89,6 @@ final class ManiphestTaskSearchEngine id(new PhabricatorSearchTextField()) ->setLabel(pht('Contains Words')) ->setKey('fulltext'), - id(new PhabricatorSearchTextField()) - ->setLabel(pht('Query (Prototype)')) - ->setKey('query') - ->setIsHidden($hide_ferret), id(new PhabricatorSearchThreeStateField()) ->setLabel(pht('Open Parents')) ->setKey('hasParents') @@ -150,7 +144,6 @@ final class ManiphestTaskSearchEngine 'statuses', 'priorities', 'subtypes', - 'query', 'fulltext', 'hasParents', 'hasSubtasks', @@ -231,27 +224,6 @@ final class ManiphestTaskSearchEngine $query->withFullTextSearch($map['fulltext']); } - if (strlen($map['query'])) { - $raw_query = $map['query']; - - $compiler = id(new PhutilSearchQueryCompiler()) - ->setEnableFunctions(true); - - $raw_tokens = $compiler->newTokens($raw_query); - - $fulltext_tokens = array(); - foreach ($raw_tokens as $raw_token) { - $fulltext_token = id(new PhabricatorFulltextToken()) - ->setToken($raw_token); - - $fulltext_tokens[] = $fulltext_token; - } - - $query->withFerretConstraint( - id(new ManiphestTask())->newFerretEngine(), - $fulltext_tokens); - } - if ($map['parentIDs']) { $query->withParentTaskIDs($map['parentIDs']); } diff --git a/src/applications/search/engineextension/PhabricatorFerretSearchEngineExtension.php b/src/applications/search/engineextension/PhabricatorFerretSearchEngineExtension.php new file mode 100644 index 0000000000..02aadf7336 --- /dev/null +++ b/src/applications/search/engineextension/PhabricatorFerretSearchEngineExtension.php @@ -0,0 +1,70 @@ +newFerretEngine(); + + $raw_query = $map['query']; + + $compiler = id(new PhutilSearchQueryCompiler()) + ->setEnableFunctions(true); + + $raw_tokens = $compiler->newTokens($raw_query); + + $fulltext_tokens = array(); + foreach ($raw_tokens as $raw_token) { + $fulltext_token = id(new PhabricatorFulltextToken()) + ->setToken($raw_token); + + $fulltext_tokens[] = $fulltext_token; + } + + $query->withFerretConstraint($engine, $fulltext_tokens); + } + + public function getSearchFields($object) { + $fields = array(); + + $fields[] = id(new PhabricatorSearchTextField()) + ->setKey('query') + ->setLabel(pht('Query (Prototype)')) + ->setDescription(pht('Fulltext search.')); + + return $fields; + } + + public function getSearchAttachments($object) { + return array(); + } + + +} From 4ea677ba979d5117b7a73e427190c1b38f9931e3 Mon Sep 17 00:00:00 2001 From: epriestley Date: Wed, 6 Sep 2017 11:48:21 -0700 Subject: [PATCH 24/54] Skeleton support for running global fulltext queries via the Ferret engine Summary: Ref T12819. Provides a Ferret-engine-based fulltext engine to ultimately replace the InnoDB fulltext engine. This is still pretty basic (hard-coded and buggy) but technically sort of works. To activate this, you must explicitly configure it, so it isn't visible to users yet. Test Plan: Searched for objects with global fulltext search, got a mixture of matching revisions and tasks back. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12819 Differential Revision: https://secure.phabricator.com/D18548 --- src/__phutil_library_map__.php | 2 + .../query/DifferentialRevisionQuery.php | 2 +- .../DifferentialRevisionFerretEngine.php | 4 + .../search/ManiphestTaskFerretEngine.php | 4 + .../search/ferret/PhabricatorFerretEngine.php | 55 +++++++++++ ...PhabricatorFerretFulltextStorageEngine.php | 96 +++++++++++++++++++ 6 files changed, 162 insertions(+), 1 deletion(-) create mode 100644 src/applications/search/fulltextstorage/PhabricatorFerretFulltextStorageEngine.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index b9c2dedf1d..e81239f9c0 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -2838,6 +2838,7 @@ phutil_register_library_map(array( 'PhabricatorFerretEngineTestCase' => 'applications/search/ferret/__tests__/PhabricatorFerretEngineTestCase.php', 'PhabricatorFerretField' => 'applications/search/ferret/PhabricatorFerretField.php', 'PhabricatorFerretFulltextEngineExtension' => 'applications/search/engineextension/PhabricatorFerretFulltextEngineExtension.php', + 'PhabricatorFerretFulltextStorageEngine' => 'applications/search/fulltextstorage/PhabricatorFerretFulltextStorageEngine.php', 'PhabricatorFerretInterface' => 'applications/search/ferret/PhabricatorFerretInterface.php', 'PhabricatorFerretNgrams' => 'applications/search/ferret/PhabricatorFerretNgrams.php', 'PhabricatorFerretSearchEngineExtension' => 'applications/search/engineextension/PhabricatorFerretSearchEngineExtension.php', @@ -8173,6 +8174,7 @@ phutil_register_library_map(array( 'PhabricatorFerretEngineTestCase' => 'PhabricatorTestCase', 'PhabricatorFerretField' => 'PhabricatorSearchDAO', 'PhabricatorFerretFulltextEngineExtension' => 'PhabricatorFulltextEngineExtension', + 'PhabricatorFerretFulltextStorageEngine' => 'PhabricatorFulltextStorageEngine', 'PhabricatorFerretNgrams' => 'PhabricatorSearchDAO', 'PhabricatorFerretSearchEngineExtension' => 'PhabricatorSearchEngineExtension', 'PhabricatorFile' => array( diff --git a/src/applications/differential/query/DifferentialRevisionQuery.php b/src/applications/differential/query/DifferentialRevisionQuery.php index 8e6e23776a..622eba564a 100644 --- a/src/applications/differential/query/DifferentialRevisionQuery.php +++ b/src/applications/differential/query/DifferentialRevisionQuery.php @@ -772,7 +772,7 @@ final class DifferentialRevisionQuery 'column' => 'dateModified', 'type' => 'int', ), - ); + ) + parent::getOrderableColumns(); } protected function getPagingValueMap($cursor, array $keys) { diff --git a/src/applications/differential/search/DifferentialRevisionFerretEngine.php b/src/applications/differential/search/DifferentialRevisionFerretEngine.php index 0581cf281d..b51a486ef5 100644 --- a/src/applications/differential/search/DifferentialRevisionFerretEngine.php +++ b/src/applications/differential/search/DifferentialRevisionFerretEngine.php @@ -15,6 +15,10 @@ final class DifferentialRevisionFerretEngine return new DifferentialRevisionFerretField(); } + protected function newSearchEngine() { + return new DifferentialRevisionSearchEngine(); + } + protected function getFunctionMap() { $map = parent::getFunctionMap(); diff --git a/src/applications/maniphest/search/ManiphestTaskFerretEngine.php b/src/applications/maniphest/search/ManiphestTaskFerretEngine.php index 8aa503fbf8..2eab7db74c 100644 --- a/src/applications/maniphest/search/ManiphestTaskFerretEngine.php +++ b/src/applications/maniphest/search/ManiphestTaskFerretEngine.php @@ -15,6 +15,10 @@ final class ManiphestTaskFerretEngine return new ManiphestTaskFerretField(); } + protected function newSearchEngine() { + return new ManiphestTaskSearchEngine(); + } + protected function getFunctionMap() { $map = parent::getFunctionMap(); diff --git a/src/applications/search/ferret/PhabricatorFerretEngine.php b/src/applications/search/ferret/PhabricatorFerretEngine.php index 1de336e70b..7e30189fb8 100644 --- a/src/applications/search/ferret/PhabricatorFerretEngine.php +++ b/src/applications/search/ferret/PhabricatorFerretEngine.php @@ -5,6 +5,7 @@ abstract class PhabricatorFerretEngine extends Phobject { abstract public function newNgramsObject(); abstract public function newDocumentObject(); abstract public function newFieldObject(); + abstract protected function newSearchEngine(); public function getDefaultFunctionKey() { return 'all'; @@ -69,6 +70,60 @@ abstract class PhabricatorFerretEngine extends Phobject { return new PhutilSearchStemmer(); } + public function newConfiguredFulltextQuery( + $object, + PhabricatorSavedQuery $query, + PhabricatorUser $viewer) { + + $local_query = new PhabricatorSavedQuery(); + $local_query->setParameter('query', $query->getParameter('query')); + + // TODO: Modularize this piece. + $project_phids = $query->getParameter('projectPHIDs'); + if ($project_phids) { + $local_query->setParameter('projectPHIDs', $project_phids); + } + + $subscriber_phids = $query->getParameter('subscriberPHIDs'); + if ($subscriber_phids) { + $local_query->setParameter('subscriberPHIDs', $subscriber_phids); + } + + $author_phids = $query->getParameter('authorPHIDs'); + if ($author_phids) { + $local_query->setParameter('authorPHIDs', $author_phids); + } + + $owner_phids = $query->getParameter('ownerPHIDs'); + if ($owner_phids) { + $local_query->setParameter('ownerPHIDs', $owner_phids); + } + + $rel_open = PhabricatorSearchRelationship::RELATIONSHIP_OPEN; + $rel_closed = PhabricatorSearchRelationship::RELATIONSHIP_CLOSED; + + $statuses = $query->getParameter('statuses'); + if ($statuses) { + $statuses = array_fuse($statuses); + if (count($statuses) == 1) { + if (isset($statuses[$rel_open])) { + $local_query->setParameter('statuses', array('open()')); + } + if (isset($statuses[$rel_closed])) { + $local_query->setParameter('statuses', array('closed()')); + } + } + } + + $search_engine = $this->newSearchEngine() + ->setViewer($viewer); + + $engine_query = $search_engine->buildQueryFromSavedQuery($local_query) + ->setViewer($viewer); + + return $engine_query; + } + public function tokenizeString($value) { $value = trim($value, ' '); $value = preg_split('/ +/', $value); diff --git a/src/applications/search/fulltextstorage/PhabricatorFerretFulltextStorageEngine.php b/src/applications/search/fulltextstorage/PhabricatorFerretFulltextStorageEngine.php new file mode 100644 index 0000000000..0036ca928b --- /dev/null +++ b/src/applications/search/fulltextstorage/PhabricatorFerretFulltextStorageEngine.php @@ -0,0 +1,96 @@ +setAncestorClass('PhabricatorFerretInterface') + ->execute(); + + $type_map = array(); + foreach ($all_objects as $object) { + $phid_type = phid_get_type($object->generatePHID()); + + $type_map[$phid_type] = array( + 'object' => $object, + 'engine' => $object->newFerretEngine(), + ); + } + + $types = $query->getParameter('types'); + if ($types) { + $type_map = array_select_keys($type_map, $types); + } + + $offset = (int)$query->getParameter('offset', 0); + $limit = (int)$query->getParameter('limit', 25); + + $viewer = PhabricatorUser::getOmnipotentUser(); + + $type_results = array(); + foreach ($type_map as $type => $spec) { + $engine = $spec['engine']; + $object = $spec['object']; + + // NOTE: For now, it's okay to query with the omnipotent viewer here + // because we're just returning PHIDs which we'll filter later. + + $type_query = $engine->newConfiguredFulltextQuery( + $object, + $query, + $viewer); + + $type_query + ->setOrder('relevance') + ->setLimit($offset + $limit); + + $results = $type_query->execute(); + $results = mpull($results, null, 'getPHID'); + $type_results[$type] = $results; + } + + $list = array(); + foreach ($type_results as $type => $results) { + $list += $results; + } + + $result_slice = array_slice($list, $offset, $limit, true); + return array_keys($result_slice); + } + + public function indexExists() { + return true; + } + + public function getIndexStats() { + return false; + } + + public function getFulltextTokens() { + return $this->fulltextTokens; + } + + +} From 3b2accee7c69bcbd6856b1e71e76e7d0fe034dfc Mon Sep 17 00:00:00 2001 From: Chad Little Date: Wed, 6 Sep 2017 20:44:37 +0000 Subject: [PATCH 25/54] Add a border on diffusion uri page Summary: This should have a border Test Plan: Reload page Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D18549 --- .../controller/DiffusionRepositoryURIViewController.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/applications/diffusion/controller/DiffusionRepositoryURIViewController.php b/src/applications/diffusion/controller/DiffusionRepositoryURIViewController.php index 308df8f0d2..91ffbb473f 100644 --- a/src/applications/diffusion/controller/DiffusionRepositoryURIViewController.php +++ b/src/applications/diffusion/controller/DiffusionRepositoryURIViewController.php @@ -45,6 +45,7 @@ final class DiffusionRepositoryURIViewController ); $crumbs = $this->buildApplicationCrumbs(); + $crumbs->setBorder(true); $crumbs->addTextCrumb( $repository->getDisplayName(), $repository->getURI()); From 97f0103a80fe7a0190f2104e07be18007834f1e0 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Thu, 7 Sep 2017 11:17:58 -0700 Subject: [PATCH 26/54] Update Spaces for new edit UI Summary: New edit ui Test Plan: create a space Reviewers: epriestley Reviewed By: epriestley Spies: Korvin Differential Revision: https://secure.phabricator.com/D18558 --- .../controller/PhabricatorSpacesEditController.php | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/applications/spaces/controller/PhabricatorSpacesEditController.php b/src/applications/spaces/controller/PhabricatorSpacesEditController.php index faca39d634..cf3b6578b6 100644 --- a/src/applications/spaces/controller/PhabricatorSpacesEditController.php +++ b/src/applications/spaces/controller/PhabricatorSpacesEditController.php @@ -165,8 +165,8 @@ final class PhabricatorSpacesEditController ->addCancelButton($cancel_uri)); $box = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Space')) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) + ->setHeaderText($title) + ->setBackground(PHUIObjectBoxView::WHITE_CONFIG) ->setValidationException($validation_exception) ->appendChild($form); @@ -179,12 +179,7 @@ final class PhabricatorSpacesEditController $crumbs->addTextCrumb($title); $crumbs->setBorder(true); - $header = id(new PHUIHeaderView()) - ->setHeader($header_text) - ->setHeaderIcon('fa-pencil'); - $view = id(new PHUITwoColumnView()) - ->setHeader($header) ->setFooter(array( $box, )); From d3db3fff59de592768030171959b5439e6f69afa Mon Sep 17 00:00:00 2001 From: Chad Little Date: Thu, 7 Sep 2017 11:12:45 -0700 Subject: [PATCH 27/54] Update file edit UI Summary: New white box Test Plan: /file/upload/ Reviewers: epriestley Reviewed By: epriestley Spies: Korvin Differential Revision: https://secure.phabricator.com/D18557 --- .../files/controller/PhabricatorFileUploadController.php | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/applications/files/controller/PhabricatorFileUploadController.php b/src/applications/files/controller/PhabricatorFileUploadController.php index 3be0ca3968..c06e0e6d89 100644 --- a/src/applications/files/controller/PhabricatorFileUploadController.php +++ b/src/applications/files/controller/PhabricatorFileUploadController.php @@ -90,17 +90,12 @@ final class PhabricatorFileUploadController extends PhabricatorFileController { ->setShowIfSupportedID($support_id); $form_box = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('File')) + ->setHeaderText($title) ->setFormErrors($errors) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) + ->setBackground(PHUIObjectBoxView::WHITE_CONFIG) ->setForm($form); - $header = id(new PHUIHeaderView()) - ->setHeader($title) - ->setHeaderIcon('fa-upload'); - $view = id(new PHUITwoColumnView()) - ->setHeader($header) ->setFooter(array( $form_box, $global_upload, From a5232e015afa6fe65086563806288d0df9f2bcb7 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Thu, 7 Sep 2017 12:01:44 -0700 Subject: [PATCH 28/54] Update herald edit for new UI Summary: Updates herald update, create Test Plan: Create some rulez Reviewers: epriestley Reviewed By: epriestley Spies: Korvin Differential Revision: https://secure.phabricator.com/D18563 --- .../herald/controller/HeraldNewController.php | 8 ++------ .../herald/controller/HeraldRuleController.php | 7 ++----- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/src/applications/herald/controller/HeraldNewController.php b/src/applications/herald/controller/HeraldNewController.php index e9fa1e66bd..fbaf1aeb9e 100644 --- a/src/applications/herald/controller/HeraldNewController.php +++ b/src/applications/herald/controller/HeraldNewController.php @@ -194,8 +194,9 @@ final class HeraldNewController extends HeraldController { ->addCancelButton($cancel_uri, $cancel_text)); $form_box = id(new PHUIObjectBoxView()) + ->setHeaderText($title) ->setFormErrors($errors) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) + ->setBackground(PHUIObjectBoxView::WHITE_CONFIG) ->setForm($form); $crumbs = $this @@ -203,12 +204,7 @@ final class HeraldNewController extends HeraldController { ->addTextCrumb(pht('Create Rule')) ->setBorder(true); - $header = id(new PHUIHeaderView()) - ->setHeader($title) - ->setHeaderIcon('fa-plus-square'); - $view = id(new PHUITwoColumnView()) - ->setHeader($header) ->setFooter($form_box); return $this->newPage() diff --git a/src/applications/herald/controller/HeraldRuleController.php b/src/applications/herald/controller/HeraldRuleController.php index 0e7f6b0aa5..d338f6a57e 100644 --- a/src/applications/herald/controller/HeraldRuleController.php +++ b/src/applications/herald/controller/HeraldRuleController.php @@ -241,6 +241,8 @@ final class HeraldRuleController extends HeraldController { $icon = $rule->getID() ? 'fa-pencil' : 'fa-plus-square'; $form_box = id(new PHUIObjectBoxView()) + ->setHeaderText($title) + ->setBackground(PHUIObjectBoxView::WHITE_CONFIG) ->setFormErrors($errors) ->setForm($form); @@ -249,12 +251,7 @@ final class HeraldRuleController extends HeraldController { ->addTextCrumb($title) ->setBorder(true); - $header = id(new PHUIHeaderView()) - ->setHeader($title) - ->setHeaderIcon('fa-plus-square'); - $view = id(new PHUITwoColumnView()) - ->setHeader($header) ->setFooter($form_box); return $this->newPage() From d6bb0d1bfa83a9a25d01dec717f149ecdd8370bb Mon Sep 17 00:00:00 2001 From: Chad Little Date: Thu, 7 Sep 2017 11:49:10 -0700 Subject: [PATCH 29/54] Update people edit pages UI Summary: Updates and clarifies UI Test Plan: New peoples, new bots, new mailing list Reviewers: epriestley Reviewed By: epriestley Spies: Korvin Differential Revision: https://secure.phabricator.com/D18562 --- .../PhabricatorPeopleCreateController.php | 9 ++------- .../controller/PhabricatorPeopleNewController.php | 15 +++++---------- 2 files changed, 7 insertions(+), 17 deletions(-) diff --git a/src/applications/people/controller/PhabricatorPeopleCreateController.php b/src/applications/people/controller/PhabricatorPeopleCreateController.php index 04b2f4a8a4..c0b232645b 100644 --- a/src/applications/people/controller/PhabricatorPeopleCreateController.php +++ b/src/applications/people/controller/PhabricatorPeopleCreateController.php @@ -92,13 +92,9 @@ final class PhabricatorPeopleCreateController $crumbs->addTextCrumb($title); $crumbs->setBorder(true); - $header = id(new PHUIHeaderView()) - ->setHeader($title) - ->setHeaderIcon('fa-user'); - $box = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('User')) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) + ->setHeaderText($title) + ->setBackground(PHUIObjectBoxView::WHITE_CONFIG) ->setForm($form); $guidance_context = new PhabricatorPeopleCreateGuidanceContext(); @@ -109,7 +105,6 @@ final class PhabricatorPeopleCreateController ->newInfoView(); $view = id(new PHUITwoColumnView()) - ->setHeader($header) ->setFooter( array( $guidance, diff --git a/src/applications/people/controller/PhabricatorPeopleNewController.php b/src/applications/people/controller/PhabricatorPeopleNewController.php index 60f9f47b5d..9f52cf567a 100644 --- a/src/applications/people/controller/PhabricatorPeopleNewController.php +++ b/src/applications/people/controller/PhabricatorPeopleNewController.php @@ -132,12 +132,15 @@ final class PhabricatorPeopleNewController ->setUser($admin); if ($is_bot) { + $title = pht('Create New Bot'); $form->appendRemarkupInstructions( pht('You are creating a new **bot** user account.')); } else if ($is_list) { + $title = pht('Create New Mailing List'); $form->appendRemarkupInstructions( pht('You are creating a new **mailing list** user account.')); } else { + $title = pht('Create New User'); $form->appendRemarkupInstructions( pht('You are creating a new **standard** user account.')); } @@ -205,25 +208,17 @@ final class PhabricatorPeopleNewController "`bot@yourcompany.com` if you prefer.")); } - - $title = pht('Create New User'); - $box = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('User')) + ->setHeaderText($title) ->setFormErrors($errors) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) + ->setBackground(PHUIObjectBoxView::WHITE_CONFIG) ->setForm($form); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb($title); $crumbs->setBorder(true); - $header = id(new PHUIHeaderView()) - ->setHeader($title) - ->setHeaderIcon('fa-user'); - $view = id(new PHUITwoColumnView()) - ->setHeader($header) ->setFooter($box); return $this->newPage() From 98185730df8dfa45256d63622d644626f53634ca Mon Sep 17 00:00:00 2001 From: Chad Little Date: Thu, 7 Sep 2017 11:41:23 -0700 Subject: [PATCH 30/54] Update Phlux edit UI Summary: Updates Test Plan: Phlux edit page Reviewers: epriestley Reviewed By: epriestley Spies: Korvin Differential Revision: https://secure.phabricator.com/D18561 --- .../phlux/controller/PhluxEditController.php | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/applications/phlux/controller/PhluxEditController.php b/src/applications/phlux/controller/PhluxEditController.php index f37795a754..e2bb7719f7 100644 --- a/src/applications/phlux/controller/PhluxEditController.php +++ b/src/applications/phlux/controller/PhluxEditController.php @@ -154,26 +154,19 @@ final class PhluxEditController extends PhluxController { if ($is_new) { $title = pht('Create Variable'); $crumbs->addTextCrumb($title, $request->getRequestURI()); - $header_icon = 'fa-plus-square'; } else { $title = pht('Edit Variable: %s', $key); - $header_icon = 'fa-pencil'; $crumbs->addTextCrumb($title, $request->getRequestURI()); } $crumbs->setBorder(true); $box = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Variable')) + ->setHeaderText($title) ->setFormErrors($errors) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) + ->setBackground(PHUIObjectBoxView::WHITE_CONFIG) ->setForm($form); - $header = id(new PHUIHeaderView()) - ->setHeader($title) - ->setHeaderIcon($header_icon); - $view = id(new PHUITwoColumnView()) - ->setHeader($header) ->setFooter(array( $box, )); From 3720b28c6c27919005c22b160cdec899747260b8 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Thu, 7 Sep 2017 11:20:48 -0700 Subject: [PATCH 31/54] Update slowvote for new edit UI Summary: Updates UI Test Plan: open new poll Reviewers: epriestley Reviewed By: epriestley Spies: Korvin Differential Revision: https://secure.phabricator.com/D18560 --- .../controller/PhabricatorSlowvoteEditController.php | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/applications/slowvote/controller/PhabricatorSlowvoteEditController.php b/src/applications/slowvote/controller/PhabricatorSlowvoteEditController.php index ebf09ec929..44927fedea 100644 --- a/src/applications/slowvote/controller/PhabricatorSlowvoteEditController.php +++ b/src/applications/slowvote/controller/PhabricatorSlowvoteEditController.php @@ -269,17 +269,12 @@ final class PhabricatorSlowvoteEditController $crumbs->setBorder(true); $form_box = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Poll')) + ->setHeaderText($title) ->setFormErrors($errors) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) + ->setBackground(PHUIObjectBoxView::WHITE_CONFIG) ->setForm($form); - $header = id(new PHUIHeaderView()) - ->setHeader($title) - ->setHeaderIcon($header_icon); - $view = id(new PHUITwoColumnView()) - ->setHeader($header) ->setFooter($form_box); return $this->newPage() From 8059db894d640946f580ef2af6c0933e2bfd7d9a Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 7 Sep 2017 08:33:20 -0700 Subject: [PATCH 32/54] Use the Ferret engine fulltext document table to drive auxiliary fulltext constraints Summary: Ref T12819. I started trying to get individual engines to drive these constraints (e.g., `ManiphestTaskQuery` can do most of the work) but this is a big pain, especially since most engines don't support "any owner" or "no owner", and not everything has an owner, and so on and so on. Going down this path would have meant a huge pile of stub functions everywhere, I think. Instead, drive these through the main engine using the fulltext document table, which already has everything we need to apply these constraints in a uniform way. Also tweak some parts of query construction and result ordering. Test Plan: Searched for documents by author, owner, unowned, any owner, tags, subscribers, fulltext in global search. Got sensible results without any application-specific code. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12819 Differential Revision: https://secure.phabricator.com/D18550 --- .../DifferentialRevisionFerretEngine.php | 2 +- .../search/ManiphestTaskFerretEngine.php | 2 +- ...abricatorFerretFulltextEngineExtension.php | 32 ++++- .../ferret/PhabricatorFerretDocument.php | 12 ++ .../search/ferret/PhabricatorFerretEngine.php | 56 +-------- ...PhabricatorFerretFulltextStorageEngine.php | 30 +++-- ...PhabricatorCursorPagedPolicyAwareQuery.php | 114 ++++++++++++++++-- 7 files changed, 171 insertions(+), 77 deletions(-) diff --git a/src/applications/differential/search/DifferentialRevisionFerretEngine.php b/src/applications/differential/search/DifferentialRevisionFerretEngine.php index b51a486ef5..ebe59c2780 100644 --- a/src/applications/differential/search/DifferentialRevisionFerretEngine.php +++ b/src/applications/differential/search/DifferentialRevisionFerretEngine.php @@ -15,7 +15,7 @@ final class DifferentialRevisionFerretEngine return new DifferentialRevisionFerretField(); } - protected function newSearchEngine() { + public function newSearchEngine() { return new DifferentialRevisionSearchEngine(); } diff --git a/src/applications/maniphest/search/ManiphestTaskFerretEngine.php b/src/applications/maniphest/search/ManiphestTaskFerretEngine.php index 2eab7db74c..7de368402a 100644 --- a/src/applications/maniphest/search/ManiphestTaskFerretEngine.php +++ b/src/applications/maniphest/search/ManiphestTaskFerretEngine.php @@ -15,7 +15,7 @@ final class ManiphestTaskFerretEngine return new ManiphestTaskFerretField(); } - protected function newSearchEngine() { + public function newSearchEngine() { return new ManiphestTaskSearchEngine(); } diff --git a/src/applications/search/engineextension/PhabricatorFerretFulltextEngineExtension.php b/src/applications/search/engineextension/PhabricatorFerretFulltextEngineExtension.php index 8d1b6070e6..27694e3a01 100644 --- a/src/applications/search/engineextension/PhabricatorFerretFulltextEngineExtension.php +++ b/src/applications/search/engineextension/PhabricatorFerretFulltextEngineExtension.php @@ -23,11 +23,37 @@ final class PhabricatorFerretFulltextEngineExtension $phid = $document->getPHID(); $engine = $object->newFerretEngine(); + $is_closed = 0; + $author_phid = null; + $owner_phid = null; + foreach ($document->getRelationshipData() as $relationship) { + list($related_type, $related_phid) = $relationship; + switch ($related_type) { + case PhabricatorSearchRelationship::RELATIONSHIP_OPEN: + $is_closed = 0; + break; + case PhabricatorSearchRelationship::RELATIONSHIP_CLOSED: + $is_closed = 1; + break; + case PhabricatorSearchRelationship::RELATIONSHIP_OWNER: + $owner_phid = $related_phid; + break; + case PhabricatorSearchRelationship::RELATIONSHIP_UNOWNED: + $owner_phid = null; + break; + case PhabricatorSearchRelationship::RELATIONSHIP_AUTHOR: + $author_phid = $related_phid; + break; + } + } + $ferret_document = $engine->newDocumentObject() ->setObjectPHID($phid) - ->setIsClosed(0) - ->setEpochCreated(0) - ->setEpochModified(0); + ->setIsClosed($is_closed) + ->setEpochCreated($document->getDocumentCreated()) + ->setEpochModified($document->getDocumentModified()) + ->setAuthorPHID($author_phid) + ->setOwnerPHID($owner_phid); $stemmer = $engine->newStemmer(); diff --git a/src/applications/search/ferret/PhabricatorFerretDocument.php b/src/applications/search/ferret/PhabricatorFerretDocument.php index fa816c8d17..6f25eb93b6 100644 --- a/src/applications/search/ferret/PhabricatorFerretDocument.php +++ b/src/applications/search/ferret/PhabricatorFerretDocument.php @@ -27,6 +27,18 @@ abstract class PhabricatorFerretDocument 'columns' => array('objectPHID'), 'unique' => true, ), + 'key_author' => array( + 'columns' => array('authorPHID'), + ), + 'key_owner' => array( + 'columns' => array('ownerPHID'), + ), + 'key_created' => array( + 'columns' => array('epochCreated'), + ), + 'key_modified' => array( + 'columns' => array('epochModified'), + ), ), ) + parent::getConfiguration(); } diff --git a/src/applications/search/ferret/PhabricatorFerretEngine.php b/src/applications/search/ferret/PhabricatorFerretEngine.php index 7e30189fb8..7b8520ac71 100644 --- a/src/applications/search/ferret/PhabricatorFerretEngine.php +++ b/src/applications/search/ferret/PhabricatorFerretEngine.php @@ -5,7 +5,7 @@ abstract class PhabricatorFerretEngine extends Phobject { abstract public function newNgramsObject(); abstract public function newDocumentObject(); abstract public function newFieldObject(); - abstract protected function newSearchEngine(); + abstract public function newSearchEngine(); public function getDefaultFunctionKey() { return 'all'; @@ -70,60 +70,6 @@ abstract class PhabricatorFerretEngine extends Phobject { return new PhutilSearchStemmer(); } - public function newConfiguredFulltextQuery( - $object, - PhabricatorSavedQuery $query, - PhabricatorUser $viewer) { - - $local_query = new PhabricatorSavedQuery(); - $local_query->setParameter('query', $query->getParameter('query')); - - // TODO: Modularize this piece. - $project_phids = $query->getParameter('projectPHIDs'); - if ($project_phids) { - $local_query->setParameter('projectPHIDs', $project_phids); - } - - $subscriber_phids = $query->getParameter('subscriberPHIDs'); - if ($subscriber_phids) { - $local_query->setParameter('subscriberPHIDs', $subscriber_phids); - } - - $author_phids = $query->getParameter('authorPHIDs'); - if ($author_phids) { - $local_query->setParameter('authorPHIDs', $author_phids); - } - - $owner_phids = $query->getParameter('ownerPHIDs'); - if ($owner_phids) { - $local_query->setParameter('ownerPHIDs', $owner_phids); - } - - $rel_open = PhabricatorSearchRelationship::RELATIONSHIP_OPEN; - $rel_closed = PhabricatorSearchRelationship::RELATIONSHIP_CLOSED; - - $statuses = $query->getParameter('statuses'); - if ($statuses) { - $statuses = array_fuse($statuses); - if (count($statuses) == 1) { - if (isset($statuses[$rel_open])) { - $local_query->setParameter('statuses', array('open()')); - } - if (isset($statuses[$rel_closed])) { - $local_query->setParameter('statuses', array('closed()')); - } - } - } - - $search_engine = $this->newSearchEngine() - ->setViewer($viewer); - - $engine_query = $search_engine->buildQueryFromSavedQuery($local_query) - ->setViewer($viewer); - - return $engine_query; - } - public function tokenizeString($value) { $value = trim($value, ' '); $value = preg_split('/ +/', $value); diff --git a/src/applications/search/fulltextstorage/PhabricatorFerretFulltextStorageEngine.php b/src/applications/search/fulltextstorage/PhabricatorFerretFulltextStorageEngine.php index 0036ca928b..b67cd7d43c 100644 --- a/src/applications/search/fulltextstorage/PhabricatorFerretFulltextStorageEngine.php +++ b/src/applications/search/fulltextstorage/PhabricatorFerretFulltextStorageEngine.php @@ -47,6 +47,8 @@ final class PhabricatorFerretFulltextStorageEngine $offset = (int)$query->getParameter('offset', 0); $limit = (int)$query->getParameter('limit', 25); + // NOTE: For now, it's okay to query with the omnipotent viewer here + // because we're just returning PHIDs which we'll filter later. $viewer = PhabricatorUser::getOmnipotentUser(); $type_results = array(); @@ -54,19 +56,31 @@ final class PhabricatorFerretFulltextStorageEngine $engine = $spec['engine']; $object = $spec['object']; - // NOTE: For now, it's okay to query with the omnipotent viewer here - // because we're just returning PHIDs which we'll filter later. + $local_query = new PhabricatorSavedQuery(); + $local_query->setParameter('query', $query->getParameter('query')); - $type_query = $engine->newConfiguredFulltextQuery( - $object, - $query, - $viewer); + $project_phids = $query->getParameter('projectPHIDs'); + if ($project_phids) { + $local_query->setParameter('projectPHIDs', $project_phids); + } - $type_query + $subscriber_phids = $query->getParameter('subscriberPHIDs'); + if ($subscriber_phids) { + $local_query->setParameter('subscriberPHIDs', $subscriber_phids); + } + + $search_engine = $engine->newSearchEngine() + ->setViewer($viewer); + + $engine_query = $search_engine->buildQueryFromSavedQuery($local_query) + ->setViewer($viewer); + + $engine_query + ->withFerretQuery($engine, $query) ->setOrder('relevance') ->setLimit($offset + $limit); - $results = $type_query->execute(); + $results = $engine_query->execute(); $results = mpull($results, null, 'getPHID'); $type_results[$type] = $results; } diff --git a/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php b/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php index 1411095f36..569f79d824 100644 --- a/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php +++ b/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php @@ -28,8 +28,9 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery private $spaceIsArchived; private $ngrams = array(); private $ferretEngine; - private $ferretTokens; - private $ferretTables; + private $ferretTokens = array(); + private $ferretTables = array(); + private $ferretQuery; protected function getPageCursors(array $page) { return array( @@ -772,7 +773,7 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery if ($this->supportsFerretEngine()) { $orders['relevance'] = array( - 'vector' => array('rank', 'id'), + 'vector' => array('rank', 'fulltext-modified', 'id'), 'name' => pht('Relevence'), ); } @@ -975,6 +976,16 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery 'column' => '_ft_rank', 'type' => 'int', ); + $columns['fulltext-created'] = array( + 'table' => 'ft_doc', + 'column' => 'epochCreated', + 'type' => 'int', + ); + $columns['fulltext-modified'] = array( + 'table' => 'ft_doc', + 'column' => 'epochModified', + 'type' => 'int', + ); } $cache->setKey($cache_key, $columns); @@ -1406,6 +1417,22 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery return ($object instanceof PhabricatorFerretInterface); } + public function withFerretQuery( + PhabricatorFerretEngine $engine, + PhabricatorSavedQuery $query) { + + if (!$this->supportsFerretEngine()) { + throw new Exception( + pht( + 'Query ("%s") does not support the Ferret fulltext engine.', + get_class($this))); + } + + $this->ferretEngine = $engine; + $this->ferretQuery = $query; + + return $this; + } public function withFerretConstraint( PhabricatorFerretEngine $engine, @@ -1538,10 +1565,10 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery $table_alias, $stem_value); } - - $parts[] = '0'; } + $parts[] = '0'; + $select[] = qsprintf( $conn, '%Q _ft_rank', @@ -1646,7 +1673,7 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery $joins = array(); $joins[] = qsprintf( $conn, - 'JOIN %T ftdoc ON ftdoc.objectPHID = %Q', + 'JOIN %T ft_doc ON ft_doc.objectPHID = %Q', $document_table->getTableName(), $phid_column); @@ -1655,11 +1682,11 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery $table = $spec['table']; $ngram = $spec['ngram']; - $alias = 'ft'.$idx++; + $alias = 'ftngram_'.$idx++; $joins[] = qsprintf( $conn, - 'JOIN %T %T ON %T.documentID = ftdoc.id AND %T.ngram = %s', + 'JOIN %T %T ON %T.documentID = ft_doc.id AND %T.ngram = %s', $table, $alias, $alias, @@ -1672,7 +1699,7 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery $joins[] = qsprintf( $conn, - 'JOIN %T %T ON ftdoc.id = %T.documentID + 'JOIN %T %T ON ft_doc.id = %T.documentID AND %T.fieldKey = %s', $field_table->getTableName(), $alias, @@ -1801,6 +1828,75 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery } } + if ($this->ferretQuery) { + $query = $this->ferretQuery; + + $author_phids = $query->getParameter('authorPHIDs'); + if ($author_phids) { + $where[] = qsprintf( + $conn, + 'ft_doc.authorPHID IN (%Ls)', + $author_phids); + } + + $with_unowned = $query->getParameter('withUnowned'); + $with_any = $query->getParameter('withAnyOwner'); + + if ($with_any && $with_unowned) { + throw new PhabricatorEmptyQueryException( + pht( + 'This query matches only unowned documents owned by anyone, '. + 'which is impossible.')); + } + + $owner_phids = $query->getParameter('ownerPHIDs'); + if ($owner_phids && !$with_any) { + if ($with_unowned) { + $where[] = qsprintf( + $conn, + 'ft_doc.ownerPHID IN (%Ls) OR ft_doc.ownerPHID IS NULL', + $owner_phids); + } else { + $where[] = qsprintf( + $conn, + 'ft_doc.ownerPHID IN (%Ls)', + $owner_phids); + } + } else if ($with_unowned) { + $where[] = qsprintf( + $conn, + 'ft_doc.ownerPHID IS NULL'); + } + + if ($with_any) { + $where[] = qsprintf( + $conn, + 'ft_doc.ownerPHID IS NOT NULL'); + } + + $rel_open = PhabricatorSearchRelationship::RELATIONSHIP_OPEN; + + $statuses = $query->getParameter('statuses'); + $is_closed = null; + if ($statuses) { + $statuses = array_fuse($statuses); + if (count($statuses) == 1) { + if (isset($statuses[$rel_open])) { + $is_closed = 0; + } else { + $is_closed = 1; + } + } + } + + if ($is_closed !== null) { + $where[] = qsprintf( + $conn, + 'ft_doc.isClosed = %d', + $is_closed); + } + } + return $where; } From a2a2b3f7f4b590ce211f8e02f8a76060313729cb Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 7 Sep 2017 09:09:39 -0700 Subject: [PATCH 33/54] Sort global fulltext results by overall relevance Summary: Ref T12819. Currently, under the Ferret engine, we query each application's index separately and then aggregate the results. At the moment, results are aggregated by type first, then by actual rank. For example, all the revisions appear first, then all the tasks. Instead, surface the internal ranking data from the underlying query and sort by it. Test Plan: Searched for "A B" with a task named "A B" and a revision named "A". Saw task first. Broadly, saw mixed task and revision order in result sets. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12819 Differential Revision: https://secure.phabricator.com/D18551 --- src/__phutil_library_map__.php | 2 + .../query/DifferentialRevisionQuery.php | 2 +- .../maniphest/query/ManiphestTaskQuery.php | 1 + .../ferret/PhabricatorFerretMetadata.php | 41 +++++++++++++++++++ ...PhabricatorFerretFulltextStorageEngine.php | 13 ++++++ ...PhabricatorCursorPagedPolicyAwareQuery.php | 35 ++++++++++++++++ 6 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 src/applications/search/ferret/PhabricatorFerretMetadata.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index e81239f9c0..ce3a86b98c 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -2840,6 +2840,7 @@ phutil_register_library_map(array( 'PhabricatorFerretFulltextEngineExtension' => 'applications/search/engineextension/PhabricatorFerretFulltextEngineExtension.php', 'PhabricatorFerretFulltextStorageEngine' => 'applications/search/fulltextstorage/PhabricatorFerretFulltextStorageEngine.php', 'PhabricatorFerretInterface' => 'applications/search/ferret/PhabricatorFerretInterface.php', + 'PhabricatorFerretMetadata' => 'applications/search/ferret/PhabricatorFerretMetadata.php', 'PhabricatorFerretNgrams' => 'applications/search/ferret/PhabricatorFerretNgrams.php', 'PhabricatorFerretSearchEngineExtension' => 'applications/search/engineextension/PhabricatorFerretSearchEngineExtension.php', 'PhabricatorFile' => 'applications/files/storage/PhabricatorFile.php', @@ -8175,6 +8176,7 @@ phutil_register_library_map(array( 'PhabricatorFerretField' => 'PhabricatorSearchDAO', 'PhabricatorFerretFulltextEngineExtension' => 'PhabricatorFulltextEngineExtension', 'PhabricatorFerretFulltextStorageEngine' => 'PhabricatorFulltextStorageEngine', + 'PhabricatorFerretMetadata' => 'Phobject', 'PhabricatorFerretNgrams' => 'PhabricatorSearchDAO', 'PhabricatorFerretSearchEngineExtension' => 'PhabricatorSearchEngineExtension', 'PhabricatorFile' => array( diff --git a/src/applications/differential/query/DifferentialRevisionQuery.php b/src/applications/differential/query/DifferentialRevisionQuery.php index 622eba564a..8fd91cbd7e 100644 --- a/src/applications/differential/query/DifferentialRevisionQuery.php +++ b/src/applications/differential/query/DifferentialRevisionQuery.php @@ -320,7 +320,7 @@ final class DifferentialRevisionQuery */ protected function loadPage() { $data = $this->loadData(); - + $data = $this->didLoadRawRows($data); $table = $this->newResultObject(); return $table->loadAllFromArray($data); } diff --git a/src/applications/maniphest/query/ManiphestTaskQuery.php b/src/applications/maniphest/query/ManiphestTaskQuery.php index 704a67f548..f009e5c2ef 100644 --- a/src/applications/maniphest/query/ManiphestTaskQuery.php +++ b/src/applications/maniphest/query/ManiphestTaskQuery.php @@ -247,6 +247,7 @@ final class ManiphestTaskQuery extends PhabricatorCursorPagedPolicyAwareQuery { break; } + $data = $this->didLoadRawRows($data); $tasks = $task_dao->loadAllFromArray($data); switch ($this->groupBy) { diff --git a/src/applications/search/ferret/PhabricatorFerretMetadata.php b/src/applications/search/ferret/PhabricatorFerretMetadata.php new file mode 100644 index 0000000000..8ab5e37e45 --- /dev/null +++ b/src/applications/search/ferret/PhabricatorFerretMetadata.php @@ -0,0 +1,41 @@ +engine = $engine; + return $this; + } + + public function getEngine() { + return $this->engine; + } + + public function setPHID($phid) { + $this->phid = $phid; + return $this; + } + + public function getPHID() { + return $this->phid; + } + + public function setRelevance($relevance) { + $this->relevance = $relevance; + return $this; + } + + public function getRelevance() { + return $this->relevance; + } + + public function getRelevanceSortVector() { + return id(new PhutilSortVector()) + ->addInt(-$this->getRelevance()); + } + +} diff --git a/src/applications/search/fulltextstorage/PhabricatorFerretFulltextStorageEngine.php b/src/applications/search/fulltextstorage/PhabricatorFerretFulltextStorageEngine.php index b67cd7d43c..74e8771de7 100644 --- a/src/applications/search/fulltextstorage/PhabricatorFerretFulltextStorageEngine.php +++ b/src/applications/search/fulltextstorage/PhabricatorFerretFulltextStorageEngine.php @@ -52,6 +52,7 @@ final class PhabricatorFerretFulltextStorageEngine $viewer = PhabricatorUser::getOmnipotentUser(); $type_results = array(); + $metadata = array(); foreach ($type_map as $type => $spec) { $engine = $spec['engine']; $object = $spec['object']; @@ -83,6 +84,8 @@ final class PhabricatorFerretFulltextStorageEngine $results = $engine_query->execute(); $results = mpull($results, null, 'getPHID'); $type_results[$type] = $results; + + $metadata += $engine_query->getFerretMetadata(); } $list = array(); @@ -90,6 +93,16 @@ final class PhabricatorFerretFulltextStorageEngine $list += $results; } + // Currently, the list is grouped by object type. For example, all the + // tasks might be first, then all the revisions, and so on. In each group, + // the results are ordered properly. + + // Reorder the results so that the highest-ranking results come first, + // no matter which object types they belong to. + + $metadata = msort($metadata, 'getRelevanceSortVector'); + $list = array_select_keys($list, array_keys($metadata)) + $list; + $result_slice = array_slice($list, $offset, $limit, true); return array_keys($result_slice); } diff --git a/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php b/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php index 569f79d824..42e6ed7b4e 100644 --- a/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php +++ b/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php @@ -31,6 +31,7 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery private $ferretTokens = array(); private $ferretTables = array(); private $ferretQuery; + private $ferretMetadata = array(); protected function getPageCursors(array $page) { return array( @@ -82,6 +83,18 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery return $this->beforeID; } + final public function getFerretMetadata() { + if (!$this->supportsFerretEngine()) { + throw new Exception( + pht( + 'Unable to retrieve Ferret engine metadata, this class ("%s") does '. + 'not support the Ferret engine.', + get_class($this))); + } + + return $this->ferretMetadata; + } + protected function loadStandardPage(PhabricatorLiskDAO $table) { $rows = $this->loadStandardPageRows($table); return $table->loadAllFromArray($rows); @@ -111,6 +124,27 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery $this->buildOrderClause($conn), $this->buildLimitClause($conn)); + $rows = $this->didLoadRawRows($rows); + + return $rows; + } + + protected function didLoadRawRows(array $rows) { + if ($this->ferretEngine) { + foreach ($rows as $row) { + $phid = $row['phid']; + + $metadata = id(new PhabricatorFerretMetadata()) + ->setPHID($phid) + ->setEngine($this->ferretEngine) + ->setRelevance(idx($row, '_ft_rank')); + + $this->ferretMetadata[$phid] = $metadata; + + unset($row['_ft_rank']); + } + } + return $rows; } @@ -172,6 +206,7 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery if ($this->beforeID) { $results = array_reverse($results, $preserve_keys = true); } + return $results; } From 3ff9d4a4cab39fcd84cb4706139486c0c85218be Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 7 Sep 2017 09:38:19 -0700 Subject: [PATCH 34/54] Support Ferret engine for searching users Summary: Ref T12819. Adds support for indexing user accounts so they appear in global fulltext results. Also, always rank users ahead of other results. Test Plan: Indexed users. Searched for a user, got that user. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12819 Differential Revision: https://secure.phabricator.com/D18552 --- .../20170907.ferret.01.user.doc.sql | 9 ++++++ .../20170907.ferret.02.user.field.sql | 8 +++++ .../20170907.ferret.03.user.ngrams.sql | 5 ++++ src/__phutil_library_map__.php | 9 ++++++ .../search/PhabricatorUserFerretEngine.php | 29 +++++++++++++++++++ .../people/storage/PhabricatorUser.php | 9 ++++++ .../storage/PhabricatorUserFerretDocument.php | 14 +++++++++ .../storage/PhabricatorUserFerretField.php | 14 +++++++++ .../storage/PhabricatorUserFerretNgrams.php | 14 +++++++++ .../search/ferret/PhabricatorFerretEngine.php | 4 +++ .../ferret/PhabricatorFerretMetadata.php | 3 ++ 11 files changed, 118 insertions(+) create mode 100644 resources/sql/autopatches/20170907.ferret.01.user.doc.sql create mode 100644 resources/sql/autopatches/20170907.ferret.02.user.field.sql create mode 100644 resources/sql/autopatches/20170907.ferret.03.user.ngrams.sql create mode 100644 src/applications/people/search/PhabricatorUserFerretEngine.php create mode 100644 src/applications/people/storage/PhabricatorUserFerretDocument.php create mode 100644 src/applications/people/storage/PhabricatorUserFerretField.php create mode 100644 src/applications/people/storage/PhabricatorUserFerretNgrams.php diff --git a/resources/sql/autopatches/20170907.ferret.01.user.doc.sql b/resources/sql/autopatches/20170907.ferret.01.user.doc.sql new file mode 100644 index 0000000000..39496a0de0 --- /dev/null +++ b/resources/sql/autopatches/20170907.ferret.01.user.doc.sql @@ -0,0 +1,9 @@ +CREATE TABLE {$NAMESPACE}_user.user_user_fdocument ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + objectPHID VARBINARY(64) NOT NULL, + isClosed BOOL NOT NULL, + authorPHID VARBINARY(64), + ownerPHID VARBINARY(64), + epochCreated INT UNSIGNED NOT NULL, + epochModified INT UNSIGNED NOT NULL +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/resources/sql/autopatches/20170907.ferret.02.user.field.sql b/resources/sql/autopatches/20170907.ferret.02.user.field.sql new file mode 100644 index 0000000000..3179e58e5b --- /dev/null +++ b/resources/sql/autopatches/20170907.ferret.02.user.field.sql @@ -0,0 +1,8 @@ +CREATE TABLE {$NAMESPACE}_user.user_user_ffield ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + documentID INT UNSIGNED NOT NULL, + fieldKey VARCHAR(4) NOT NULL COLLATE {$COLLATE_TEXT}, + rawCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT}, + termCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT}, + normalCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT} +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/resources/sql/autopatches/20170907.ferret.03.user.ngrams.sql b/resources/sql/autopatches/20170907.ferret.03.user.ngrams.sql new file mode 100644 index 0000000000..2105a7b7af --- /dev/null +++ b/resources/sql/autopatches/20170907.ferret.03.user.ngrams.sql @@ -0,0 +1,5 @@ +CREATE TABLE {$NAMESPACE}_user.user_user_fngrams ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + documentID INT UNSIGNED NOT NULL, + ngram CHAR(3) NOT NULL COLLATE {$COLLATE_TEXT} +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index ce3a86b98c..854a96366e 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -4257,6 +4257,10 @@ phutil_register_library_map(array( 'PhabricatorUserEditorTestCase' => 'applications/people/editor/__tests__/PhabricatorUserEditorTestCase.php', 'PhabricatorUserEmail' => 'applications/people/storage/PhabricatorUserEmail.php', 'PhabricatorUserEmailTestCase' => 'applications/people/storage/__tests__/PhabricatorUserEmailTestCase.php', + 'PhabricatorUserFerretDocument' => 'applications/people/storage/PhabricatorUserFerretDocument.php', + 'PhabricatorUserFerretEngine' => 'applications/people/search/PhabricatorUserFerretEngine.php', + 'PhabricatorUserFerretField' => 'applications/people/storage/PhabricatorUserFerretField.php', + 'PhabricatorUserFerretNgrams' => 'applications/people/storage/PhabricatorUserFerretNgrams.php', 'PhabricatorUserFulltextEngine' => 'applications/people/search/PhabricatorUserFulltextEngine.php', 'PhabricatorUserIconField' => 'applications/people/customfield/PhabricatorUserIconField.php', 'PhabricatorUserLog' => 'applications/people/storage/PhabricatorUserLog.php', @@ -9840,6 +9844,7 @@ phutil_register_library_map(array( 'PhabricatorFlaggableInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorFulltextInterface', + 'PhabricatorFerretInterface', 'PhabricatorConduitResultInterface', ), 'PhabricatorUserBadgesCacheType' => 'PhabricatorUserCacheType', @@ -9862,6 +9867,10 @@ phutil_register_library_map(array( 'PhabricatorUserEditorTestCase' => 'PhabricatorTestCase', 'PhabricatorUserEmail' => 'PhabricatorUserDAO', 'PhabricatorUserEmailTestCase' => 'PhabricatorTestCase', + 'PhabricatorUserFerretDocument' => 'PhabricatorFerretDocument', + 'PhabricatorUserFerretEngine' => 'PhabricatorFerretEngine', + 'PhabricatorUserFerretField' => 'PhabricatorFerretField', + 'PhabricatorUserFerretNgrams' => 'PhabricatorFerretNgrams', 'PhabricatorUserFulltextEngine' => 'PhabricatorFulltextEngine', 'PhabricatorUserIconField' => 'PhabricatorUserCustomField', 'PhabricatorUserLog' => array( diff --git a/src/applications/people/search/PhabricatorUserFerretEngine.php b/src/applications/people/search/PhabricatorUserFerretEngine.php new file mode 100644 index 0000000000..1f44bf4289 --- /dev/null +++ b/src/applications/people/search/PhabricatorUserFerretEngine.php @@ -0,0 +1,29 @@ +getEngine(); + return id(new PhutilSortVector()) + ->addInt($engine->getObjectTypeRelevance()) ->addInt(-$this->getRelevance()); } From 60deec36d8ed922938223f7771c21c62f5689d88 Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 7 Sep 2017 09:53:15 -0700 Subject: [PATCH 35/54] Lightly modernize FundInitiativeQuery Summary: Ref T12819. Prepares Fund to move to Ferret. Test Plan: Searched for initiatives in Fund. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12819 Differential Revision: https://secure.phabricator.com/D18553 --- .../fund/query/FundInitiativeQuery.php | 33 +++++++------------ 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/src/applications/fund/query/FundInitiativeQuery.php b/src/applications/fund/query/FundInitiativeQuery.php index 66f87a883c..9efbcfbf27 100644 --- a/src/applications/fund/query/FundInitiativeQuery.php +++ b/src/applications/fund/query/FundInitiativeQuery.php @@ -35,19 +35,12 @@ final class FundInitiativeQuery return $this; } + public function newResultObject() { + return new FundInitiative(); + } + protected function loadPage() { - $table = new FundInitiative(); - $conn_r = $table->establishConnection('r'); - - $rows = queryfx_all( - $conn_r, - 'SELECT * FROM %T %Q %Q %Q', - $table->getTableName(), - $this->buildWhereClause($conn_r), - $this->buildOrderClause($conn_r), - $this->buildLimitClause($conn_r)); - - return $table->loadAllFromArray($rows); + return $this->loadStandardPage($this->newResultObject()); } protected function didFilterPage(array $initiatives) { @@ -73,40 +66,38 @@ final class FundInitiativeQuery return $initiatives; } - protected function buildWhereClause(AphrontDatabaseConnection $conn_r) { - $where = array(); - - $where[] = $this->buildPagingClause($conn_r); + protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { + $where = parent::buildWhereClauseParts($conn); if ($this->ids !== null) { $where[] = qsprintf( - $conn_r, + $conn, 'id IN (%Ld)', $this->ids); } if ($this->phids !== null) { $where[] = qsprintf( - $conn_r, + $conn, 'phid IN (%Ls)', $this->phids); } if ($this->ownerPHIDs !== null) { $where[] = qsprintf( - $conn_r, + $conn, 'ownerPHID IN (%Ls)', $this->ownerPHIDs); } if ($this->statuses !== null) { $where[] = qsprintf( - $conn_r, + $conn, 'status IN (%Ls)', $this->statuses); } - return $this->formatWhereClause($where); + return $where; } public function getQueryApplicationClass() { From cf0bc32e18a9aac85ccfdda74c36b040cbf4fe74 Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 7 Sep 2017 10:05:48 -0700 Subject: [PATCH 36/54] Lightly modernize FundInitiativeSearchEngine Summary: Ref T12819. Prepares for Ferret engine support. Test Plan: Queried for various initiatives. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12819 Differential Revision: https://secure.phabricator.com/D18554 --- .../fund/query/FundInitiativeQuery.php | 30 ----- .../fund/query/FundInitiativeSearchEngine.php | 124 +++++++----------- 2 files changed, 51 insertions(+), 103 deletions(-) diff --git a/src/applications/fund/query/FundInitiativeQuery.php b/src/applications/fund/query/FundInitiativeQuery.php index 9efbcfbf27..aeeb0942b9 100644 --- a/src/applications/fund/query/FundInitiativeQuery.php +++ b/src/applications/fund/query/FundInitiativeQuery.php @@ -8,8 +8,6 @@ final class FundInitiativeQuery private $ownerPHIDs; private $statuses; - private $needProjectPHIDs; - public function withIDs(array $ids) { $this->ids = $ids; return $this; @@ -30,11 +28,6 @@ final class FundInitiativeQuery return $this; } - public function needProjectPHIDs($need) { - $this->needProjectPHIDs = $need; - return $this; - } - public function newResultObject() { return new FundInitiative(); } @@ -43,29 +36,6 @@ final class FundInitiativeQuery return $this->loadStandardPage($this->newResultObject()); } - protected function didFilterPage(array $initiatives) { - - if ($this->needProjectPHIDs) { - $edge_query = id(new PhabricatorEdgeQuery()) - ->withSourcePHIDs(mpull($initiatives, 'getPHID')) - ->withEdgeTypes( - array( - PhabricatorProjectObjectHasProjectEdgeType::EDGECONST, - )); - $edge_query->execute(); - - foreach ($initiatives as $initiative) { - $phids = $edge_query->getDestinationPHIDs( - array( - $initiative->getPHID(), - )); - $initiative->attachProjectPHIDs($phids); - } - } - - return $initiatives; - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff --git a/src/applications/fund/query/FundInitiativeSearchEngine.php b/src/applications/fund/query/FundInitiativeSearchEngine.php index 3c339c1a64..e075fe5063 100644 --- a/src/applications/fund/query/FundInitiativeSearchEngine.php +++ b/src/applications/fund/query/FundInitiativeSearchEngine.php @@ -11,67 +11,37 @@ final class FundInitiativeSearchEngine return 'PhabricatorFundApplication'; } - public function buildSavedQueryFromRequest(AphrontRequest $request) { - $saved = new PhabricatorSavedQuery(); - - $saved->setParameter( - 'ownerPHIDs', - $this->readUsersFromRequest($request, 'owners')); - - $saved->setParameter( - 'statuses', - $this->readListFromRequest($request, 'statuses')); - - return $saved; + public function newQuery() { + return new FundInitiativeQuery(); } - public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) { - $query = id(new FundInitiativeQuery()) - ->needProjectPHIDs(true); + protected function buildCustomSearchFields() { + return array( + id(new PhabricatorUsersSearchField()) + ->setKey('ownerPHIDs') + ->setAliases(array('owner', 'ownerPHID', 'owners')) + ->setLabel(pht('Owners')), + id(new PhabricatorSearchCheckboxesField()) + ->setKey('statuses') + ->setLabel(pht('Statuses')) + ->setOptions(FundInitiative::getStatusNameMap()), + ); + } - $owner_phids = $saved->getParameter('ownerPHIDs'); - if ($owner_phids) { - $query->withOwnerPHIDs($owner_phids); + protected function buildQueryFromParameters(array $map) { + $query = $this->newQuery(); + + if ($map['ownerPHIDs']) { + $query->withOwnerPHIDs($map['ownerPHIDs']); } - $statuses = $saved->getParameter('statuses'); - if ($statuses) { - $query->withStatuses($statuses); + if ($map['statuses']) { + $query->withStatuses($map['statuses']); } return $query; } - public function buildSearchForm( - AphrontFormView $form, - PhabricatorSavedQuery $saved) { - - $statuses = $saved->getParameter('statuses', array()); - $statuses = array_fuse($statuses); - - $owner_phids = $saved->getParameter('ownerPHIDs', array()); - - $status_map = FundInitiative::getStatusNameMap(); - $status_control = id(new AphrontFormCheckboxControl()) - ->setLabel(pht('Statuses')); - foreach ($status_map as $status => $name) { - $status_control->addCheckbox( - 'statuses[]', - $status, - $name, - isset($statuses[$status])); - } - - $form - ->appendControl( - id(new AphrontFormTokenizerControl()) - ->setLabel(pht('Owners')) - ->setName('owners') - ->setDatasource(new PhabricatorPeopleDatasource()) - ->setValue($owner_phids)) - ->appendChild($status_control); - } - protected function getURI($path) { return '/fund/'.$path; } @@ -112,21 +82,6 @@ final class FundInitiativeSearchEngine return parent::buildSavedQueryFromBuiltin($query_key); } - protected function getRequiredHandlePHIDsForResultList( - array $initiatives, - PhabricatorSavedQuery $query) { - - $phids = array(); - foreach ($initiatives as $initiative) { - $phids[] = $initiative->getOwnerPHID(); - foreach ($initiative->getProjectPHIDs() as $project_phid) { - $phids[] = $project_phid; - } - } - - return $phids; - } - protected function renderResultList( array $initiatives, PhabricatorSavedQuery $query, @@ -135,7 +90,30 @@ final class FundInitiativeSearchEngine $viewer = $this->requireViewer(); - $list = id(new PHUIObjectItemListView()); + $load_phids = array(); + foreach ($initiatives as $initiative) { + $load_phids[] = $initiative->getOwnerPHID(); + } + + if ($initiatives) { + $edge_query = id(new PhabricatorEdgeQuery()) + ->withSourcePHIDs(mpull($initiatives, 'getPHID')) + ->withEdgeTypes( + array( + PhabricatorProjectObjectHasProjectEdgeType::EDGECONST, + )); + + $edge_query->execute(); + + foreach ($edge_query->getDestinationPHIDs() as $phid) { + $load_phids[] = $phid; + } + } + + $handles = $viewer->loadHandles($load_phids); + $handles = iterator_to_array($handles); + + $list = new PHUIObjectItemListView(); foreach ($initiatives as $initiative) { $owner_handle = $handles[$initiative->getOwnerPHID()]; @@ -149,9 +127,12 @@ final class FundInitiativeSearchEngine $item->setDisabled(true); } - $project_handles = array_select_keys( - $handles, - $initiative->getProjectPHIDs()); + $project_phids = $edge_query->getDestinationPHIDs( + array( + $initiative->getPHID(), + )); + + $project_handles = array_select_keys($handles, $project_phids); if ($project_handles) { $item->addAttribute( id(new PHUIHandleTagListView()) @@ -168,9 +149,6 @@ final class FundInitiativeSearchEngine $result->setNoDataString(pht('No initiatives found.')); return $result; - - - return $list; } } From f23717b416fe08e579752ca361ee18b612822812 Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 7 Sep 2017 10:20:31 -0700 Subject: [PATCH 37/54] Support Ferret engine in Fund initiatives Summary: Ref T12819. Adds Ferret engine support to initiatives. Test Plan: Indexed and searched for initiatives. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12819 Differential Revision: https://secure.phabricator.com/D18555 --- .../20170907.ferret.04.fund.doc.sql | 9 ++++++++ .../20170907.ferret.05.fund.field.sql | 8 +++++++ .../20170907.ferret.06.fund.ngrams.sql | 5 +++++ src/__phutil_library_map__.php | 9 ++++++++ .../fund/query/FundInitiativeQuery.php | 12 ++++++---- .../search/FundInitiativeFerretEngine.php | 22 +++++++++++++++++++ .../fund/storage/FundInitiative.php | 11 +++++++++- .../storage/FundInitiativeFerretDocument.php | 14 ++++++++++++ .../storage/FundInitiativeFerretField.php | 14 ++++++++++++ .../storage/FundInitiativeFerretNgrams.php | 14 ++++++++++++ 10 files changed, 113 insertions(+), 5 deletions(-) create mode 100644 resources/sql/autopatches/20170907.ferret.04.fund.doc.sql create mode 100644 resources/sql/autopatches/20170907.ferret.05.fund.field.sql create mode 100644 resources/sql/autopatches/20170907.ferret.06.fund.ngrams.sql create mode 100644 src/applications/fund/search/FundInitiativeFerretEngine.php create mode 100644 src/applications/fund/storage/FundInitiativeFerretDocument.php create mode 100644 src/applications/fund/storage/FundInitiativeFerretField.php create mode 100644 src/applications/fund/storage/FundInitiativeFerretNgrams.php diff --git a/resources/sql/autopatches/20170907.ferret.04.fund.doc.sql b/resources/sql/autopatches/20170907.ferret.04.fund.doc.sql new file mode 100644 index 0000000000..a7f8324594 --- /dev/null +++ b/resources/sql/autopatches/20170907.ferret.04.fund.doc.sql @@ -0,0 +1,9 @@ +CREATE TABLE {$NAMESPACE}_fund.fund_initiative_fdocument ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + objectPHID VARBINARY(64) NOT NULL, + isClosed BOOL NOT NULL, + authorPHID VARBINARY(64), + ownerPHID VARBINARY(64), + epochCreated INT UNSIGNED NOT NULL, + epochModified INT UNSIGNED NOT NULL +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/resources/sql/autopatches/20170907.ferret.05.fund.field.sql b/resources/sql/autopatches/20170907.ferret.05.fund.field.sql new file mode 100644 index 0000000000..b8c544c2a7 --- /dev/null +++ b/resources/sql/autopatches/20170907.ferret.05.fund.field.sql @@ -0,0 +1,8 @@ +CREATE TABLE {$NAMESPACE}_fund.fund_initiative_ffield ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + documentID INT UNSIGNED NOT NULL, + fieldKey VARCHAR(4) NOT NULL COLLATE {$COLLATE_TEXT}, + rawCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT}, + termCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT}, + normalCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT} +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/resources/sql/autopatches/20170907.ferret.06.fund.ngrams.sql b/resources/sql/autopatches/20170907.ferret.06.fund.ngrams.sql new file mode 100644 index 0000000000..a509087bae --- /dev/null +++ b/resources/sql/autopatches/20170907.ferret.06.fund.ngrams.sql @@ -0,0 +1,5 @@ +CREATE TABLE {$NAMESPACE}_fund.fund_initiative_fngrams ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + documentID INT UNSIGNED NOT NULL, + ngram CHAR(3) NOT NULL COLLATE {$COLLATE_TEXT} +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 854a96366e..2d415173bb 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1153,6 +1153,10 @@ phutil_register_library_map(array( 'FundInitiativeEditController' => 'applications/fund/controller/FundInitiativeEditController.php', 'FundInitiativeEditEngine' => 'applications/fund/editor/FundInitiativeEditEngine.php', 'FundInitiativeEditor' => 'applications/fund/editor/FundInitiativeEditor.php', + 'FundInitiativeFerretDocument' => 'applications/fund/storage/FundInitiativeFerretDocument.php', + 'FundInitiativeFerretEngine' => 'applications/fund/search/FundInitiativeFerretEngine.php', + 'FundInitiativeFerretField' => 'applications/fund/storage/FundInitiativeFerretField.php', + 'FundInitiativeFerretNgrams' => 'applications/fund/storage/FundInitiativeFerretNgrams.php', 'FundInitiativeFulltextEngine' => 'applications/fund/search/FundInitiativeFulltextEngine.php', 'FundInitiativeListController' => 'applications/fund/controller/FundInitiativeListController.php', 'FundInitiativeMerchantTransaction' => 'applications/fund/xaction/FundInitiativeMerchantTransaction.php', @@ -6231,6 +6235,7 @@ phutil_register_library_map(array( 'PhabricatorTokenReceiverInterface', 'PhabricatorDestructibleInterface', 'PhabricatorFulltextInterface', + 'PhabricatorFerretInterface', ), 'FundInitiativeBackController' => 'FundController', 'FundInitiativeBackerTransaction' => 'FundInitiativeTransactionType', @@ -6239,6 +6244,10 @@ phutil_register_library_map(array( 'FundInitiativeEditController' => 'FundController', 'FundInitiativeEditEngine' => 'PhabricatorEditEngine', 'FundInitiativeEditor' => 'PhabricatorApplicationTransactionEditor', + 'FundInitiativeFerretDocument' => 'PhabricatorFerretDocument', + 'FundInitiativeFerretEngine' => 'PhabricatorFerretEngine', + 'FundInitiativeFerretField' => 'PhabricatorFerretField', + 'FundInitiativeFerretNgrams' => 'PhabricatorFerretNgrams', 'FundInitiativeFulltextEngine' => 'PhabricatorFulltextEngine', 'FundInitiativeListController' => 'FundController', 'FundInitiativeMerchantTransaction' => 'FundInitiativeTransactionType', diff --git a/src/applications/fund/query/FundInitiativeQuery.php b/src/applications/fund/query/FundInitiativeQuery.php index aeeb0942b9..bbb4ef2746 100644 --- a/src/applications/fund/query/FundInitiativeQuery.php +++ b/src/applications/fund/query/FundInitiativeQuery.php @@ -42,28 +42,28 @@ final class FundInitiativeQuery if ($this->ids !== null) { $where[] = qsprintf( $conn, - 'id IN (%Ld)', + 'i.id IN (%Ld)', $this->ids); } if ($this->phids !== null) { $where[] = qsprintf( $conn, - 'phid IN (%Ls)', + 'i.phid IN (%Ls)', $this->phids); } if ($this->ownerPHIDs !== null) { $where[] = qsprintf( $conn, - 'ownerPHID IN (%Ls)', + 'i.ownerPHID IN (%Ls)', $this->ownerPHIDs); } if ($this->statuses !== null) { $where[] = qsprintf( $conn, - 'status IN (%Ls)', + 'i.status IN (%Ls)', $this->statuses); } @@ -74,4 +74,8 @@ final class FundInitiativeQuery return 'PhabricatorFundApplication'; } + protected function getPrimaryTableAlias() { + return 'i'; + } + } diff --git a/src/applications/fund/search/FundInitiativeFerretEngine.php b/src/applications/fund/search/FundInitiativeFerretEngine.php new file mode 100644 index 0000000000..fd9ce1313d --- /dev/null +++ b/src/applications/fund/search/FundInitiativeFerretEngine.php @@ -0,0 +1,22 @@ + Date: Thu, 7 Sep 2017 10:27:10 -0700 Subject: [PATCH 38/54] Support Ferret engine for Passphrase credentials Summary: Ref T12819. Adds Ferret support to Passphrase. Test Plan: Indexed credentials, searched for credentials. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12819 Differential Revision: https://secure.phabricator.com/D18556 --- .../20170907.ferret.07.passphrase.doc.sql | 9 ++++++++ .../20170907.ferret.08.passphrase.field.sql | 8 +++++++ .../20170907.ferret.09.passphrase.ngrams.sql | 5 +++++ src/__phutil_library_map__.php | 9 ++++++++ .../query/PassphraseCredentialQuery.php | 18 +++++++++------ .../PassphraseCredentialFerretEngine.php | 22 +++++++++++++++++++ .../storage/PassphraseCredential.php | 11 +++++++++- .../PassphraseCredentialFerretDocument.php | 14 ++++++++++++ .../PassphraseCredentialFerretField.php | 14 ++++++++++++ .../PassphraseCredentialFerretNgrams.php | 14 ++++++++++++ 10 files changed, 116 insertions(+), 8 deletions(-) create mode 100644 resources/sql/autopatches/20170907.ferret.07.passphrase.doc.sql create mode 100644 resources/sql/autopatches/20170907.ferret.08.passphrase.field.sql create mode 100644 resources/sql/autopatches/20170907.ferret.09.passphrase.ngrams.sql create mode 100644 src/applications/passphrase/search/PassphraseCredentialFerretEngine.php create mode 100644 src/applications/passphrase/storage/PassphraseCredentialFerretDocument.php create mode 100644 src/applications/passphrase/storage/PassphraseCredentialFerretField.php create mode 100644 src/applications/passphrase/storage/PassphraseCredentialFerretNgrams.php diff --git a/resources/sql/autopatches/20170907.ferret.07.passphrase.doc.sql b/resources/sql/autopatches/20170907.ferret.07.passphrase.doc.sql new file mode 100644 index 0000000000..6787528d0e --- /dev/null +++ b/resources/sql/autopatches/20170907.ferret.07.passphrase.doc.sql @@ -0,0 +1,9 @@ +CREATE TABLE {$NAMESPACE}_passphrase.passphrase_credential_fdocument ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + objectPHID VARBINARY(64) NOT NULL, + isClosed BOOL NOT NULL, + authorPHID VARBINARY(64), + ownerPHID VARBINARY(64), + epochCreated INT UNSIGNED NOT NULL, + epochModified INT UNSIGNED NOT NULL +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/resources/sql/autopatches/20170907.ferret.08.passphrase.field.sql b/resources/sql/autopatches/20170907.ferret.08.passphrase.field.sql new file mode 100644 index 0000000000..6dc62d477e --- /dev/null +++ b/resources/sql/autopatches/20170907.ferret.08.passphrase.field.sql @@ -0,0 +1,8 @@ +CREATE TABLE {$NAMESPACE}_passphrase.passphrase_credential_ffield ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + documentID INT UNSIGNED NOT NULL, + fieldKey VARCHAR(4) NOT NULL COLLATE {$COLLATE_TEXT}, + rawCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT}, + termCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT}, + normalCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT} +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/resources/sql/autopatches/20170907.ferret.09.passphrase.ngrams.sql b/resources/sql/autopatches/20170907.ferret.09.passphrase.ngrams.sql new file mode 100644 index 0000000000..2b64beb7ed --- /dev/null +++ b/resources/sql/autopatches/20170907.ferret.09.passphrase.ngrams.sql @@ -0,0 +1,5 @@ +CREATE TABLE {$NAMESPACE}_passphrase.passphrase_credential_fngrams ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + documentID INT UNSIGNED NOT NULL, + ngram CHAR(3) NOT NULL COLLATE {$COLLATE_TEXT} +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 2d415173bb..3e498d6273 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1840,6 +1840,10 @@ phutil_register_library_map(array( 'PassphraseCredentialDestroyController' => 'applications/passphrase/controller/PassphraseCredentialDestroyController.php', 'PassphraseCredentialDestroyTransaction' => 'applications/passphrase/xaction/PassphraseCredentialDestroyTransaction.php', 'PassphraseCredentialEditController' => 'applications/passphrase/controller/PassphraseCredentialEditController.php', + 'PassphraseCredentialFerretDocument' => 'applications/passphrase/storage/PassphraseCredentialFerretDocument.php', + 'PassphraseCredentialFerretEngine' => 'applications/passphrase/search/PassphraseCredentialFerretEngine.php', + 'PassphraseCredentialFerretField' => 'applications/passphrase/storage/PassphraseCredentialFerretField.php', + 'PassphraseCredentialFerretNgrams' => 'applications/passphrase/storage/PassphraseCredentialFerretNgrams.php', 'PassphraseCredentialFulltextEngine' => 'applications/passphrase/search/PassphraseCredentialFulltextEngine.php', 'PassphraseCredentialListController' => 'applications/passphrase/controller/PassphraseCredentialListController.php', 'PassphraseCredentialLockController' => 'applications/passphrase/controller/PassphraseCredentialLockController.php', @@ -7034,6 +7038,7 @@ phutil_register_library_map(array( 'PhabricatorDestructibleInterface', 'PhabricatorSpacesInterface', 'PhabricatorFulltextInterface', + 'PhabricatorFerretInterface', ), 'PassphraseCredentialAuthorPolicyRule' => 'PhabricatorPolicyRule', 'PassphraseCredentialConduitController' => 'PassphraseController', @@ -7044,6 +7049,10 @@ phutil_register_library_map(array( 'PassphraseCredentialDestroyController' => 'PassphraseController', 'PassphraseCredentialDestroyTransaction' => 'PassphraseCredentialTransactionType', 'PassphraseCredentialEditController' => 'PassphraseController', + 'PassphraseCredentialFerretDocument' => 'PhabricatorFerretDocument', + 'PassphraseCredentialFerretEngine' => 'PhabricatorFerretEngine', + 'PassphraseCredentialFerretField' => 'PhabricatorFerretField', + 'PassphraseCredentialFerretNgrams' => 'PhabricatorFerretNgrams', 'PassphraseCredentialFulltextEngine' => 'PhabricatorFulltextEngine', 'PassphraseCredentialListController' => 'PassphraseController', 'PassphraseCredentialLockController' => 'PassphraseController', diff --git a/src/applications/passphrase/query/PassphraseCredentialQuery.php b/src/applications/passphrase/query/PassphraseCredentialQuery.php index 3a78ac0d13..2518ad44e5 100644 --- a/src/applications/passphrase/query/PassphraseCredentialQuery.php +++ b/src/applications/passphrase/query/PassphraseCredentialQuery.php @@ -109,49 +109,49 @@ final class PassphraseCredentialQuery if ($this->ids !== null) { $where[] = qsprintf( $conn, - 'id IN (%Ld)', + 'c.id IN (%Ld)', $this->ids); } if ($this->phids !== null) { $where[] = qsprintf( $conn, - 'phid IN (%Ls)', + 'c.phid IN (%Ls)', $this->phids); } if ($this->credentialTypes !== null) { $where[] = qsprintf( $conn, - 'credentialType in (%Ls)', + 'c.credentialType in (%Ls)', $this->credentialTypes); } if ($this->providesTypes !== null) { $where[] = qsprintf( $conn, - 'providesType IN (%Ls)', + 'c.providesType IN (%Ls)', $this->providesTypes); } if ($this->isDestroyed !== null) { $where[] = qsprintf( $conn, - 'isDestroyed = %d', + 'c.isDestroyed = %d', (int)$this->isDestroyed); } if ($this->allowConduit !== null) { $where[] = qsprintf( $conn, - 'allowConduit = %d', + 'c.allowConduit = %d', (int)$this->allowConduit); } if (strlen($this->nameContains)) { $where[] = qsprintf( $conn, - 'LOWER(name) LIKE %~', + 'LOWER(c.name) LIKE %~', phutil_utf8_strtolower($this->nameContains)); } @@ -162,4 +162,8 @@ final class PassphraseCredentialQuery return 'PhabricatorPassphraseApplication'; } + protected function getPrimaryTableAlias() { + return 'c'; + } + } diff --git a/src/applications/passphrase/search/PassphraseCredentialFerretEngine.php b/src/applications/passphrase/search/PassphraseCredentialFerretEngine.php new file mode 100644 index 0000000000..3caba16371 --- /dev/null +++ b/src/applications/passphrase/search/PassphraseCredentialFerretEngine.php @@ -0,0 +1,22 @@ + Date: Thu, 7 Sep 2017 11:03:39 -0700 Subject: [PATCH 39/54] Reduce the amount of boilerplate that implementing FerretInterface requires Summary: See brief discussion in D18554. All the index tables are the same for every application (and, at this point, seem unlikely to change) and we never actually pass these objects around (they're only used internally). In some other cases (like Transactions) not every application has the same tables (for example, Differential has extra field for inline comments), and/or we pass the objects around (lots of stuff uses `$xactions` directly). However, in this case, and in Edges, we don't interact with any representation of the database state directly in much of the code, and it doesn't change from application to application. Just automatically define document, field, and ngram tables for anything which implements `FerretInterface`. This makes the query and index logic a tiny bit messier but lets us delete a ton of boilerplate classes. Test Plan: Indexed objects, searched for objects. Same results as before with much less code. Ran `bin/storage upgrade`, got a clean bill of health. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12819 Differential Revision: https://secure.phabricator.com/D18559 --- src/__phutil_library_map__.php | 36 ------ .../PhabricatorConfigCoreSchemaSpec.php | 8 ++ .../schema/PhabricatorConfigSchemaSpec.php | 20 ++++ .../DifferentialRevisionFerretEngine.php | 12 +- .../DifferentialRevisionFerretDocument.php | 14 --- .../DifferentialRevisionFerretField.php | 14 --- .../DifferentialRevisionFerretNgrams.php | 14 --- .../search/FundInitiativeFerretEngine.php | 12 +- .../storage/FundInitiativeFerretDocument.php | 14 --- .../storage/FundInitiativeFerretField.php | 14 --- .../storage/FundInitiativeFerretNgrams.php | 14 --- .../search/ManiphestTaskFerretEngine.php | 12 +- .../storage/ManiphestTaskFerretDocument.php | 14 --- .../storage/ManiphestTaskFerretField.php | 14 --- .../storage/ManiphestTaskFerretNgrams.php | 14 --- .../PassphraseCredentialFerretEngine.php | 12 +- .../PassphraseCredentialFerretDocument.php | 14 --- .../PassphraseCredentialFerretField.php | 14 --- .../PassphraseCredentialFerretNgrams.php | 14 --- .../search/PhabricatorUserFerretEngine.php | 12 +- .../storage/PhabricatorUserFerretDocument.php | 14 --- .../storage/PhabricatorUserFerretField.php | 14 --- .../storage/PhabricatorUserFerretNgrams.php | 14 --- ...abricatorFerretFulltextEngineExtension.php | 77 ++++++------ .../ferret/PhabricatorFerretDocument.php | 52 -------- .../search/ferret/PhabricatorFerretEngine.php | 112 +++++++++++++++++- .../search/ferret/PhabricatorFerretField.php | 39 ------ .../search/ferret/PhabricatorFerretNgrams.php | 35 ------ ...PhabricatorCursorPagedPolicyAwareQuery.php | 13 +- 29 files changed, 207 insertions(+), 455 deletions(-) delete mode 100644 src/applications/differential/storage/DifferentialRevisionFerretDocument.php delete mode 100644 src/applications/differential/storage/DifferentialRevisionFerretField.php delete mode 100644 src/applications/differential/storage/DifferentialRevisionFerretNgrams.php delete mode 100644 src/applications/fund/storage/FundInitiativeFerretDocument.php delete mode 100644 src/applications/fund/storage/FundInitiativeFerretField.php delete mode 100644 src/applications/fund/storage/FundInitiativeFerretNgrams.php delete mode 100644 src/applications/maniphest/storage/ManiphestTaskFerretDocument.php delete mode 100644 src/applications/maniphest/storage/ManiphestTaskFerretField.php delete mode 100644 src/applications/maniphest/storage/ManiphestTaskFerretNgrams.php delete mode 100644 src/applications/passphrase/storage/PassphraseCredentialFerretDocument.php delete mode 100644 src/applications/passphrase/storage/PassphraseCredentialFerretField.php delete mode 100644 src/applications/passphrase/storage/PassphraseCredentialFerretNgrams.php delete mode 100644 src/applications/people/storage/PhabricatorUserFerretDocument.php delete mode 100644 src/applications/people/storage/PhabricatorUserFerretField.php delete mode 100644 src/applications/people/storage/PhabricatorUserFerretNgrams.php delete mode 100644 src/applications/search/ferret/PhabricatorFerretDocument.php delete mode 100644 src/applications/search/ferret/PhabricatorFerretField.php delete mode 100644 src/applications/search/ferret/PhabricatorFerretNgrams.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 3e498d6273..1ffe418b5c 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -532,10 +532,7 @@ phutil_register_library_map(array( 'DifferentialRevisionEditConduitAPIMethod' => 'applications/differential/conduit/DifferentialRevisionEditConduitAPIMethod.php', 'DifferentialRevisionEditController' => 'applications/differential/controller/DifferentialRevisionEditController.php', 'DifferentialRevisionEditEngine' => 'applications/differential/editor/DifferentialRevisionEditEngine.php', - 'DifferentialRevisionFerretDocument' => 'applications/differential/storage/DifferentialRevisionFerretDocument.php', 'DifferentialRevisionFerretEngine' => 'applications/differential/search/DifferentialRevisionFerretEngine.php', - 'DifferentialRevisionFerretField' => 'applications/differential/storage/DifferentialRevisionFerretField.php', - 'DifferentialRevisionFerretNgrams' => 'applications/differential/storage/DifferentialRevisionFerretNgrams.php', 'DifferentialRevisionFulltextEngine' => 'applications/differential/search/DifferentialRevisionFulltextEngine.php', 'DifferentialRevisionGraph' => 'infrastructure/graph/DifferentialRevisionGraph.php', 'DifferentialRevisionHasChildRelationship' => 'applications/differential/relationships/DifferentialRevisionHasChildRelationship.php', @@ -1153,10 +1150,7 @@ phutil_register_library_map(array( 'FundInitiativeEditController' => 'applications/fund/controller/FundInitiativeEditController.php', 'FundInitiativeEditEngine' => 'applications/fund/editor/FundInitiativeEditEngine.php', 'FundInitiativeEditor' => 'applications/fund/editor/FundInitiativeEditor.php', - 'FundInitiativeFerretDocument' => 'applications/fund/storage/FundInitiativeFerretDocument.php', 'FundInitiativeFerretEngine' => 'applications/fund/search/FundInitiativeFerretEngine.php', - 'FundInitiativeFerretField' => 'applications/fund/storage/FundInitiativeFerretField.php', - 'FundInitiativeFerretNgrams' => 'applications/fund/storage/FundInitiativeFerretNgrams.php', 'FundInitiativeFulltextEngine' => 'applications/fund/search/FundInitiativeFulltextEngine.php', 'FundInitiativeListController' => 'applications/fund/controller/FundInitiativeListController.php', 'FundInitiativeMerchantTransaction' => 'applications/fund/xaction/FundInitiativeMerchantTransaction.php', @@ -1539,10 +1533,7 @@ phutil_register_library_map(array( 'ManiphestTaskEditBulkJobType' => 'applications/maniphest/bulk/ManiphestTaskEditBulkJobType.php', 'ManiphestTaskEditController' => 'applications/maniphest/controller/ManiphestTaskEditController.php', 'ManiphestTaskEditEngineLock' => 'applications/maniphest/editor/ManiphestTaskEditEngineLock.php', - 'ManiphestTaskFerretDocument' => 'applications/maniphest/storage/ManiphestTaskFerretDocument.php', 'ManiphestTaskFerretEngine' => 'applications/maniphest/search/ManiphestTaskFerretEngine.php', - 'ManiphestTaskFerretField' => 'applications/maniphest/storage/ManiphestTaskFerretField.php', - 'ManiphestTaskFerretNgrams' => 'applications/maniphest/storage/ManiphestTaskFerretNgrams.php', 'ManiphestTaskFulltextEngine' => 'applications/maniphest/search/ManiphestTaskFulltextEngine.php', 'ManiphestTaskGraph' => 'infrastructure/graph/ManiphestTaskGraph.php', 'ManiphestTaskHasCommitEdgeType' => 'applications/maniphest/edge/ManiphestTaskHasCommitEdgeType.php', @@ -1840,10 +1831,7 @@ phutil_register_library_map(array( 'PassphraseCredentialDestroyController' => 'applications/passphrase/controller/PassphraseCredentialDestroyController.php', 'PassphraseCredentialDestroyTransaction' => 'applications/passphrase/xaction/PassphraseCredentialDestroyTransaction.php', 'PassphraseCredentialEditController' => 'applications/passphrase/controller/PassphraseCredentialEditController.php', - 'PassphraseCredentialFerretDocument' => 'applications/passphrase/storage/PassphraseCredentialFerretDocument.php', 'PassphraseCredentialFerretEngine' => 'applications/passphrase/search/PassphraseCredentialFerretEngine.php', - 'PassphraseCredentialFerretField' => 'applications/passphrase/storage/PassphraseCredentialFerretField.php', - 'PassphraseCredentialFerretNgrams' => 'applications/passphrase/storage/PassphraseCredentialFerretNgrams.php', 'PassphraseCredentialFulltextEngine' => 'applications/passphrase/search/PassphraseCredentialFulltextEngine.php', 'PassphraseCredentialListController' => 'applications/passphrase/controller/PassphraseCredentialListController.php', 'PassphraseCredentialLockController' => 'applications/passphrase/controller/PassphraseCredentialLockController.php', @@ -2841,15 +2829,12 @@ phutil_register_library_map(array( 'PhabricatorFeedStoryNotification' => 'applications/notification/storage/PhabricatorFeedStoryNotification.php', 'PhabricatorFeedStoryPublisher' => 'applications/feed/PhabricatorFeedStoryPublisher.php', 'PhabricatorFeedStoryReference' => 'applications/feed/storage/PhabricatorFeedStoryReference.php', - 'PhabricatorFerretDocument' => 'applications/search/ferret/PhabricatorFerretDocument.php', 'PhabricatorFerretEngine' => 'applications/search/ferret/PhabricatorFerretEngine.php', 'PhabricatorFerretEngineTestCase' => 'applications/search/ferret/__tests__/PhabricatorFerretEngineTestCase.php', - 'PhabricatorFerretField' => 'applications/search/ferret/PhabricatorFerretField.php', 'PhabricatorFerretFulltextEngineExtension' => 'applications/search/engineextension/PhabricatorFerretFulltextEngineExtension.php', 'PhabricatorFerretFulltextStorageEngine' => 'applications/search/fulltextstorage/PhabricatorFerretFulltextStorageEngine.php', 'PhabricatorFerretInterface' => 'applications/search/ferret/PhabricatorFerretInterface.php', 'PhabricatorFerretMetadata' => 'applications/search/ferret/PhabricatorFerretMetadata.php', - 'PhabricatorFerretNgrams' => 'applications/search/ferret/PhabricatorFerretNgrams.php', 'PhabricatorFerretSearchEngineExtension' => 'applications/search/engineextension/PhabricatorFerretSearchEngineExtension.php', 'PhabricatorFile' => 'applications/files/storage/PhabricatorFile.php', 'PhabricatorFileAES256StorageFormat' => 'applications/files/format/PhabricatorFileAES256StorageFormat.php', @@ -4265,10 +4250,7 @@ phutil_register_library_map(array( 'PhabricatorUserEditorTestCase' => 'applications/people/editor/__tests__/PhabricatorUserEditorTestCase.php', 'PhabricatorUserEmail' => 'applications/people/storage/PhabricatorUserEmail.php', 'PhabricatorUserEmailTestCase' => 'applications/people/storage/__tests__/PhabricatorUserEmailTestCase.php', - 'PhabricatorUserFerretDocument' => 'applications/people/storage/PhabricatorUserFerretDocument.php', 'PhabricatorUserFerretEngine' => 'applications/people/search/PhabricatorUserFerretEngine.php', - 'PhabricatorUserFerretField' => 'applications/people/storage/PhabricatorUserFerretField.php', - 'PhabricatorUserFerretNgrams' => 'applications/people/storage/PhabricatorUserFerretNgrams.php', 'PhabricatorUserFulltextEngine' => 'applications/people/search/PhabricatorUserFulltextEngine.php', 'PhabricatorUserIconField' => 'applications/people/customfield/PhabricatorUserIconField.php', 'PhabricatorUserLog' => 'applications/people/storage/PhabricatorUserLog.php', @@ -5564,10 +5546,7 @@ phutil_register_library_map(array( 'DifferentialRevisionEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', 'DifferentialRevisionEditController' => 'DifferentialController', 'DifferentialRevisionEditEngine' => 'PhabricatorEditEngine', - 'DifferentialRevisionFerretDocument' => 'PhabricatorFerretDocument', 'DifferentialRevisionFerretEngine' => 'PhabricatorFerretEngine', - 'DifferentialRevisionFerretField' => 'PhabricatorFerretField', - 'DifferentialRevisionFerretNgrams' => 'PhabricatorFerretNgrams', 'DifferentialRevisionFulltextEngine' => 'PhabricatorFulltextEngine', 'DifferentialRevisionGraph' => 'PhabricatorObjectGraph', 'DifferentialRevisionHasChildRelationship' => 'DifferentialRevisionRelationship', @@ -6248,10 +6227,7 @@ phutil_register_library_map(array( 'FundInitiativeEditController' => 'FundController', 'FundInitiativeEditEngine' => 'PhabricatorEditEngine', 'FundInitiativeEditor' => 'PhabricatorApplicationTransactionEditor', - 'FundInitiativeFerretDocument' => 'PhabricatorFerretDocument', 'FundInitiativeFerretEngine' => 'PhabricatorFerretEngine', - 'FundInitiativeFerretField' => 'PhabricatorFerretField', - 'FundInitiativeFerretNgrams' => 'PhabricatorFerretNgrams', 'FundInitiativeFulltextEngine' => 'PhabricatorFulltextEngine', 'FundInitiativeListController' => 'FundController', 'FundInitiativeMerchantTransaction' => 'FundInitiativeTransactionType', @@ -6719,10 +6695,7 @@ phutil_register_library_map(array( 'ManiphestTaskEditBulkJobType' => 'PhabricatorWorkerBulkJobType', 'ManiphestTaskEditController' => 'ManiphestController', 'ManiphestTaskEditEngineLock' => 'PhabricatorEditEngineLock', - 'ManiphestTaskFerretDocument' => 'PhabricatorFerretDocument', 'ManiphestTaskFerretEngine' => 'PhabricatorFerretEngine', - 'ManiphestTaskFerretField' => 'PhabricatorFerretField', - 'ManiphestTaskFerretNgrams' => 'PhabricatorFerretNgrams', 'ManiphestTaskFulltextEngine' => 'PhabricatorFulltextEngine', 'ManiphestTaskGraph' => 'PhabricatorObjectGraph', 'ManiphestTaskHasCommitEdgeType' => 'PhabricatorEdgeType', @@ -7049,10 +7022,7 @@ phutil_register_library_map(array( 'PassphraseCredentialDestroyController' => 'PassphraseController', 'PassphraseCredentialDestroyTransaction' => 'PassphraseCredentialTransactionType', 'PassphraseCredentialEditController' => 'PassphraseController', - 'PassphraseCredentialFerretDocument' => 'PhabricatorFerretDocument', 'PassphraseCredentialFerretEngine' => 'PhabricatorFerretEngine', - 'PassphraseCredentialFerretField' => 'PhabricatorFerretField', - 'PassphraseCredentialFerretNgrams' => 'PhabricatorFerretNgrams', 'PassphraseCredentialFulltextEngine' => 'PhabricatorFulltextEngine', 'PassphraseCredentialListController' => 'PassphraseController', 'PassphraseCredentialLockController' => 'PassphraseController', @@ -8192,14 +8162,11 @@ phutil_register_library_map(array( 'PhabricatorFeedStoryNotification' => 'PhabricatorFeedDAO', 'PhabricatorFeedStoryPublisher' => 'Phobject', 'PhabricatorFeedStoryReference' => 'PhabricatorFeedDAO', - 'PhabricatorFerretDocument' => 'PhabricatorSearchDAO', 'PhabricatorFerretEngine' => 'Phobject', 'PhabricatorFerretEngineTestCase' => 'PhabricatorTestCase', - 'PhabricatorFerretField' => 'PhabricatorSearchDAO', 'PhabricatorFerretFulltextEngineExtension' => 'PhabricatorFulltextEngineExtension', 'PhabricatorFerretFulltextStorageEngine' => 'PhabricatorFulltextStorageEngine', 'PhabricatorFerretMetadata' => 'Phobject', - 'PhabricatorFerretNgrams' => 'PhabricatorSearchDAO', 'PhabricatorFerretSearchEngineExtension' => 'PhabricatorSearchEngineExtension', 'PhabricatorFile' => array( 'PhabricatorFileDAO', @@ -9885,10 +9852,7 @@ phutil_register_library_map(array( 'PhabricatorUserEditorTestCase' => 'PhabricatorTestCase', 'PhabricatorUserEmail' => 'PhabricatorUserDAO', 'PhabricatorUserEmailTestCase' => 'PhabricatorTestCase', - 'PhabricatorUserFerretDocument' => 'PhabricatorFerretDocument', 'PhabricatorUserFerretEngine' => 'PhabricatorFerretEngine', - 'PhabricatorUserFerretField' => 'PhabricatorFerretField', - 'PhabricatorUserFerretNgrams' => 'PhabricatorFerretNgrams', 'PhabricatorUserFulltextEngine' => 'PhabricatorFulltextEngine', 'PhabricatorUserIconField' => 'PhabricatorUserCustomField', 'PhabricatorUserLog' => array( diff --git a/src/applications/config/schema/PhabricatorConfigCoreSchemaSpec.php b/src/applications/config/schema/PhabricatorConfigCoreSchemaSpec.php index 4219ad2cb4..0d8d743649 100644 --- a/src/applications/config/schema/PhabricatorConfigCoreSchemaSpec.php +++ b/src/applications/config/schema/PhabricatorConfigCoreSchemaSpec.php @@ -42,5 +42,13 @@ final class PhabricatorConfigCoreSchemaSpec )); } + $ferret_objects = id(new PhutilClassMapQuery()) + ->setAncestorClass('PhabricatorFerretInterface') + ->execute(); + + foreach ($ferret_objects as $ferret_object) { + $engine = $ferret_object->newFerretEngine(); + $this->buildFerretIndexSchema($engine); + } } } diff --git a/src/applications/config/schema/PhabricatorConfigSchemaSpec.php b/src/applications/config/schema/PhabricatorConfigSchemaSpec.php index 49a99ab03a..b24adf27cd 100644 --- a/src/applications/config/schema/PhabricatorConfigSchemaSpec.php +++ b/src/applications/config/schema/PhabricatorConfigSchemaSpec.php @@ -55,6 +55,26 @@ abstract class PhabricatorConfigSchemaSpec extends Phobject { $object->getSchemaKeys()); } + protected function buildFerretIndexSchema(PhabricatorFerretEngine $engine) { + $this->buildRawSchema( + $engine->getApplicationName(), + $engine->getDocumentTableName(), + $engine->getDocumentSchemaColumns(), + $engine->getDocumentSchemaKeys()); + + $this->buildRawSchema( + $engine->getApplicationName(), + $engine->getFieldTableName(), + $engine->getFieldSchemaColumns(), + $engine->getFieldSchemaKeys()); + + $this->buildRawSchema( + $engine->getApplicationName(), + $engine->getNgramsTableName(), + $engine->getNgramsSchemaColumns(), + $engine->getNgramsSchemaKeys()); + } + protected function buildRawSchema( $database_name, $table_name, diff --git a/src/applications/differential/search/DifferentialRevisionFerretEngine.php b/src/applications/differential/search/DifferentialRevisionFerretEngine.php index ebe59c2780..2fc7d5905e 100644 --- a/src/applications/differential/search/DifferentialRevisionFerretEngine.php +++ b/src/applications/differential/search/DifferentialRevisionFerretEngine.php @@ -3,16 +3,12 @@ final class DifferentialRevisionFerretEngine extends PhabricatorFerretEngine { - public function newNgramsObject() { - return new DifferentialRevisionFerretNgrams(); + public function getApplicationName() { + return 'differential'; } - public function newDocumentObject() { - return new DifferentialRevisionFerretDocument(); - } - - public function newFieldObject() { - return new DifferentialRevisionFerretField(); + public function getScopeName() { + return 'revision'; } public function newSearchEngine() { diff --git a/src/applications/differential/storage/DifferentialRevisionFerretDocument.php b/src/applications/differential/storage/DifferentialRevisionFerretDocument.php deleted file mode 100644 index ae8571f625..0000000000 --- a/src/applications/differential/storage/DifferentialRevisionFerretDocument.php +++ /dev/null @@ -1,14 +0,0 @@ -newDocumentObject() - ->setObjectPHID($phid) - ->setIsClosed($is_closed) - ->setEpochCreated($document->getDocumentCreated()) - ->setEpochModified($document->getDocumentModified()) - ->setAuthorPHID($author_phid) - ->setOwnerPHID($owner_phid); - $stemmer = $engine->newStemmer(); // Copy all of the "title" and "body" fields to create new "core" fields. @@ -133,33 +125,49 @@ final class PhabricatorFerretFulltextEngineExtension $ngrams_source[] = $term_corpus; } - $ferret_fields[] = $engine->newFieldObject() - ->setFieldKey($key) - ->setRawCorpus($raw_corpus) - ->setTermCorpus($term_corpus) - ->setNormalCorpus($normal_corpus); + $ferret_fields[] = array( + 'fieldKey' => $key, + 'rawCorpus' => $raw_corpus, + 'termCorpus' => $term_corpus, + 'normalCorpus' => $normal_corpus, + ); } $ngrams_source = implode("\n", $ngrams_source); $ngrams = $engine->getTermNgramsFromString($ngrams_source); - $ferret_document->openTransaction(); + $object->openTransaction(); try { + $conn = $object->establishConnection('w'); $this->deleteOldDocument($engine, $object, $document); - $ferret_document->save(); + queryfx( + $conn, + 'INSERT INTO %T (objectPHID, isClosed, epochCreated, epochModified, + authorPHID, ownerPHID) VALUES (%s, %d, %d, %d, %ns, %ns)', + $engine->getDocumentTableName(), + $object->getPHID(), + $is_closed, + $document->getDocumentCreated(), + $document->getDocumentModified(), + $author_phid, + $owner_phid); - $document_id = $ferret_document->getID(); + $document_id = $conn->getInsertID(); foreach ($ferret_fields as $ferret_field) { - $ferret_field - ->setDocumentID($document_id) - ->save(); + queryfx( + $conn, + 'INSERT INTO %T (documentID, fieldKey, rawCorpus, termCorpus, + normalCorpus) VALUES (%d, %s, %s, %s, %s)', + $engine->getFieldTableName(), + $document_id, + $ferret_field['fieldKey'], + $ferret_field['rawCorpus'], + $ferret_field['termCorpus'], + $ferret_field['normalCorpus']); } - $ferret_ngrams = $engine->newNgramsObject(); - $conn = $ferret_ngrams->establishConnection('w'); - $sql = array(); foreach ($ngrams as $ngram) { $sql[] = qsprintf( @@ -173,15 +181,15 @@ final class PhabricatorFerretFulltextEngineExtension queryfx( $conn, 'INSERT INTO %T (documentID, ngram) VALUES %Q', - $ferret_ngrams->getTableName(), + $engine->getNgramsTableName(), $chunk); } } catch (Exception $ex) { - $ferret_document->killTransaction(); + $object->killTransaction(); throw $ex; } - $ferret_document->saveTransaction(); + $object->saveTransaction(); } @@ -190,32 +198,35 @@ final class PhabricatorFerretFulltextEngineExtension $object, PhabricatorSearchAbstractDocument $document) { - $old_document = $engine->newDocumentObject()->loadOneWhere( - 'objectPHID = %s', - $document->getPHID()); + $conn = $object->establishConnection('w'); + + $old_document = queryfx_one( + $conn, + 'SELECT * FROM %T WHERE objectPHID = %s', + $engine->getDocumentTableName(), + $object->getPHID()); if (!$old_document) { return; } - $conn = $old_document->establishConnection('w'); - $old_id = $old_document->getID(); + $old_id = $old_document['id']; queryfx( $conn, 'DELETE FROM %T WHERE id = %d', - $engine->newDocumentObject()->getTableName(), + $engine->getDocumentTableName(), $old_id); queryfx( $conn, 'DELETE FROM %T WHERE documentID = %d', - $engine->newFieldObject()->getTableName(), + $engine->getFieldTableName(), $old_id); queryfx( $conn, 'DELETE FROM %T WHERE documentID = %d', - $engine->newNgramsObject()->getTableName(), + $engine->getNgramsTableName(), $old_id); } diff --git a/src/applications/search/ferret/PhabricatorFerretDocument.php b/src/applications/search/ferret/PhabricatorFerretDocument.php deleted file mode 100644 index 6f25eb93b6..0000000000 --- a/src/applications/search/ferret/PhabricatorFerretDocument.php +++ /dev/null @@ -1,52 +0,0 @@ - false, - self::CONFIG_COLUMN_SCHEMA => array( - 'isClosed' => 'bool', - 'authorPHID' => 'phid?', - 'ownerPHID' => 'phid?', - 'epochCreated' => 'epoch', - 'epochModified' => 'epoch', - ), - self::CONFIG_KEY_SCHEMA => array( - 'key_object' => array( - 'columns' => array('objectPHID'), - 'unique' => true, - ), - 'key_author' => array( - 'columns' => array('authorPHID'), - ), - 'key_owner' => array( - 'columns' => array('ownerPHID'), - ), - 'key_created' => array( - 'columns' => array('epochCreated'), - ), - 'key_modified' => array( - 'columns' => array('epochModified'), - ), - ), - ) + parent::getConfiguration(); - } - - public function getTableName() { - $application = $this->getApplicationName(); - $key = $this->getIndexKey(); - return "{$application}_{$key}_fdocument"; - } - -} diff --git a/src/applications/search/ferret/PhabricatorFerretEngine.php b/src/applications/search/ferret/PhabricatorFerretEngine.php index eb40b70e58..219130c02c 100644 --- a/src/applications/search/ferret/PhabricatorFerretEngine.php +++ b/src/applications/search/ferret/PhabricatorFerretEngine.php @@ -2,9 +2,8 @@ abstract class PhabricatorFerretEngine extends Phobject { - abstract public function newNgramsObject(); - abstract public function newDocumentObject(); - abstract public function newFieldObject(); + abstract public function getApplicationName(); + abstract public function getScopeName(); abstract public function newSearchEngine(); public function getDefaultFunctionKey() { @@ -168,4 +167,111 @@ abstract class PhabricatorFerretEngine extends Phobject { return $term_corpus; } +/* -( Schema )------------------------------------------------------------- */ + + public function getDocumentTableName() { + $application = $this->getApplicationName(); + $scope = $this->getScopeName(); + + return "{$application}_{$scope}_fdocument"; + } + + public function getDocumentSchemaColumns() { + return array( + 'id' => 'auto', + 'objectPHID' => 'phid', + 'isClosed' => 'bool', + 'authorPHID' => 'phid?', + 'ownerPHID' => 'phid?', + 'epochCreated' => 'epoch', + 'epochModified' => 'epoch', + ); + } + + public function getDocumentSchemaKeys() { + return array( + 'PRIMARY' => array( + 'columns' => array('id'), + 'unique' => true, + ), + 'key_object' => array( + 'columns' => array('objectPHID'), + 'unique' => true, + ), + 'key_author' => array( + 'columns' => array('authorPHID'), + ), + 'key_owner' => array( + 'columns' => array('ownerPHID'), + ), + 'key_created' => array( + 'columns' => array('epochCreated'), + ), + 'key_modified' => array( + 'columns' => array('epochModified'), + ), + ); + } + + public function getFieldTableName() { + $application = $this->getApplicationName(); + $scope = $this->getScopeName(); + + return "{$application}_{$scope}_ffield"; + } + + public function getFieldSchemaColumns() { + return array( + 'id' => 'auto', + 'documentID' => 'uint32', + 'fieldKey' => 'text4', + 'rawCorpus' => 'sort', + 'termCorpus' => 'sort', + 'normalCorpus' => 'sort', + ); + } + + public function getFieldSchemaKeys() { + return array( + 'PRIMARY' => array( + 'columns' => array('id'), + 'unique' => true, + ), + 'key_documentfield' => array( + 'columns' => array('documentID', 'fieldKey'), + 'unique' => true, + ), + ); + } + + public function getNgramsTableName() { + $application = $this->getApplicationName(); + $scope = $this->getScopeName(); + + return "{$application}_{$scope}_fngrams"; + } + + public function getNgramsSchemaColumns() { + return array( + 'id' => 'auto', + 'documentID' => 'uint32', + 'ngram' => 'char3', + ); + } + + public function getNgramsSchemaKeys() { + return array( + 'PRIMARY' => array( + 'columns' => array('id'), + 'unique' => true, + ), + 'key_ngram' => array( + 'columns' => array('ngram', 'documentID'), + ), + 'key_object' => array( + 'columns' => array('documentID'), + ), + ); + } + } diff --git a/src/applications/search/ferret/PhabricatorFerretField.php b/src/applications/search/ferret/PhabricatorFerretField.php deleted file mode 100644 index be39e745ed..0000000000 --- a/src/applications/search/ferret/PhabricatorFerretField.php +++ /dev/null @@ -1,39 +0,0 @@ - false, - self::CONFIG_COLUMN_SCHEMA => array( - 'documentID' => 'uint32', - 'fieldKey' => 'text4', - 'rawCorpus' => 'sort', - 'termCorpus' => 'sort', - 'normalCorpus' => 'sort', - ), - self::CONFIG_KEY_SCHEMA => array( - 'key_documentfield' => array( - 'columns' => array('documentID', 'fieldKey'), - 'unique' => true, - ), - ), - ) + parent::getConfiguration(); - } - - public function getTableName() { - $application = $this->getApplicationName(); - $key = $this->getIndexKey(); - return "{$application}_{$key}_ffield"; - } - -} diff --git a/src/applications/search/ferret/PhabricatorFerretNgrams.php b/src/applications/search/ferret/PhabricatorFerretNgrams.php deleted file mode 100644 index 9e28f96cb6..0000000000 --- a/src/applications/search/ferret/PhabricatorFerretNgrams.php +++ /dev/null @@ -1,35 +0,0 @@ - false, - self::CONFIG_COLUMN_SCHEMA => array( - 'documentID' => 'uint32', - 'ngram' => 'char3', - ), - self::CONFIG_KEY_SCHEMA => array( - 'key_ngram' => array( - 'columns' => array('ngram', 'documentID'), - ), - 'key_object' => array( - 'columns' => array('documentID'), - ), - ), - ) + parent::getConfiguration(); - } - - public function getTableName() { - $application = $this->getApplicationName(); - $key = $this->getIndexKey(); - return "{$application}_{$key}_fngrams"; - } - -} diff --git a/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php b/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php index 42e6ed7b4e..18e860ebb9 100644 --- a/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php +++ b/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php @@ -1623,8 +1623,7 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery $engine = $this->ferretEngine; $stemmer = $engine->newStemmer(); - $ngram_table = $engine->newNgramsObject(); - $ngram_table_name = $ngram_table->getTableName(); + $ngram_table = $engine->getNgramsTableName(); $flat = array(); foreach ($this->ferretTokens as $fulltext_token) { @@ -1680,7 +1679,7 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery foreach ($ngrams as $ngram) { $flat[] = array( - 'table' => $ngram_table_name, + 'table' => $ngram_table, 'ngram' => $ngram, ); } @@ -1702,14 +1701,14 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery $phid_column = qsprintf($conn, '%T', 'phid'); } - $document_table = $engine->newDocumentObject(); - $field_table = $engine->newFieldObject(); + $document_table = $engine->getDocumentTableName(); + $field_table = $engine->getFieldTableName(); $joins = array(); $joins[] = qsprintf( $conn, 'JOIN %T ft_doc ON ft_doc.objectPHID = %Q', - $document_table->getTableName(), + $document_table, $phid_column); $idx = 1; @@ -1736,7 +1735,7 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery $conn, 'JOIN %T %T ON ft_doc.id = %T.documentID AND %T.fieldKey = %s', - $field_table->getTableName(), + $field_table, $alias, $alias, $alias, From c9152b586b64a2e9f552f6f5348126b64a9adce8 Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 7 Sep 2017 12:02:53 -0700 Subject: [PATCH 40/54] Support Ferret engine in Owners Summary: Ref T12819. Same deal as before, but smaller diffs after D18559. Test Plan: Indexed and searched for packages. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12819 Differential Revision: https://secure.phabricator.com/D18564 --- .../20170907.ferret.10.owners.doc.sql | 9 +++++++++ .../20170907.ferret.11.owners.field.sql | 8 ++++++++ .../20170907.ferret.12.owners.ngrams.sql | 5 +++++ src/__phutil_library_map__.php | 5 ++++- .../PhabricatorOwnersPackageFerretEngine.php | 18 ++++++++++++++++++ .../PhabricatorOwnersPackageFulltextEngine.php | 0 .../storage/PhabricatorOwnersPackage.php | 9 +++++++++ 7 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 resources/sql/autopatches/20170907.ferret.10.owners.doc.sql create mode 100644 resources/sql/autopatches/20170907.ferret.11.owners.field.sql create mode 100644 resources/sql/autopatches/20170907.ferret.12.owners.ngrams.sql create mode 100644 src/applications/owners/search/PhabricatorOwnersPackageFerretEngine.php rename src/applications/owners/{query => search}/PhabricatorOwnersPackageFulltextEngine.php (100%) diff --git a/resources/sql/autopatches/20170907.ferret.10.owners.doc.sql b/resources/sql/autopatches/20170907.ferret.10.owners.doc.sql new file mode 100644 index 0000000000..aaaa36623b --- /dev/null +++ b/resources/sql/autopatches/20170907.ferret.10.owners.doc.sql @@ -0,0 +1,9 @@ +CREATE TABLE {$NAMESPACE}_owners.owners_package_fdocument ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + objectPHID VARBINARY(64) NOT NULL, + isClosed BOOL NOT NULL, + authorPHID VARBINARY(64), + ownerPHID VARBINARY(64), + epochCreated INT UNSIGNED NOT NULL, + epochModified INT UNSIGNED NOT NULL +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/resources/sql/autopatches/20170907.ferret.11.owners.field.sql b/resources/sql/autopatches/20170907.ferret.11.owners.field.sql new file mode 100644 index 0000000000..ebd72806f4 --- /dev/null +++ b/resources/sql/autopatches/20170907.ferret.11.owners.field.sql @@ -0,0 +1,8 @@ +CREATE TABLE {$NAMESPACE}_owners.owners_package_ffield ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + documentID INT UNSIGNED NOT NULL, + fieldKey VARCHAR(4) NOT NULL COLLATE {$COLLATE_TEXT}, + rawCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT}, + termCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT}, + normalCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT} +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/resources/sql/autopatches/20170907.ferret.12.owners.ngrams.sql b/resources/sql/autopatches/20170907.ferret.12.owners.ngrams.sql new file mode 100644 index 0000000000..0f8c6865bf --- /dev/null +++ b/resources/sql/autopatches/20170907.ferret.12.owners.ngrams.sql @@ -0,0 +1,5 @@ +CREATE TABLE {$NAMESPACE}_owners.owners_package_fngrams ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + documentID INT UNSIGNED NOT NULL, + ngram CHAR(3) NOT NULL COLLATE {$COLLATE_TEXT} +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 1ffe418b5c..266993bfb7 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -3317,7 +3317,8 @@ phutil_register_library_map(array( 'PhabricatorOwnersPackageDescriptionTransaction' => 'applications/owners/xaction/PhabricatorOwnersPackageDescriptionTransaction.php', 'PhabricatorOwnersPackageDominionTransaction' => 'applications/owners/xaction/PhabricatorOwnersPackageDominionTransaction.php', 'PhabricatorOwnersPackageEditEngine' => 'applications/owners/editor/PhabricatorOwnersPackageEditEngine.php', - 'PhabricatorOwnersPackageFulltextEngine' => 'applications/owners/query/PhabricatorOwnersPackageFulltextEngine.php', + 'PhabricatorOwnersPackageFerretEngine' => 'applications/owners/search/PhabricatorOwnersPackageFerretEngine.php', + 'PhabricatorOwnersPackageFulltextEngine' => 'applications/owners/search/PhabricatorOwnersPackageFulltextEngine.php', 'PhabricatorOwnersPackageFunctionDatasource' => 'applications/owners/typeahead/PhabricatorOwnersPackageFunctionDatasource.php', 'PhabricatorOwnersPackageNameNgrams' => 'applications/owners/storage/PhabricatorOwnersPackageNameNgrams.php', 'PhabricatorOwnersPackageNameTransaction' => 'applications/owners/xaction/PhabricatorOwnersPackageNameTransaction.php', @@ -8714,6 +8715,7 @@ phutil_register_library_map(array( 'PhabricatorDestructibleInterface', 'PhabricatorConduitResultInterface', 'PhabricatorFulltextInterface', + 'PhabricatorFerretInterface', 'PhabricatorNgramsInterface', ), 'PhabricatorOwnersPackageAuditingTransaction' => 'PhabricatorOwnersPackageTransactionType', @@ -8723,6 +8725,7 @@ phutil_register_library_map(array( 'PhabricatorOwnersPackageDescriptionTransaction' => 'PhabricatorOwnersPackageTransactionType', 'PhabricatorOwnersPackageDominionTransaction' => 'PhabricatorOwnersPackageTransactionType', 'PhabricatorOwnersPackageEditEngine' => 'PhabricatorEditEngine', + 'PhabricatorOwnersPackageFerretEngine' => 'PhabricatorFerretEngine', 'PhabricatorOwnersPackageFulltextEngine' => 'PhabricatorFulltextEngine', 'PhabricatorOwnersPackageFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'PhabricatorOwnersPackageNameNgrams' => 'PhabricatorSearchNgrams', diff --git a/src/applications/owners/search/PhabricatorOwnersPackageFerretEngine.php b/src/applications/owners/search/PhabricatorOwnersPackageFerretEngine.php new file mode 100644 index 0000000000..684fe10969 --- /dev/null +++ b/src/applications/owners/search/PhabricatorOwnersPackageFerretEngine.php @@ -0,0 +1,18 @@ + Date: Thu, 7 Sep 2017 12:14:05 -0700 Subject: [PATCH 41/54] Support Ferret engine in Phame Summary: Ref T12819. Mostly straightforward, with a couple of minor query modernization things. Test Plan: Indexed and searched for posts and blogs. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12819 Differential Revision: https://secure.phabricator.com/D18565 --- .../20170907.ferret.13.blog.doc.sql | 9 +++++++ .../20170907.ferret.14.blog.field.sql | 8 ++++++ .../20170907.ferret.15.blog.ngrams.sql | 5 ++++ .../20170907.ferret.16.post.doc.sql | 9 +++++++ .../20170907.ferret.17.post.field.sql | 8 ++++++ .../20170907.ferret.18.post.ngrams.sql | 5 ++++ src/__phutil_library_map__.php | 6 +++++ .../phame/query/PhameBlogQuery.php | 12 ++++++--- .../phame/query/PhamePostQuery.php | 25 +++++++++++-------- .../phame/search/PhameBlogFerretEngine.php | 18 +++++++++++++ .../phame/search/PhamePostFerretEngine.php | 18 +++++++++++++ src/applications/phame/storage/PhameBlog.php | 11 +++++++- src/applications/phame/storage/PhamePost.php | 11 +++++++- 13 files changed, 129 insertions(+), 16 deletions(-) create mode 100644 resources/sql/autopatches/20170907.ferret.13.blog.doc.sql create mode 100644 resources/sql/autopatches/20170907.ferret.14.blog.field.sql create mode 100644 resources/sql/autopatches/20170907.ferret.15.blog.ngrams.sql create mode 100644 resources/sql/autopatches/20170907.ferret.16.post.doc.sql create mode 100644 resources/sql/autopatches/20170907.ferret.17.post.field.sql create mode 100644 resources/sql/autopatches/20170907.ferret.18.post.ngrams.sql create mode 100644 src/applications/phame/search/PhameBlogFerretEngine.php create mode 100644 src/applications/phame/search/PhamePostFerretEngine.php diff --git a/resources/sql/autopatches/20170907.ferret.13.blog.doc.sql b/resources/sql/autopatches/20170907.ferret.13.blog.doc.sql new file mode 100644 index 0000000000..d75232fae1 --- /dev/null +++ b/resources/sql/autopatches/20170907.ferret.13.blog.doc.sql @@ -0,0 +1,9 @@ +CREATE TABLE {$NAMESPACE}_phame.phame_blog_fdocument ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + objectPHID VARBINARY(64) NOT NULL, + isClosed BOOL NOT NULL, + authorPHID VARBINARY(64), + ownerPHID VARBINARY(64), + epochCreated INT UNSIGNED NOT NULL, + epochModified INT UNSIGNED NOT NULL +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/resources/sql/autopatches/20170907.ferret.14.blog.field.sql b/resources/sql/autopatches/20170907.ferret.14.blog.field.sql new file mode 100644 index 0000000000..9982914229 --- /dev/null +++ b/resources/sql/autopatches/20170907.ferret.14.blog.field.sql @@ -0,0 +1,8 @@ +CREATE TABLE {$NAMESPACE}_phame.phame_blog_ffield ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + documentID INT UNSIGNED NOT NULL, + fieldKey VARCHAR(4) NOT NULL COLLATE {$COLLATE_TEXT}, + rawCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT}, + termCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT}, + normalCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT} +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/resources/sql/autopatches/20170907.ferret.15.blog.ngrams.sql b/resources/sql/autopatches/20170907.ferret.15.blog.ngrams.sql new file mode 100644 index 0000000000..b20bb8fcbb --- /dev/null +++ b/resources/sql/autopatches/20170907.ferret.15.blog.ngrams.sql @@ -0,0 +1,5 @@ +CREATE TABLE {$NAMESPACE}_phame.phame_blog_fngrams ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + documentID INT UNSIGNED NOT NULL, + ngram CHAR(3) NOT NULL COLLATE {$COLLATE_TEXT} +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/resources/sql/autopatches/20170907.ferret.16.post.doc.sql b/resources/sql/autopatches/20170907.ferret.16.post.doc.sql new file mode 100644 index 0000000000..9f9155aa49 --- /dev/null +++ b/resources/sql/autopatches/20170907.ferret.16.post.doc.sql @@ -0,0 +1,9 @@ +CREATE TABLE {$NAMESPACE}_phame.phame_post_fdocument ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + objectPHID VARBINARY(64) NOT NULL, + isClosed BOOL NOT NULL, + authorPHID VARBINARY(64), + ownerPHID VARBINARY(64), + epochCreated INT UNSIGNED NOT NULL, + epochModified INT UNSIGNED NOT NULL +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/resources/sql/autopatches/20170907.ferret.17.post.field.sql b/resources/sql/autopatches/20170907.ferret.17.post.field.sql new file mode 100644 index 0000000000..26d729d05d --- /dev/null +++ b/resources/sql/autopatches/20170907.ferret.17.post.field.sql @@ -0,0 +1,8 @@ +CREATE TABLE {$NAMESPACE}_phame.phame_post_ffield ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + documentID INT UNSIGNED NOT NULL, + fieldKey VARCHAR(4) NOT NULL COLLATE {$COLLATE_TEXT}, + rawCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT}, + termCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT}, + normalCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT} +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/resources/sql/autopatches/20170907.ferret.18.post.ngrams.sql b/resources/sql/autopatches/20170907.ferret.18.post.ngrams.sql new file mode 100644 index 0000000000..18e534e948 --- /dev/null +++ b/resources/sql/autopatches/20170907.ferret.18.post.ngrams.sql @@ -0,0 +1,5 @@ +CREATE TABLE {$NAMESPACE}_phame.phame_post_fngrams ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + documentID INT UNSIGNED NOT NULL, + ngram CHAR(3) NOT NULL COLLATE {$COLLATE_TEXT} +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 266993bfb7..7a26123482 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -4371,6 +4371,7 @@ phutil_register_library_map(array( 'PhameBlogEditEngine' => 'applications/phame/editor/PhameBlogEditEngine.php', 'PhameBlogEditor' => 'applications/phame/editor/PhameBlogEditor.php', 'PhameBlogFeedController' => 'applications/phame/controller/blog/PhameBlogFeedController.php', + 'PhameBlogFerretEngine' => 'applications/phame/search/PhameBlogFerretEngine.php', 'PhameBlogFullDomainTransaction' => 'applications/phame/xaction/PhameBlogFullDomainTransaction.php', 'PhameBlogFulltextEngine' => 'applications/phame/search/PhameBlogFulltextEngine.php', 'PhameBlogHeaderImageTransaction' => 'applications/phame/xaction/PhameBlogHeaderImageTransaction.php', @@ -4411,6 +4412,7 @@ phutil_register_library_map(array( 'PhamePostEditController' => 'applications/phame/controller/post/PhamePostEditController.php', 'PhamePostEditEngine' => 'applications/phame/editor/PhamePostEditEngine.php', 'PhamePostEditor' => 'applications/phame/editor/PhamePostEditor.php', + 'PhamePostFerretEngine' => 'applications/phame/search/PhamePostFerretEngine.php', 'PhamePostFulltextEngine' => 'applications/phame/search/PhamePostFulltextEngine.php', 'PhamePostHeaderImageTransaction' => 'applications/phame/xaction/PhamePostHeaderImageTransaction.php', 'PhamePostHeaderPictureController' => 'applications/phame/controller/post/PhamePostHeaderPictureController.php', @@ -9995,6 +9997,7 @@ phutil_register_library_map(array( 'PhabricatorApplicationTransactionInterface', 'PhabricatorConduitResultInterface', 'PhabricatorFulltextInterface', + 'PhabricatorFerretInterface', ), 'PhameBlog404Controller' => 'PhameLiveController', 'PhameBlogArchiveController' => 'PhameBlogController', @@ -10007,6 +10010,7 @@ phutil_register_library_map(array( 'PhameBlogEditEngine' => 'PhabricatorEditEngine', 'PhameBlogEditor' => 'PhabricatorApplicationTransactionEditor', 'PhameBlogFeedController' => 'PhameBlogController', + 'PhameBlogFerretEngine' => 'PhabricatorFerretEngine', 'PhameBlogFullDomainTransaction' => 'PhameBlogTransactionType', 'PhameBlogFulltextEngine' => 'PhabricatorFulltextEngine', 'PhameBlogHeaderImageTransaction' => 'PhameBlogTransactionType', @@ -10050,6 +10054,7 @@ phutil_register_library_map(array( 'PhabricatorTokenReceiverInterface', 'PhabricatorConduitResultInterface', 'PhabricatorFulltextInterface', + 'PhabricatorFerretInterface', ), 'PhamePostArchiveController' => 'PhamePostController', 'PhamePostBlogTransaction' => 'PhamePostTransactionType', @@ -10059,6 +10064,7 @@ phutil_register_library_map(array( 'PhamePostEditController' => 'PhamePostController', 'PhamePostEditEngine' => 'PhabricatorEditEngine', 'PhamePostEditor' => 'PhabricatorApplicationTransactionEditor', + 'PhamePostFerretEngine' => 'PhabricatorFerretEngine', 'PhamePostFulltextEngine' => 'PhabricatorFulltextEngine', 'PhamePostHeaderImageTransaction' => 'PhamePostTransactionType', 'PhamePostHeaderPictureController' => 'PhamePostController', diff --git a/src/applications/phame/query/PhameBlogQuery.php b/src/applications/phame/query/PhameBlogQuery.php index bd34255bd0..b4018c78eb 100644 --- a/src/applications/phame/query/PhameBlogQuery.php +++ b/src/applications/phame/query/PhameBlogQuery.php @@ -55,28 +55,28 @@ final class PhameBlogQuery extends PhabricatorCursorPagedPolicyAwareQuery { if ($this->statuses !== null) { $where[] = qsprintf( $conn, - 'status IN (%Ls)', + 'b.status IN (%Ls)', $this->statuses); } if ($this->ids !== null) { $where[] = qsprintf( $conn, - 'id IN (%Ls)', + 'b.id IN (%Ls)', $this->ids); } if ($this->phids !== null) { $where[] = qsprintf( $conn, - 'phid IN (%Ls)', + 'b.phid IN (%Ls)', $this->phids); } if ($this->domain !== null) { $where[] = qsprintf( $conn, - 'domain = %s', + 'b.domain = %s', $this->domain); } @@ -143,4 +143,8 @@ final class PhameBlogQuery extends PhabricatorCursorPagedPolicyAwareQuery { return null; } + protected function getPrimaryTableAlias() { + return 'b'; + } + } diff --git a/src/applications/phame/query/PhamePostQuery.php b/src/applications/phame/query/PhamePostQuery.php index 357418cfb3..85ef470cea 100644 --- a/src/applications/phame/query/PhamePostQuery.php +++ b/src/applications/phame/query/PhamePostQuery.php @@ -106,45 +106,45 @@ final class PhamePostQuery extends PhabricatorCursorPagedPolicyAwareQuery { protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); - if ($this->ids) { + if ($this->ids !== null) { $where[] = qsprintf( $conn, - 'id IN (%Ld)', + 'p.id IN (%Ld)', $this->ids); } - if ($this->phids) { + if ($this->phids !== null) { $where[] = qsprintf( $conn, - 'phid IN (%Ls)', + 'p.phid IN (%Ls)', $this->phids); } - if ($this->bloggerPHIDs) { + if ($this->bloggerPHIDs !== null) { $where[] = qsprintf( $conn, - 'bloggerPHID IN (%Ls)', + 'p.bloggerPHID IN (%Ls)', $this->bloggerPHIDs); } - if ($this->visibility) { + if ($this->visibility !== null) { $where[] = qsprintf( $conn, - 'visibility IN (%Ld)', + 'p.visibility IN (%Ld)', $this->visibility); } if ($this->publishedAfter !== null) { $where[] = qsprintf( $conn, - 'datePublished > %d', + 'p.datePublished > %d', $this->publishedAfter); } if ($this->blogPHIDs !== null) { $where[] = qsprintf( $conn, - 'blogPHID in (%Ls)', + 'p.blogPHID in (%Ls)', $this->blogPHIDs); } @@ -163,6 +163,7 @@ final class PhamePostQuery extends PhabricatorCursorPagedPolicyAwareQuery { public function getOrderableColumns() { return parent::getOrderableColumns() + array( 'datePublished' => array( + 'table' => $this->getPrimaryTableAlias(), 'column' => 'datePublished', 'type' => 'int', 'reverse' => false, @@ -186,4 +187,8 @@ final class PhamePostQuery extends PhabricatorCursorPagedPolicyAwareQuery { return null; } + protected function getPrimaryTableAlias() { + return 'p'; + } + } diff --git a/src/applications/phame/search/PhameBlogFerretEngine.php b/src/applications/phame/search/PhameBlogFerretEngine.php new file mode 100644 index 0000000000..76901f915c --- /dev/null +++ b/src/applications/phame/search/PhameBlogFerretEngine.php @@ -0,0 +1,18 @@ + Date: Thu, 7 Sep 2017 12:20:47 -0700 Subject: [PATCH 42/54] Support Ferret engine in Projects Summary: Ref T12819. Adds support for projects. Test Plan: Indexed and searched for projects. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12819 Differential Revision: https://secure.phabricator.com/D18566 --- .../20170907.ferret.19.project.doc.sql | 9 +++++++++ .../20170907.ferret.20.project.field.sql | 8 ++++++++ .../20170907.ferret.21.project.ngrams.sql | 5 +++++ src/__phutil_library_map__.php | 3 +++ .../search/PhabricatorProjectFerretEngine.php | 18 ++++++++++++++++++ .../project/storage/PhabricatorProject.php | 9 +++++++++ 6 files changed, 52 insertions(+) create mode 100644 resources/sql/autopatches/20170907.ferret.19.project.doc.sql create mode 100644 resources/sql/autopatches/20170907.ferret.20.project.field.sql create mode 100644 resources/sql/autopatches/20170907.ferret.21.project.ngrams.sql create mode 100644 src/applications/project/search/PhabricatorProjectFerretEngine.php diff --git a/resources/sql/autopatches/20170907.ferret.19.project.doc.sql b/resources/sql/autopatches/20170907.ferret.19.project.doc.sql new file mode 100644 index 0000000000..26272439cf --- /dev/null +++ b/resources/sql/autopatches/20170907.ferret.19.project.doc.sql @@ -0,0 +1,9 @@ +CREATE TABLE {$NAMESPACE}_project.project_project_fdocument ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + objectPHID VARBINARY(64) NOT NULL, + isClosed BOOL NOT NULL, + authorPHID VARBINARY(64), + ownerPHID VARBINARY(64), + epochCreated INT UNSIGNED NOT NULL, + epochModified INT UNSIGNED NOT NULL +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/resources/sql/autopatches/20170907.ferret.20.project.field.sql b/resources/sql/autopatches/20170907.ferret.20.project.field.sql new file mode 100644 index 0000000000..36514eb55d --- /dev/null +++ b/resources/sql/autopatches/20170907.ferret.20.project.field.sql @@ -0,0 +1,8 @@ +CREATE TABLE {$NAMESPACE}_project.project_project_ffield ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + documentID INT UNSIGNED NOT NULL, + fieldKey VARCHAR(4) NOT NULL COLLATE {$COLLATE_TEXT}, + rawCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT}, + termCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT}, + normalCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT} +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/resources/sql/autopatches/20170907.ferret.21.project.ngrams.sql b/resources/sql/autopatches/20170907.ferret.21.project.ngrams.sql new file mode 100644 index 0000000000..dec12b0e56 --- /dev/null +++ b/resources/sql/autopatches/20170907.ferret.21.project.ngrams.sql @@ -0,0 +1,5 @@ +CREATE TABLE {$NAMESPACE}_project.project_project_fngrams ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + documentID INT UNSIGNED NOT NULL, + ngram CHAR(3) NOT NULL COLLATE {$COLLATE_TEXT} +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 7a26123482..2513480fa3 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -3666,6 +3666,7 @@ phutil_register_library_map(array( 'PhabricatorProjectEditController' => 'applications/project/controller/PhabricatorProjectEditController.php', 'PhabricatorProjectEditEngine' => 'applications/project/engine/PhabricatorProjectEditEngine.php', 'PhabricatorProjectEditPictureController' => 'applications/project/controller/PhabricatorProjectEditPictureController.php', + 'PhabricatorProjectFerretEngine' => 'applications/project/search/PhabricatorProjectFerretEngine.php', 'PhabricatorProjectFilterTransaction' => 'applications/project/xaction/PhabricatorProjectFilterTransaction.php', 'PhabricatorProjectFulltextEngine' => 'applications/project/search/PhabricatorProjectFulltextEngine.php', 'PhabricatorProjectHeraldAction' => 'applications/project/herald/PhabricatorProjectHeraldAction.php', @@ -9105,6 +9106,7 @@ phutil_register_library_map(array( 'PhabricatorCustomFieldInterface', 'PhabricatorDestructibleInterface', 'PhabricatorFulltextInterface', + 'PhabricatorFerretInterface', 'PhabricatorConduitResultInterface', 'PhabricatorColumnProxyInterface', ), @@ -9164,6 +9166,7 @@ phutil_register_library_map(array( 'PhabricatorProjectEditController' => 'PhabricatorProjectController', 'PhabricatorProjectEditEngine' => 'PhabricatorEditEngine', 'PhabricatorProjectEditPictureController' => 'PhabricatorProjectController', + 'PhabricatorProjectFerretEngine' => 'PhabricatorFerretEngine', 'PhabricatorProjectFilterTransaction' => 'PhabricatorProjectTransactionType', 'PhabricatorProjectFulltextEngine' => 'PhabricatorFulltextEngine', 'PhabricatorProjectHeraldAction' => 'HeraldAction', diff --git a/src/applications/project/search/PhabricatorProjectFerretEngine.php b/src/applications/project/search/PhabricatorProjectFerretEngine.php new file mode 100644 index 0000000000..459fc24026 --- /dev/null +++ b/src/applications/project/search/PhabricatorProjectFerretEngine.php @@ -0,0 +1,18 @@ + Date: Thu, 7 Sep 2017 12:38:11 -0700 Subject: [PATCH 43/54] Support Ferret engine in Phriction Summary: Ref T12819. Adds Ferret engine support. Test Plan: Indexed and searched for documents. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12819 Differential Revision: https://secure.phabricator.com/D18567 --- .../20170907.ferret.22.phriction.doc.sql | 9 +++++++++ .../20170907.ferret.23.phriction.field.sql | 8 ++++++++ .../20170907.ferret.24.phriction.ngrams.sql | 5 +++++ src/__phutil_library_map__.php | 3 +++ .../search/PhrictionDocumentFerretEngine.php | 18 ++++++++++++++++++ .../phriction/storage/PhrictionDocument.php | 9 +++++++++ 6 files changed, 52 insertions(+) create mode 100644 resources/sql/autopatches/20170907.ferret.22.phriction.doc.sql create mode 100644 resources/sql/autopatches/20170907.ferret.23.phriction.field.sql create mode 100644 resources/sql/autopatches/20170907.ferret.24.phriction.ngrams.sql create mode 100644 src/applications/phriction/search/PhrictionDocumentFerretEngine.php diff --git a/resources/sql/autopatches/20170907.ferret.22.phriction.doc.sql b/resources/sql/autopatches/20170907.ferret.22.phriction.doc.sql new file mode 100644 index 0000000000..9de7124255 --- /dev/null +++ b/resources/sql/autopatches/20170907.ferret.22.phriction.doc.sql @@ -0,0 +1,9 @@ +CREATE TABLE {$NAMESPACE}_phriction.phriction_document_fdocument ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + objectPHID VARBINARY(64) NOT NULL, + isClosed BOOL NOT NULL, + authorPHID VARBINARY(64), + ownerPHID VARBINARY(64), + epochCreated INT UNSIGNED NOT NULL, + epochModified INT UNSIGNED NOT NULL +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/resources/sql/autopatches/20170907.ferret.23.phriction.field.sql b/resources/sql/autopatches/20170907.ferret.23.phriction.field.sql new file mode 100644 index 0000000000..0fc5b959d1 --- /dev/null +++ b/resources/sql/autopatches/20170907.ferret.23.phriction.field.sql @@ -0,0 +1,8 @@ +CREATE TABLE {$NAMESPACE}_phriction.phriction_document_ffield ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + documentID INT UNSIGNED NOT NULL, + fieldKey VARCHAR(4) NOT NULL COLLATE {$COLLATE_TEXT}, + rawCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT}, + termCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT}, + normalCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT} +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/resources/sql/autopatches/20170907.ferret.24.phriction.ngrams.sql b/resources/sql/autopatches/20170907.ferret.24.phriction.ngrams.sql new file mode 100644 index 0000000000..abbb90a1e4 --- /dev/null +++ b/resources/sql/autopatches/20170907.ferret.24.phriction.ngrams.sql @@ -0,0 +1,5 @@ +CREATE TABLE {$NAMESPACE}_phriction.phriction_document_fngrams ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + documentID INT UNSIGNED NOT NULL, + ngram CHAR(3) NOT NULL COLLATE {$COLLATE_TEXT} +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 2513480fa3..c22e4314c0 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -4694,6 +4694,7 @@ phutil_register_library_map(array( 'PhrictionDocumentContentTransaction' => 'applications/phriction/xaction/PhrictionDocumentContentTransaction.php', 'PhrictionDocumentController' => 'applications/phriction/controller/PhrictionDocumentController.php', 'PhrictionDocumentDeleteTransaction' => 'applications/phriction/xaction/PhrictionDocumentDeleteTransaction.php', + 'PhrictionDocumentFerretEngine' => 'applications/phriction/search/PhrictionDocumentFerretEngine.php', 'PhrictionDocumentFulltextEngine' => 'applications/phriction/search/PhrictionDocumentFulltextEngine.php', 'PhrictionDocumentHeraldAdapter' => 'applications/phriction/herald/PhrictionDocumentHeraldAdapter.php', 'PhrictionDocumentHeraldField' => 'applications/phriction/herald/PhrictionDocumentHeraldField.php', @@ -10420,6 +10421,7 @@ phutil_register_library_map(array( 'PhabricatorTokenReceiverInterface', 'PhabricatorDestructibleInterface', 'PhabricatorFulltextInterface', + 'PhabricatorFerretInterface', 'PhabricatorProjectInterface', 'PhabricatorApplicationTransactionInterface', ), @@ -10428,6 +10430,7 @@ phutil_register_library_map(array( 'PhrictionDocumentContentTransaction' => 'PhrictionDocumentTransactionType', 'PhrictionDocumentController' => 'PhrictionController', 'PhrictionDocumentDeleteTransaction' => 'PhrictionDocumentTransactionType', + 'PhrictionDocumentFerretEngine' => 'PhabricatorFerretEngine', 'PhrictionDocumentFulltextEngine' => 'PhabricatorFulltextEngine', 'PhrictionDocumentHeraldAdapter' => 'HeraldAdapter', 'PhrictionDocumentHeraldField' => 'HeraldField', diff --git a/src/applications/phriction/search/PhrictionDocumentFerretEngine.php b/src/applications/phriction/search/PhrictionDocumentFerretEngine.php new file mode 100644 index 0000000000..76802391e7 --- /dev/null +++ b/src/applications/phriction/search/PhrictionDocumentFerretEngine.php @@ -0,0 +1,18 @@ + Date: Thu, 7 Sep 2017 13:01:26 -0700 Subject: [PATCH 44/54] Support Ferret engine in Calendar Summary: Ref T12819. Adds ferret engine support for Calendar events. Test Plan: Indexed and queried calendar events. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12819 Differential Revision: https://secure.phabricator.com/D18568 --- .../20170907.ferret.25.event.doc.sql | 9 +++++++++ .../20170907.ferret.26.event.field.sql | 8 ++++++++ .../20170907.ferret.27.event.ngrams.sql | 5 +++++ src/__phutil_library_map__.php | 3 +++ .../PhabricatorCalendarEventFerretEngine.php | 18 ++++++++++++++++++ .../storage/PhabricatorCalendarEvent.php | 9 +++++++++ 6 files changed, 52 insertions(+) create mode 100644 resources/sql/autopatches/20170907.ferret.25.event.doc.sql create mode 100644 resources/sql/autopatches/20170907.ferret.26.event.field.sql create mode 100644 resources/sql/autopatches/20170907.ferret.27.event.ngrams.sql create mode 100644 src/applications/calendar/search/PhabricatorCalendarEventFerretEngine.php diff --git a/resources/sql/autopatches/20170907.ferret.25.event.doc.sql b/resources/sql/autopatches/20170907.ferret.25.event.doc.sql new file mode 100644 index 0000000000..d7298fad31 --- /dev/null +++ b/resources/sql/autopatches/20170907.ferret.25.event.doc.sql @@ -0,0 +1,9 @@ +CREATE TABLE {$NAMESPACE}_calendar.calendar_event_fdocument ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + objectPHID VARBINARY(64) NOT NULL, + isClosed BOOL NOT NULL, + authorPHID VARBINARY(64), + ownerPHID VARBINARY(64), + epochCreated INT UNSIGNED NOT NULL, + epochModified INT UNSIGNED NOT NULL +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/resources/sql/autopatches/20170907.ferret.26.event.field.sql b/resources/sql/autopatches/20170907.ferret.26.event.field.sql new file mode 100644 index 0000000000..2ec76c3511 --- /dev/null +++ b/resources/sql/autopatches/20170907.ferret.26.event.field.sql @@ -0,0 +1,8 @@ +CREATE TABLE {$NAMESPACE}_calendar.calendar_event_ffield ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + documentID INT UNSIGNED NOT NULL, + fieldKey VARCHAR(4) NOT NULL COLLATE {$COLLATE_TEXT}, + rawCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT}, + termCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT}, + normalCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT} +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/resources/sql/autopatches/20170907.ferret.27.event.ngrams.sql b/resources/sql/autopatches/20170907.ferret.27.event.ngrams.sql new file mode 100644 index 0000000000..e802e2d97e --- /dev/null +++ b/resources/sql/autopatches/20170907.ferret.27.event.ngrams.sql @@ -0,0 +1,5 @@ +CREATE TABLE {$NAMESPACE}_calendar.calendar_event_fngrams ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + documentID INT UNSIGNED NOT NULL, + ngram CHAR(3) NOT NULL COLLATE {$COLLATE_TEXT} +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index c22e4314c0..67bb9b73f3 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -2208,6 +2208,7 @@ phutil_register_library_map(array( 'PhabricatorCalendarEventEmailCommand' => 'applications/calendar/command/PhabricatorCalendarEventEmailCommand.php', 'PhabricatorCalendarEventEndDateTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventEndDateTransaction.php', 'PhabricatorCalendarEventExportController' => 'applications/calendar/controller/PhabricatorCalendarEventExportController.php', + 'PhabricatorCalendarEventFerretEngine' => 'applications/calendar/search/PhabricatorCalendarEventFerretEngine.php', 'PhabricatorCalendarEventForkTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventForkTransaction.php', 'PhabricatorCalendarEventFrequencyTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventFrequencyTransaction.php', 'PhabricatorCalendarEventFulltextEngine' => 'applications/calendar/search/PhabricatorCalendarEventFulltextEngine.php', @@ -7446,6 +7447,7 @@ phutil_register_library_map(array( 'PhabricatorFlaggableInterface', 'PhabricatorSpacesInterface', 'PhabricatorFulltextInterface', + 'PhabricatorFerretInterface', 'PhabricatorConduitResultInterface', ), 'PhabricatorCalendarEventAcceptTransaction' => 'PhabricatorCalendarEventReplyTransaction', @@ -7466,6 +7468,7 @@ phutil_register_library_map(array( 'PhabricatorCalendarEventEmailCommand' => 'MetaMTAEmailTransactionCommand', 'PhabricatorCalendarEventEndDateTransaction' => 'PhabricatorCalendarEventDateTransaction', 'PhabricatorCalendarEventExportController' => 'PhabricatorCalendarController', + 'PhabricatorCalendarEventFerretEngine' => 'PhabricatorFerretEngine', 'PhabricatorCalendarEventForkTransaction' => 'PhabricatorCalendarEventTransactionType', 'PhabricatorCalendarEventFrequencyTransaction' => 'PhabricatorCalendarEventTransactionType', 'PhabricatorCalendarEventFulltextEngine' => 'PhabricatorFulltextEngine', diff --git a/src/applications/calendar/search/PhabricatorCalendarEventFerretEngine.php b/src/applications/calendar/search/PhabricatorCalendarEventFerretEngine.php new file mode 100644 index 0000000000..70e456e034 --- /dev/null +++ b/src/applications/calendar/search/PhabricatorCalendarEventFerretEngine.php @@ -0,0 +1,18 @@ + Date: Thu, 7 Sep 2017 13:05:24 -0700 Subject: [PATCH 45/54] Support Ferret engine in Pholio Summary: Ref T12819. Support for Pholio. Test Plan: Indexed and searched mocks. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12819 Differential Revision: https://secure.phabricator.com/D18569 --- .../20170907.ferret.28.mock.doc.sql | 9 +++++++++ .../20170907.ferret.29.mock.field.sql | 8 ++++++++ .../20170907.ferret.30.mock.ngrams.sql | 5 +++++ src/__phutil_library_map__.php | 3 +++ .../pholio/search/PholioMockFerretEngine.php | 18 ++++++++++++++++++ src/applications/pholio/storage/PholioMock.php | 10 +++++++++- 6 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 resources/sql/autopatches/20170907.ferret.28.mock.doc.sql create mode 100644 resources/sql/autopatches/20170907.ferret.29.mock.field.sql create mode 100644 resources/sql/autopatches/20170907.ferret.30.mock.ngrams.sql create mode 100644 src/applications/pholio/search/PholioMockFerretEngine.php diff --git a/resources/sql/autopatches/20170907.ferret.28.mock.doc.sql b/resources/sql/autopatches/20170907.ferret.28.mock.doc.sql new file mode 100644 index 0000000000..eb80ef3937 --- /dev/null +++ b/resources/sql/autopatches/20170907.ferret.28.mock.doc.sql @@ -0,0 +1,9 @@ +CREATE TABLE {$NAMESPACE}_pholio.pholio_mock_fdocument ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + objectPHID VARBINARY(64) NOT NULL, + isClosed BOOL NOT NULL, + authorPHID VARBINARY(64), + ownerPHID VARBINARY(64), + epochCreated INT UNSIGNED NOT NULL, + epochModified INT UNSIGNED NOT NULL +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/resources/sql/autopatches/20170907.ferret.29.mock.field.sql b/resources/sql/autopatches/20170907.ferret.29.mock.field.sql new file mode 100644 index 0000000000..0cb0e97d05 --- /dev/null +++ b/resources/sql/autopatches/20170907.ferret.29.mock.field.sql @@ -0,0 +1,8 @@ +CREATE TABLE {$NAMESPACE}_pholio.pholio_mock_ffield ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + documentID INT UNSIGNED NOT NULL, + fieldKey VARCHAR(4) NOT NULL COLLATE {$COLLATE_TEXT}, + rawCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT}, + termCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT}, + normalCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT} +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/resources/sql/autopatches/20170907.ferret.30.mock.ngrams.sql b/resources/sql/autopatches/20170907.ferret.30.mock.ngrams.sql new file mode 100644 index 0000000000..e343ccf83b --- /dev/null +++ b/resources/sql/autopatches/20170907.ferret.30.mock.ngrams.sql @@ -0,0 +1,5 @@ +CREATE TABLE {$NAMESPACE}_pholio.pholio_mock_fngrams ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + documentID INT UNSIGNED NOT NULL, + ngram CHAR(3) NOT NULL COLLATE {$COLLATE_TEXT} +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 67bb9b73f3..f42f815f1f 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -4475,6 +4475,7 @@ phutil_register_library_map(array( 'PholioMockEditController' => 'applications/pholio/controller/PholioMockEditController.php', 'PholioMockEditor' => 'applications/pholio/editor/PholioMockEditor.php', 'PholioMockEmbedView' => 'applications/pholio/view/PholioMockEmbedView.php', + 'PholioMockFerretEngine' => 'applications/pholio/search/PholioMockFerretEngine.php', 'PholioMockFulltextEngine' => 'applications/pholio/search/PholioMockFulltextEngine.php', 'PholioMockHasTaskEdgeType' => 'applications/pholio/edge/PholioMockHasTaskEdgeType.php', 'PholioMockHasTaskRelationship' => 'applications/pholio/relationships/PholioMockHasTaskRelationship.php', @@ -10145,6 +10146,7 @@ phutil_register_library_map(array( 'PhabricatorSpacesInterface', 'PhabricatorMentionableInterface', 'PhabricatorFulltextInterface', + 'PhabricatorFerretInterface', ), 'PholioMockArchiveController' => 'PholioController', 'PholioMockAuthorHeraldField' => 'PholioMockHeraldField', @@ -10154,6 +10156,7 @@ phutil_register_library_map(array( 'PholioMockEditController' => 'PholioController', 'PholioMockEditor' => 'PhabricatorApplicationTransactionEditor', 'PholioMockEmbedView' => 'AphrontView', + 'PholioMockFerretEngine' => 'PhabricatorFerretEngine', 'PholioMockFulltextEngine' => 'PhabricatorFulltextEngine', 'PholioMockHasTaskEdgeType' => 'PhabricatorEdgeType', 'PholioMockHasTaskRelationship' => 'PholioMockRelationship', diff --git a/src/applications/pholio/search/PholioMockFerretEngine.php b/src/applications/pholio/search/PholioMockFerretEngine.php new file mode 100644 index 0000000000..f4f9b4610f --- /dev/null +++ b/src/applications/pholio/search/PholioMockFerretEngine.php @@ -0,0 +1,18 @@ + Date: Thu, 7 Sep 2017 13:11:34 -0700 Subject: [PATCH 46/54] Support the Ferret engine in Diffusion Summary: Ref T12819. More ferret engine support. Test Plan: Indexed and searched commits and repositories. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12819 Differential Revision: https://secure.phabricator.com/D18572 --- .../20170907.ferret.31.repo.doc.sql | 9 +++++++++ .../20170907.ferret.32.repo.field.sql | 8 ++++++++ .../20170907.ferret.33.repo.ngrams.sql | 5 +++++ .../20170907.ferret.34.commit.doc.sql | 9 +++++++++ .../20170907.ferret.35.commit.field.sql | 8 ++++++++ .../20170907.ferret.36.commit.ngrams.sql | 5 +++++ src/__phutil_library_map__.php | 6 ++++++ .../search/DiffusionCommitFerretEngine.php | 18 ++++++++++++++++++ .../PhabricatorRepositoryFerretEngine.php | 18 ++++++++++++++++++ .../storage/PhabricatorRepository.php | 11 ++++++++++- .../storage/PhabricatorRepositoryCommit.php | 9 +++++++++ 11 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 resources/sql/autopatches/20170907.ferret.31.repo.doc.sql create mode 100644 resources/sql/autopatches/20170907.ferret.32.repo.field.sql create mode 100644 resources/sql/autopatches/20170907.ferret.33.repo.ngrams.sql create mode 100644 resources/sql/autopatches/20170907.ferret.34.commit.doc.sql create mode 100644 resources/sql/autopatches/20170907.ferret.35.commit.field.sql create mode 100644 resources/sql/autopatches/20170907.ferret.36.commit.ngrams.sql create mode 100644 src/applications/repository/search/DiffusionCommitFerretEngine.php create mode 100644 src/applications/repository/search/PhabricatorRepositoryFerretEngine.php diff --git a/resources/sql/autopatches/20170907.ferret.31.repo.doc.sql b/resources/sql/autopatches/20170907.ferret.31.repo.doc.sql new file mode 100644 index 0000000000..4f37de60be --- /dev/null +++ b/resources/sql/autopatches/20170907.ferret.31.repo.doc.sql @@ -0,0 +1,9 @@ +CREATE TABLE {$NAMESPACE}_repository.repository_repository_fdocument ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + objectPHID VARBINARY(64) NOT NULL, + isClosed BOOL NOT NULL, + authorPHID VARBINARY(64), + ownerPHID VARBINARY(64), + epochCreated INT UNSIGNED NOT NULL, + epochModified INT UNSIGNED NOT NULL +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/resources/sql/autopatches/20170907.ferret.32.repo.field.sql b/resources/sql/autopatches/20170907.ferret.32.repo.field.sql new file mode 100644 index 0000000000..c7d75eb29d --- /dev/null +++ b/resources/sql/autopatches/20170907.ferret.32.repo.field.sql @@ -0,0 +1,8 @@ +CREATE TABLE {$NAMESPACE}_repository.repository_repository_ffield ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + documentID INT UNSIGNED NOT NULL, + fieldKey VARCHAR(4) NOT NULL COLLATE {$COLLATE_TEXT}, + rawCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT}, + termCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT}, + normalCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT} +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/resources/sql/autopatches/20170907.ferret.33.repo.ngrams.sql b/resources/sql/autopatches/20170907.ferret.33.repo.ngrams.sql new file mode 100644 index 0000000000..db7ad4f3a0 --- /dev/null +++ b/resources/sql/autopatches/20170907.ferret.33.repo.ngrams.sql @@ -0,0 +1,5 @@ +CREATE TABLE {$NAMESPACE}_repository.repository_repository_fngrams ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + documentID INT UNSIGNED NOT NULL, + ngram CHAR(3) NOT NULL COLLATE {$COLLATE_TEXT} +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/resources/sql/autopatches/20170907.ferret.34.commit.doc.sql b/resources/sql/autopatches/20170907.ferret.34.commit.doc.sql new file mode 100644 index 0000000000..9c275b09b7 --- /dev/null +++ b/resources/sql/autopatches/20170907.ferret.34.commit.doc.sql @@ -0,0 +1,9 @@ +CREATE TABLE {$NAMESPACE}_repository.repository_commit_fdocument ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + objectPHID VARBINARY(64) NOT NULL, + isClosed BOOL NOT NULL, + authorPHID VARBINARY(64), + ownerPHID VARBINARY(64), + epochCreated INT UNSIGNED NOT NULL, + epochModified INT UNSIGNED NOT NULL +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/resources/sql/autopatches/20170907.ferret.35.commit.field.sql b/resources/sql/autopatches/20170907.ferret.35.commit.field.sql new file mode 100644 index 0000000000..c2520b693b --- /dev/null +++ b/resources/sql/autopatches/20170907.ferret.35.commit.field.sql @@ -0,0 +1,8 @@ +CREATE TABLE {$NAMESPACE}_repository.repository_commit_ffield ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + documentID INT UNSIGNED NOT NULL, + fieldKey VARCHAR(4) NOT NULL COLLATE {$COLLATE_TEXT}, + rawCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT}, + termCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT}, + normalCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT} +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/resources/sql/autopatches/20170907.ferret.36.commit.ngrams.sql b/resources/sql/autopatches/20170907.ferret.36.commit.ngrams.sql new file mode 100644 index 0000000000..32ed2275c3 --- /dev/null +++ b/resources/sql/autopatches/20170907.ferret.36.commit.ngrams.sql @@ -0,0 +1,5 @@ +CREATE TABLE {$NAMESPACE}_repository.repository_commit_fngrams ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + documentID INT UNSIGNED NOT NULL, + ngram CHAR(3) NOT NULL COLLATE {$COLLATE_TEXT} +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index f42f815f1f..6c18759cb9 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -652,6 +652,7 @@ phutil_register_library_map(array( 'DiffusionCommitEditConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionCommitEditConduitAPIMethod.php', 'DiffusionCommitEditController' => 'applications/diffusion/controller/DiffusionCommitEditController.php', 'DiffusionCommitEditEngine' => 'applications/diffusion/editor/DiffusionCommitEditEngine.php', + 'DiffusionCommitFerretEngine' => 'applications/repository/search/DiffusionCommitFerretEngine.php', 'DiffusionCommitFulltextEngine' => 'applications/repository/search/DiffusionCommitFulltextEngine.php', 'DiffusionCommitHasPackageEdgeType' => 'applications/diffusion/edge/DiffusionCommitHasPackageEdgeType.php', 'DiffusionCommitHasRevisionEdgeType' => 'applications/diffusion/edge/DiffusionCommitHasRevisionEdgeType.php', @@ -3807,6 +3808,7 @@ phutil_register_library_map(array( 'PhabricatorRepositoryDiscoveryEngine' => 'applications/repository/engine/PhabricatorRepositoryDiscoveryEngine.php', 'PhabricatorRepositoryEditor' => 'applications/repository/editor/PhabricatorRepositoryEditor.php', 'PhabricatorRepositoryEngine' => 'applications/repository/engine/PhabricatorRepositoryEngine.php', + 'PhabricatorRepositoryFerretEngine' => 'applications/repository/search/PhabricatorRepositoryFerretEngine.php', 'PhabricatorRepositoryFulltextEngine' => 'applications/repository/search/PhabricatorRepositoryFulltextEngine.php', 'PhabricatorRepositoryGitCommitChangeParserWorker' => 'applications/repository/worker/commitchangeparser/PhabricatorRepositoryGitCommitChangeParserWorker.php', 'PhabricatorRepositoryGitCommitMessageParserWorker' => 'applications/repository/worker/commitmessageparser/PhabricatorRepositoryGitCommitMessageParserWorker.php', @@ -5673,6 +5675,7 @@ phutil_register_library_map(array( 'DiffusionCommitEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', 'DiffusionCommitEditController' => 'DiffusionController', 'DiffusionCommitEditEngine' => 'PhabricatorEditEngine', + 'DiffusionCommitFerretEngine' => 'PhabricatorFerretEngine', 'DiffusionCommitFulltextEngine' => 'PhabricatorFulltextEngine', 'DiffusionCommitHasPackageEdgeType' => 'PhabricatorEdgeType', 'DiffusionCommitHasRevisionEdgeType' => 'PhabricatorEdgeType', @@ -9308,6 +9311,7 @@ phutil_register_library_map(array( 'PhabricatorSpacesInterface', 'PhabricatorConduitResultInterface', 'PhabricatorFulltextInterface', + 'PhabricatorFerretInterface', ), 'PhabricatorRepositoryAuditRequest' => array( 'PhabricatorRepositoryDAO', @@ -9328,6 +9332,7 @@ phutil_register_library_map(array( 'PhabricatorCustomFieldInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorFulltextInterface', + 'PhabricatorFerretInterface', 'PhabricatorConduitResultInterface', 'PhabricatorDraftInterface', ), @@ -9350,6 +9355,7 @@ phutil_register_library_map(array( 'PhabricatorRepositoryDiscoveryEngine' => 'PhabricatorRepositoryEngine', 'PhabricatorRepositoryEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorRepositoryEngine' => 'Phobject', + 'PhabricatorRepositoryFerretEngine' => 'PhabricatorFerretEngine', 'PhabricatorRepositoryFulltextEngine' => 'PhabricatorFulltextEngine', 'PhabricatorRepositoryGitCommitChangeParserWorker' => 'PhabricatorRepositoryCommitChangeParserWorker', 'PhabricatorRepositoryGitCommitMessageParserWorker' => 'PhabricatorRepositoryCommitMessageParserWorker', diff --git a/src/applications/repository/search/DiffusionCommitFerretEngine.php b/src/applications/repository/search/DiffusionCommitFerretEngine.php new file mode 100644 index 0000000000..a6c5ce42c8 --- /dev/null +++ b/src/applications/repository/search/DiffusionCommitFerretEngine.php @@ -0,0 +1,18 @@ + Date: Thu, 7 Sep 2017 13:15:07 -0700 Subject: [PATCH 47/54] Fix info view error layout in config boxes Summary: Adds some side margin here. Test Plan: error out a form field in a white box Reviewers: epriestley Reviewed By: epriestley Spies: Korvin Differential Revision: https://secure.phabricator.com/D18571 --- resources/celerity/map.php | 6 +++--- webroot/rsrc/css/phui/phui-info-view.css | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index aef701f7bc..2093e3e70e 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -9,7 +9,7 @@ return array( 'names' => array( 'conpherence.pkg.css' => 'e68cf1fa', 'conpherence.pkg.js' => 'b5b51108', - 'core.pkg.css' => 'b2235af0', + 'core.pkg.css' => 'e9473020', 'core.pkg.js' => '6c085267', 'darkconsole.pkg.js' => '1f9a31bc', 'differential.pkg.css' => '45951e9e', @@ -162,7 +162,7 @@ return array( 'rsrc/css/phui/phui-icon-set-selector.css' => '87db8fee', 'rsrc/css/phui/phui-icon.css' => '5c4a5de6', 'rsrc/css/phui/phui-image-mask.css' => 'a8498f9c', - 'rsrc/css/phui/phui-info-view.css' => '04e071d7', + 'rsrc/css/phui/phui-info-view.css' => 'e929f98c', 'rsrc/css/phui/phui-invisible-character-view.css' => '6993d9f0', 'rsrc/css/phui/phui-left-right.css' => '75227a4d', 'rsrc/css/phui/phui-lightbox.css' => '0a035e40', @@ -849,7 +849,7 @@ return array( 'phui-icon-set-selector-css' => '87db8fee', 'phui-icon-view-css' => '5c4a5de6', 'phui-image-mask-css' => 'a8498f9c', - 'phui-info-view-css' => '04e071d7', + 'phui-info-view-css' => 'e929f98c', 'phui-inline-comment-view-css' => '65ae3bc2', 'phui-invisible-character-view-css' => '6993d9f0', 'phui-left-right-css' => '75227a4d', diff --git a/webroot/rsrc/css/phui/phui-info-view.css b/webroot/rsrc/css/phui/phui-info-view.css index 7b20c63ccf..55400956e4 100644 --- a/webroot/rsrc/css/phui/phui-info-view.css +++ b/webroot/rsrc/css/phui/phui-info-view.css @@ -139,3 +139,7 @@ h1.phui-info-view-head { div.phui-object-box .phui-header-shell + .phui-info-view { margin: 16px 0 8px; } + +div.phui-object-box.phui-box-white-config .phui-header-shell + .phui-info-view { + margin: 20px 16px 8px; +} From f1193afa94bfeeebe8491b0e89a2b68d286c7f81 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Thu, 7 Sep 2017 13:08:10 -0700 Subject: [PATCH 48/54] Update passphrase edit UI Summary: Updates creating credentials Test Plan: create some notes Reviewers: epriestley Reviewed By: epriestley Spies: Korvin Differential Revision: https://secure.phabricator.com/D18570 --- .../herald/controller/HeraldRuleController.php | 2 -- .../PassphraseCredentialCreateController.php | 9 ++------- .../PassphraseCredentialEditController.php | 17 +++-------------- 3 files changed, 5 insertions(+), 23 deletions(-) diff --git a/src/applications/herald/controller/HeraldRuleController.php b/src/applications/herald/controller/HeraldRuleController.php index d338f6a57e..eaf352a0a7 100644 --- a/src/applications/herald/controller/HeraldRuleController.php +++ b/src/applications/herald/controller/HeraldRuleController.php @@ -238,8 +238,6 @@ final class HeraldRuleController extends HeraldController { ? pht('Edit Herald Rule: %s', $rule->getName()) : pht('Create Herald Rule: %s', idx($content_type_map, $content_type)); - $icon = $rule->getID() ? 'fa-pencil' : 'fa-plus-square'; - $form_box = id(new PHUIObjectBoxView()) ->setHeaderText($title) ->setBackground(PHUIObjectBoxView::WHITE_CONFIG) diff --git a/src/applications/passphrase/controller/PassphraseCredentialCreateController.php b/src/applications/passphrase/controller/PassphraseCredentialCreateController.php index 87afe22cc6..b237ef378b 100644 --- a/src/applications/passphrase/controller/PassphraseCredentialCreateController.php +++ b/src/applications/passphrase/controller/PassphraseCredentialCreateController.php @@ -52,17 +52,12 @@ final class PassphraseCredentialCreateController extends PassphraseController { $crumbs->setBorder(true); $box = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Credential')) + ->setHeaderText($title) ->setFormErrors($errors) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) + ->setBackground(PHUIObjectBoxView::WHITE_CONFIG) ->setForm($form); - $header = id(new PHUIHeaderView()) - ->setHeader($title) - ->setHeaderIcon('fa-plus-square'); - $view = id(new PHUITwoColumnView()) - ->setHeader($header) ->setFooter($box); return $this->newPage() diff --git a/src/applications/passphrase/controller/PassphraseCredentialEditController.php b/src/applications/passphrase/controller/PassphraseCredentialEditController.php index a35bd3479e..91c8d93883 100644 --- a/src/applications/passphrase/controller/PassphraseCredentialEditController.php +++ b/src/applications/passphrase/controller/PassphraseCredentialEditController.php @@ -249,10 +249,6 @@ final class PassphraseCredentialEditController extends PassphraseController { ->setName('description') ->setLabel(pht('Description')) ->setValue($v_desc)) - ->appendChild( - id(new AphrontFormMarkupControl()) - ->setLabel(pht('Credential Type')) - ->setValue($type->getCredentialTypeName())) ->appendChild( id(new AphrontFormDividerControl())) ->appendControl( @@ -322,10 +318,9 @@ final class PassphraseCredentialEditController extends PassphraseController { $crumbs->setBorder(true); if ($is_new) { - $title = pht('Create New Credential'); + $title = pht('New Credential: %s', $type->getCredentialTypeName()); $crumbs->addTextCrumb(pht('Create')); $cancel_uri = $this->getApplicationURI(); - $header_icon = 'fa-plus-square'; } else { $title = pht('Edit Credential: %s', $credential->getName()); $crumbs->addTextCrumb( @@ -333,7 +328,6 @@ final class PassphraseCredentialEditController extends PassphraseController { '/K'.$credential->getID()); $crumbs->addTextCrumb(pht('Edit')); $cancel_uri = '/K'.$credential->getID(); - $header_icon = 'fa-pencil'; } if ($request->isAjax()) { @@ -356,18 +350,13 @@ final class PassphraseCredentialEditController extends PassphraseController { ->addCancelButton($cancel_uri)); $box = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Credential')) + ->setHeaderText($title) ->setFormErrors($errors) ->setValidationException($validation_exception) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) + ->setBackground(PHUIObjectBoxView::WHITE_CONFIG) ->setForm($form); - $header = id(new PHUIHeaderView()) - ->setHeader($title) - ->setHeaderIcon($header_icon); - $view = id(new PHUITwoColumnView()) - ->setHeader($header) ->setFooter(array( $box, )); From 8e9f0496266a3d328507ad79ee4e34402ac171dd Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 7 Sep 2017 13:37:41 -0700 Subject: [PATCH 49/54] Provide "bin/storage analyze" and make "bin/storage upgrade" run analysis automatically Summary: Ref T12819. Normallly "ANALYZE TABLE" is like sprinkling magic pixie dust on the database and hoping it will make "good vibes" that cause it to go faster, but in at least some concrete cases with the ngrams tables there really was a key cardinality issue which ANALYZE TABLE corrected, fixing bogus query plans. Add `bin/storage analyze` to analyze all tables, and make `bin/storage upgrade` run it after adjustment if `--no-adjust` is not specified, and make `bin/storage adjust` run it always. This runs in a couple seconds and should never hurt anything, so it should be fine to sprinkle lots of pixie dust into the `bin/storage` workflow. Test Plan: Ran `bin/storage analyze`. Ran `bin/storage upgrade`, saw analyze run. Totally felt great vibes and really aligned chakras on the database. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12819 Differential Revision: https://secure.phabricator.com/D18573 --- src/__phutil_library_map__.php | 2 + ...icatorStorageManagementAnalyzeWorkflow.php | 19 ++++++ .../PhabricatorStorageManagementWorkflow.php | 58 +++++++++++++++++++ 3 files changed, 79 insertions(+) create mode 100644 src/infrastructure/storage/management/workflow/PhabricatorStorageManagementAnalyzeWorkflow.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 6c18759cb9..83714d4e13 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -4088,6 +4088,7 @@ phutil_register_library_map(array( 'PhabricatorStorageFixtureScopeGuard' => 'infrastructure/testing/fixture/PhabricatorStorageFixtureScopeGuard.php', 'PhabricatorStorageManagementAPI' => 'infrastructure/storage/management/PhabricatorStorageManagementAPI.php', 'PhabricatorStorageManagementAdjustWorkflow' => 'infrastructure/storage/management/workflow/PhabricatorStorageManagementAdjustWorkflow.php', + 'PhabricatorStorageManagementAnalyzeWorkflow' => 'infrastructure/storage/management/workflow/PhabricatorStorageManagementAnalyzeWorkflow.php', 'PhabricatorStorageManagementDatabasesWorkflow' => 'infrastructure/storage/management/workflow/PhabricatorStorageManagementDatabasesWorkflow.php', 'PhabricatorStorageManagementDestroyWorkflow' => 'infrastructure/storage/management/workflow/PhabricatorStorageManagementDestroyWorkflow.php', 'PhabricatorStorageManagementDumpWorkflow' => 'infrastructure/storage/management/workflow/PhabricatorStorageManagementDumpWorkflow.php', @@ -9679,6 +9680,7 @@ phutil_register_library_map(array( 'PhabricatorStorageFixtureScopeGuard' => 'Phobject', 'PhabricatorStorageManagementAPI' => 'Phobject', 'PhabricatorStorageManagementAdjustWorkflow' => 'PhabricatorStorageManagementWorkflow', + 'PhabricatorStorageManagementAnalyzeWorkflow' => 'PhabricatorStorageManagementWorkflow', 'PhabricatorStorageManagementDatabasesWorkflow' => 'PhabricatorStorageManagementWorkflow', 'PhabricatorStorageManagementDestroyWorkflow' => 'PhabricatorStorageManagementWorkflow', 'PhabricatorStorageManagementDumpWorkflow' => 'PhabricatorStorageManagementWorkflow', diff --git a/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementAnalyzeWorkflow.php b/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementAnalyzeWorkflow.php new file mode 100644 index 0000000000..54a4bf3d36 --- /dev/null +++ b/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementAnalyzeWorkflow.php @@ -0,0 +1,19 @@ +setName('analyze') + ->setExamples('**analyze**') + ->setSynopsis( + pht('Run "ANALYZE TABLE" on tables to improve performance.')); + } + + public function didExecute(PhutilArgumentParser $args) { + $this->analyzeTables(); + return 0; + } + +} diff --git a/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementWorkflow.php b/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementWorkflow.php index 48d753781d..85d0c09c73 100644 --- a/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementWorkflow.php +++ b/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementWorkflow.php @@ -137,6 +137,15 @@ abstract class PhabricatorStorageManagementWorkflow try { $err = $this->doAdjustSchemata($api, $unsafe); + + // Analyze tables if we're not doing a dry run and adjustments are either + // all clear or have minor errors like surplus tables. + if (!$this->dryRun) { + $should_analyze = (($err == 0) || ($err == 2)); + if ($should_analyze) { + $this->analyzeTables(); + } + } } catch (Exception $ex) { $lock->unlock(); throw $ex; @@ -1163,4 +1172,53 @@ abstract class PhabricatorStorageManagementWorkflow ->lock(); } + final protected function analyzeTables() { + // Analyzing tables can sometimes have a significant effect on query + // performance, particularly for the fulltext ngrams tables. See T12819 + // for some specific examples. + + $api = $this->getSingleAPI(); + $conn = $api->getConn(null); + + $patches = $this->getPatches(); + $databases = $api->getDatabaseList($patches, true); + + $this->logInfo( + pht('ANALYZE'), + pht('Analyzing tables...')); + + $targets = array(); + foreach ($databases as $database) { + queryfx($conn, 'USE %C', $database); + $tables = queryfx_all($conn, 'SHOW TABLE STATUS'); + foreach ($tables as $table) { + $table_name = $table['Name']; + + $targets[] = array( + 'database' => $database, + 'table' => $table_name, + ); + } + } + + $bar = id(new PhutilConsoleProgressBar()) + ->setTotal(count($targets)); + foreach ($targets as $target) { + queryfx( + $conn, + 'ANALYZE TABLE %T.%T', + $target['database'], + $target['table']); + + $bar->update(1); + } + $bar->done(); + + $this->logOkay( + pht('ANALYZED'), + pht( + 'Analyzed %d table(s).', + count($targets))); + } + } From a46a9ff165bd0254b31a7ede38b474e9f7897531 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Thu, 7 Sep 2017 15:38:33 -0700 Subject: [PATCH 50/54] Update VCS password UI Summary: Miss this with earlier pass, updates the VCS password page. Test Plan: Try to set a vcs password Reviewers: epriestley Reviewed By: epriestley Spies: Korvin Differential Revision: https://secure.phabricator.com/D18574 --- .../diffusion/panel/DiffusionSetPasswordSettingsPanel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/applications/diffusion/panel/DiffusionSetPasswordSettingsPanel.php b/src/applications/diffusion/panel/DiffusionSetPasswordSettingsPanel.php index a41f322a3d..ccfa0df4a4 100644 --- a/src/applications/diffusion/panel/DiffusionSetPasswordSettingsPanel.php +++ b/src/applications/diffusion/panel/DiffusionSetPasswordSettingsPanel.php @@ -233,7 +233,7 @@ final class DiffusionSetPasswordSettingsPanel extends PhabricatorSettingsPanel { $object_box = id(new PHUIObjectBoxView()) ->setHeaderText($title) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) + ->setBackground(PHUIObjectBoxView::WHITE_CONFIG) ->setForm($form) ->setFormErrors($errors); @@ -259,7 +259,7 @@ final class DiffusionSetPasswordSettingsPanel extends PhabricatorSettingsPanel { $remove_box = id(new PHUIObjectBoxView()) ->setHeaderText(pht('Remove VCS Password')) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) + ->setBackground(PHUIObjectBoxView::WHITE_CONFIG) ->setForm($remove_form); $saved = null; From 4cae4a3b767fb505c32efd7ab7d8c6c185c59b96 Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 7 Sep 2017 14:52:38 -0700 Subject: [PATCH 51/54] Correct `bin/storage analyze` internal API for cluster environments Summary: Ref T12819. This worked right in a non-cluster environment, but `bin/storage upgrade` iterates over each master in a partitioned cluster environment. Tweak the API so `bin/storage analyze` targets a single host but `bin/storage upgrade` can hit all the masters. Test Plan: Will run `bin/storage upgrade` in production again. Ran `upgrade` and `analyze` locally, still work fine. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12819 Differential Revision: https://secure.phabricator.com/D18576 --- .../PhabricatorStorageManagementAnalyzeWorkflow.php | 3 ++- .../workflow/PhabricatorStorageManagementWorkflow.php | 7 ++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementAnalyzeWorkflow.php b/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementAnalyzeWorkflow.php index 54a4bf3d36..6fe3e60926 100644 --- a/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementAnalyzeWorkflow.php +++ b/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementAnalyzeWorkflow.php @@ -12,7 +12,8 @@ final class PhabricatorStorageManagementAnalyzeWorkflow } public function didExecute(PhutilArgumentParser $args) { - $this->analyzeTables(); + $api = $this->getSingleAPI(); + $this->analyzeTables($api); return 0; } diff --git a/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementWorkflow.php b/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementWorkflow.php index 85d0c09c73..a03ef41c4d 100644 --- a/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementWorkflow.php +++ b/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementWorkflow.php @@ -143,7 +143,7 @@ abstract class PhabricatorStorageManagementWorkflow if (!$this->dryRun) { $should_analyze = (($err == 0) || ($err == 2)); if ($should_analyze) { - $this->analyzeTables(); + $this->analyzeTables($api); } } } catch (Exception $ex) { @@ -1172,12 +1172,13 @@ abstract class PhabricatorStorageManagementWorkflow ->lock(); } - final protected function analyzeTables() { + final protected function analyzeTables( + PhabricatorStorageManagementAPI $api) { + // Analyzing tables can sometimes have a significant effect on query // performance, particularly for the fulltext ngrams tables. See T12819 // for some specific examples. - $api = $this->getSingleAPI(); $conn = $api->getConn(null); $patches = $this->getPatches(); From 7ea6de6e9c9da3ce818ac65c78da8065b73e6d67 Mon Sep 17 00:00:00 2001 From: epriestley Date: Fri, 8 Sep 2017 08:06:16 -0700 Subject: [PATCH 52/54] Split Ferret engine strings for tokenization on any sequence of whitespace Summary: Ref T12819. Currently, strings are split only on spaces, but newlines (and, if they exist, tabs) should also split strings. Without this, we can fail to get the proper term boundary tokens for words which begin at the start of a line or end at the end of a line. Test Plan: Reindexed a document with "xyz\nabc", saw `"yz "` and `" ab"` term boundary tokens generate properly. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12819 Differential Revision: https://secure.phabricator.com/D18579 --- src/applications/search/ferret/PhabricatorFerretEngine.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/applications/search/ferret/PhabricatorFerretEngine.php b/src/applications/search/ferret/PhabricatorFerretEngine.php index 219130c02c..3c8098c54f 100644 --- a/src/applications/search/ferret/PhabricatorFerretEngine.php +++ b/src/applications/search/ferret/PhabricatorFerretEngine.php @@ -75,7 +75,7 @@ abstract class PhabricatorFerretEngine extends Phobject { public function tokenizeString($value) { $value = trim($value, ' '); - $value = preg_split('/ +/', $value); + $value = preg_split('/\s+/u', $value); return $value; } From d67cc8e5c59c435bca027ac3e5f377aeab23412d Mon Sep 17 00:00:00 2001 From: epriestley Date: Fri, 8 Sep 2017 08:13:08 -0700 Subject: [PATCH 53/54] Remove some redundant information from the Ferret engine index Summary: Ref T12819. The "full" field has all other fields, and the "core" field has "title" and "body". Due to the way the "full" and "core" fields were being built, the "core" field also got included in the "full" field, so the "full" field has two copies of the title, two copies of the body, and then one copy of everything else. Put only one copy of each distinct thing in each "full" and "core". Also, simplify the logic a little bit so we build these virtual fields in a more consistent way. Test Plan: Ran `bin/search index` and looked at the fields in the database, saw less redundant information. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12819 Differential Revision: https://secure.phabricator.com/D18580 --- .../PhabricatorFerretFulltextEngineExtension.php | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/applications/search/engineextension/PhabricatorFerretFulltextEngineExtension.php b/src/applications/search/engineextension/PhabricatorFerretFulltextEngineExtension.php index 4344fe1623..6903072345 100644 --- a/src/applications/search/engineextension/PhabricatorFerretFulltextEngineExtension.php +++ b/src/applications/search/engineextension/PhabricatorFerretFulltextEngineExtension.php @@ -66,9 +66,12 @@ final class PhabricatorFerretFulltextEngineExtension ); break; } - } - $key_all = PhabricatorSearchDocumentFieldType::FIELD_ALL; + $virtual_fields[] = array( + PhabricatorSearchDocumentFieldType::FIELD_ALL, + $raw_corpus, + ); + } $empty_template = array( 'raw' => array(), @@ -76,9 +79,7 @@ final class PhabricatorFerretFulltextEngineExtension 'normal' => array(), ); - $ferret_corpus_map = array( - $key_all => $empty_template, - ); + $ferret_corpus_map = array(); foreach ($virtual_fields as $field) { list($key, $raw_corpus) = $field; @@ -98,10 +99,6 @@ final class PhabricatorFerretFulltextEngineExtension $ferret_corpus_map[$key]['raw'][] = $raw_corpus; $ferret_corpus_map[$key]['term'][] = $term_corpus; $ferret_corpus_map[$key]['normal'][] = $normal_corpus; - - $ferret_corpus_map[$key_all]['raw'][] = $raw_corpus; - $ferret_corpus_map[$key_all]['term'][] = $term_corpus; - $ferret_corpus_map[$key_all]['normal'][] = $normal_corpus; } $ferret_fields = array(); From c662dda0f17d886fb864ecfde0e8b37b4fe090f8 Mon Sep 17 00:00:00 2001 From: epriestley Date: Fri, 8 Sep 2017 09:03:32 -0700 Subject: [PATCH 54/54] When selecting Ferret ngrams, select term ngrams (not raw ngrams) for term search Summary: Ref T12819. For queries like `v0.2`, we would incorrectly search for ngrams including `0.2`, but this is only a substring ngram: the term corpus splits this into `v0` and `2`, so `0.2` is not in the ngrams table. When executing term queries, search for term ngrams instead. This makes "v0.2" work properly again. Test Plan: Searched for "v0.2", found a task with "v0.2" in the title. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12819 Differential Revision: https://secure.phabricator.com/D18581 --- .../query/policy/PhabricatorCursorPagedPolicyAwareQuery.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php b/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php index 18e860ebb9..0488ba6133 100644 --- a/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php +++ b/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php @@ -1666,12 +1666,13 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery if ($is_substring) { $ngrams = $engine->getSubstringNgramsFromString($value); } else { - $ngrams = $engine->getTermNgramsFromString($value); + $terms_value = $engine->newTermsCorpus($value); + $ngrams = $engine->getTermNgramsFromString($terms_value); // If this is a stemmed term, only look for ngrams present in both the // unstemmed and stemmed variations. if ($is_stemmed) { - $stem_value = $stemmer->stemToken($value); + $stem_value = $stemmer->stemToken($terms_value); $stem_ngrams = $engine->getTermNgramsFromString($stem_value); $ngrams = array_intersect($ngrams, $stem_ngrams); }