1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-15 18:10:53 +01:00

(stable) Promote 2017 Week 35

This commit is contained in:
epriestley 2017-09-01 13:58:18 -07:00
commit 007fb4c30e
57 changed files with 1196 additions and 113 deletions

View file

@ -9,7 +9,7 @@ return array(
'names' => array( 'names' => array(
'conpherence.pkg.css' => 'e68cf1fa', 'conpherence.pkg.css' => 'e68cf1fa',
'conpherence.pkg.js' => 'b5b51108', 'conpherence.pkg.js' => 'b5b51108',
'core.pkg.css' => '291cbd98', 'core.pkg.css' => '4ac857bf',
'core.pkg.js' => '6c085267', 'core.pkg.js' => '6c085267',
'darkconsole.pkg.js' => '1f9a31bc', 'darkconsole.pkg.js' => '1f9a31bc',
'differential.pkg.css' => '45951e9e', 'differential.pkg.css' => '45951e9e',
@ -29,10 +29,10 @@ return array(
'rsrc/css/aphront/dialog-view.css' => '6bfc244b', 'rsrc/css/aphront/dialog-view.css' => '6bfc244b',
'rsrc/css/aphront/list-filter-view.css' => '5d6f0526', 'rsrc/css/aphront/list-filter-view.css' => '5d6f0526',
'rsrc/css/aphront/multi-column.css' => '84cc6640', 'rsrc/css/aphront/multi-column.css' => '84cc6640',
'rsrc/css/aphront/notification.css' => '3f6c89c9', 'rsrc/css/aphront/notification.css' => '457861ec',
'rsrc/css/aphront/panel-view.css' => '8427b78d', 'rsrc/css/aphront/panel-view.css' => '8427b78d',
'rsrc/css/aphront/phabricator-nav-view.css' => 'faf6a6fc', 'rsrc/css/aphront/phabricator-nav-view.css' => 'faf6a6fc',
'rsrc/css/aphront/table-view.css' => 'a3aa6910', 'rsrc/css/aphront/table-view.css' => '8c9bbafe',
'rsrc/css/aphront/tokenizer.css' => '15d5ff71', 'rsrc/css/aphront/tokenizer.css' => '15d5ff71',
'rsrc/css/aphront/tooltip.css' => '173b9431', 'rsrc/css/aphront/tooltip.css' => '173b9431',
'rsrc/css/aphront/typeahead-browse.css' => 'f2818435', 'rsrc/css/aphront/typeahead-browse.css' => 'f2818435',
@ -40,7 +40,7 @@ return array(
'rsrc/css/application/almanac/almanac.css' => 'dbb9b3af', 'rsrc/css/application/almanac/almanac.css' => 'dbb9b3af',
'rsrc/css/application/auth/auth.css' => '0877ed6e', 'rsrc/css/application/auth/auth.css' => '0877ed6e',
'rsrc/css/application/base/main-menu-view.css' => '1802a242', 'rsrc/css/application/base/main-menu-view.css' => '1802a242',
'rsrc/css/application/base/notification-menu.css' => '73fefdfa', 'rsrc/css/application/base/notification-menu.css' => '10685bd4',
'rsrc/css/application/base/phui-theme.css' => '9f261c6b', 'rsrc/css/application/base/phui-theme.css' => '9f261c6b',
'rsrc/css/application/base/standard-page-view.css' => '34ee718b', 'rsrc/css/application/base/standard-page-view.css' => '34ee718b',
'rsrc/css/application/chatlog/chatlog.css' => 'd295b020', 'rsrc/css/application/chatlog/chatlog.css' => 'd295b020',
@ -74,8 +74,8 @@ return array(
'rsrc/css/application/diffusion/diffusion-icons.css' => '0c15255e', 'rsrc/css/application/diffusion/diffusion-icons.css' => '0c15255e',
'rsrc/css/application/diffusion/diffusion-readme.css' => '419dd5b6', 'rsrc/css/application/diffusion/diffusion-readme.css' => '419dd5b6',
'rsrc/css/application/diffusion/diffusion-repository.css' => 'ee6f20ec', 'rsrc/css/application/diffusion/diffusion-repository.css' => 'ee6f20ec',
'rsrc/css/application/diffusion/diffusion-source.css' => '47db8a7c', 'rsrc/css/application/diffusion/diffusion-source.css' => '69ac9399',
'rsrc/css/application/diffusion/diffusion.css' => 'ceacf994', 'rsrc/css/application/diffusion/diffusion.css' => '45727264',
'rsrc/css/application/feed/feed.css' => 'ecd4ec57', 'rsrc/css/application/feed/feed.css' => 'ecd4ec57',
'rsrc/css/application/files/global-drag-and-drop.css' => 'b556a948', 'rsrc/css/application/files/global-drag-and-drop.css' => 'b556a948',
'rsrc/css/application/flag/flag.css' => 'bba8f811', 'rsrc/css/application/flag/flag.css' => 'bba8f811',
@ -110,7 +110,7 @@ return array(
'rsrc/css/application/releeph/releeph-preview-branch.css' => 'b7a6f4a5', 'rsrc/css/application/releeph/releeph-preview-branch.css' => 'b7a6f4a5',
'rsrc/css/application/releeph/releeph-request-differential-create-dialog.css' => '8d8b92cd', 'rsrc/css/application/releeph/releeph-request-differential-create-dialog.css' => '8d8b92cd',
'rsrc/css/application/releeph/releeph-request-typeahead.css' => '667a48ae', 'rsrc/css/application/releeph/releeph-request-typeahead.css' => '667a48ae',
'rsrc/css/application/search/application-search-view.css' => '66ee5d46', 'rsrc/css/application/search/application-search-view.css' => '787f5b76',
'rsrc/css/application/search/search-results.css' => '505dd8cf', 'rsrc/css/application/search/search-results.css' => '505dd8cf',
'rsrc/css/application/slowvote/slowvote.css' => 'a94b7230', 'rsrc/css/application/slowvote/slowvote.css' => 'a94b7230',
'rsrc/css/application/tokens/tokens.css' => '3d0f239e', 'rsrc/css/application/tokens/tokens.css' => '3d0f239e',
@ -127,7 +127,7 @@ return array(
'rsrc/css/layout/phabricator-source-code-view.css' => 'aea41829', 'rsrc/css/layout/phabricator-source-code-view.css' => 'aea41829',
'rsrc/css/phui/button/phui-button-bar.css' => 'f1ff5494', 'rsrc/css/phui/button/phui-button-bar.css' => 'f1ff5494',
'rsrc/css/phui/button/phui-button-simple.css' => '8e1baf68', 'rsrc/css/phui/button/phui-button-simple.css' => '8e1baf68',
'rsrc/css/phui/button/phui-button.css' => 'a37aa3a8', 'rsrc/css/phui/button/phui-button.css' => '1863cc6e',
'rsrc/css/phui/calendar/phui-calendar-day.css' => '572b1893', 'rsrc/css/phui/calendar/phui-calendar-day.css' => '572b1893',
'rsrc/css/phui/calendar/phui-calendar-list.css' => '576be600', 'rsrc/css/phui/calendar/phui-calendar-list.css' => '576be600',
'rsrc/css/phui/calendar/phui-calendar-month.css' => '21154caf', 'rsrc/css/phui/calendar/phui-calendar-month.css' => '21154caf',
@ -141,7 +141,7 @@ return array(
'rsrc/css/phui/phui-action-list.css' => 'e7eba156', 'rsrc/css/phui/phui-action-list.css' => 'e7eba156',
'rsrc/css/phui/phui-action-panel.css' => 'b4798122', 'rsrc/css/phui/phui-action-panel.css' => 'b4798122',
'rsrc/css/phui/phui-badge.css' => '22c0cf4f', 'rsrc/css/phui/phui-badge.css' => '22c0cf4f',
'rsrc/css/phui/phui-basic-nav-view.css' => 'a0705f53', 'rsrc/css/phui/phui-basic-nav-view.css' => '98c11ab3',
'rsrc/css/phui/phui-big-info-view.css' => 'acc3492c', 'rsrc/css/phui/phui-big-info-view.css' => 'acc3492c',
'rsrc/css/phui/phui-box.css' => '745e881d', 'rsrc/css/phui/phui-box.css' => '745e881d',
'rsrc/css/phui/phui-chart.css' => '6bf6f78e', 'rsrc/css/phui/phui-chart.css' => '6bf6f78e',
@ -178,7 +178,7 @@ return array(
'rsrc/css/phui/phui-status.css' => 'd5263e49', 'rsrc/css/phui/phui-status.css' => 'd5263e49',
'rsrc/css/phui/phui-tag-view.css' => 'b4719c50', 'rsrc/css/phui/phui-tag-view.css' => 'b4719c50',
'rsrc/css/phui/phui-timeline-view.css' => 'f21db7ca', 'rsrc/css/phui/phui-timeline-view.css' => 'f21db7ca',
'rsrc/css/phui/phui-two-column-view.css' => '76dcd3d4', 'rsrc/css/phui/phui-two-column-view.css' => 'bf86c483',
'rsrc/css/phui/workboards/phui-workboard-color.css' => '783cdff5', 'rsrc/css/phui/workboards/phui-workboard-color.css' => '783cdff5',
'rsrc/css/phui/workboards/phui-workboard.css' => '3bc85455', 'rsrc/css/phui/workboards/phui-workboard.css' => '3bc85455',
'rsrc/css/phui/workboards/phui-workcard.css' => 'cca5fa92', 'rsrc/css/phui/workboards/phui-workcard.css' => 'cca5fa92',
@ -529,7 +529,7 @@ return array(
'rsrc/js/phuix/PHUIXActionListView.js' => 'b5c256b8', 'rsrc/js/phuix/PHUIXActionListView.js' => 'b5c256b8',
'rsrc/js/phuix/PHUIXActionView.js' => '442efd08', 'rsrc/js/phuix/PHUIXActionView.js' => '442efd08',
'rsrc/js/phuix/PHUIXAutocomplete.js' => '4b7430ab', 'rsrc/js/phuix/PHUIXAutocomplete.js' => '4b7430ab',
'rsrc/js/phuix/PHUIXButtonView.js' => 'a37126bd', 'rsrc/js/phuix/PHUIXButtonView.js' => '8a91e1ac',
'rsrc/js/phuix/PHUIXDropdownMenu.js' => '8018ee50', 'rsrc/js/phuix/PHUIXDropdownMenu.js' => '8018ee50',
'rsrc/js/phuix/PHUIXExample.js' => '68af71ca', 'rsrc/js/phuix/PHUIXExample.js' => '68af71ca',
'rsrc/js/phuix/PHUIXFormControl.js' => '83e03671', 'rsrc/js/phuix/PHUIXFormControl.js' => '83e03671',
@ -543,11 +543,11 @@ return array(
'aphront-list-filter-view-css' => '5d6f0526', 'aphront-list-filter-view-css' => '5d6f0526',
'aphront-multi-column-view-css' => '84cc6640', 'aphront-multi-column-view-css' => '84cc6640',
'aphront-panel-view-css' => '8427b78d', 'aphront-panel-view-css' => '8427b78d',
'aphront-table-view-css' => 'a3aa6910', 'aphront-table-view-css' => '8c9bbafe',
'aphront-tokenizer-control-css' => '15d5ff71', 'aphront-tokenizer-control-css' => '15d5ff71',
'aphront-tooltip-css' => '173b9431', 'aphront-tooltip-css' => '173b9431',
'aphront-typeahead-control-css' => 'a4a21016', 'aphront-typeahead-control-css' => 'a4a21016',
'application-search-view-css' => '66ee5d46', 'application-search-view-css' => '787f5b76',
'auth-css' => '0877ed6e', 'auth-css' => '0877ed6e',
'bulk-job-css' => 'df9c1d4a', 'bulk-job-css' => 'df9c1d4a',
'conduit-api-css' => '7bc725c4', 'conduit-api-css' => '7bc725c4',
@ -570,11 +570,11 @@ return array(
'differential-revision-history-css' => '0e8eb855', 'differential-revision-history-css' => '0e8eb855',
'differential-revision-list-css' => 'f3c47d33', 'differential-revision-list-css' => 'f3c47d33',
'differential-table-of-contents-css' => 'ae4b7a55', 'differential-table-of-contents-css' => 'ae4b7a55',
'diffusion-css' => 'ceacf994', 'diffusion-css' => '45727264',
'diffusion-icons-css' => '0c15255e', 'diffusion-icons-css' => '0c15255e',
'diffusion-readme-css' => '419dd5b6', 'diffusion-readme-css' => '419dd5b6',
'diffusion-repository-css' => 'ee6f20ec', 'diffusion-repository-css' => 'ee6f20ec',
'diffusion-source-css' => '47db8a7c', 'diffusion-source-css' => '69ac9399',
'diviner-shared-css' => '896f1d43', 'diviner-shared-css' => '896f1d43',
'font-fontawesome' => 'e838e088', 'font-fontawesome' => 'e838e088',
'font-lato' => 'c7ccd872', 'font-lato' => 'c7ccd872',
@ -792,8 +792,8 @@ return array(
'phabricator-main-menu-view' => '1802a242', 'phabricator-main-menu-view' => '1802a242',
'phabricator-nav-view-css' => 'faf6a6fc', 'phabricator-nav-view-css' => 'faf6a6fc',
'phabricator-notification' => '5c3349b2', 'phabricator-notification' => '5c3349b2',
'phabricator-notification-css' => '3f6c89c9', 'phabricator-notification-css' => '457861ec',
'phabricator-notification-menu-css' => '73fefdfa', 'phabricator-notification-menu-css' => '10685bd4',
'phabricator-object-selector-css' => '85ee8ce6', 'phabricator-object-selector-css' => '85ee8ce6',
'phabricator-phtize' => 'd254d646', 'phabricator-phtize' => 'd254d646',
'phabricator-prefab' => 'c5af80a2', 'phabricator-prefab' => 'c5af80a2',
@ -820,11 +820,11 @@ return array(
'phriction-document-css' => '4282e4ad', 'phriction-document-css' => '4282e4ad',
'phui-action-panel-css' => 'b4798122', 'phui-action-panel-css' => 'b4798122',
'phui-badge-view-css' => '22c0cf4f', 'phui-badge-view-css' => '22c0cf4f',
'phui-basic-nav-view-css' => 'a0705f53', 'phui-basic-nav-view-css' => '98c11ab3',
'phui-big-info-view-css' => 'acc3492c', 'phui-big-info-view-css' => 'acc3492c',
'phui-box-css' => '745e881d', 'phui-box-css' => '745e881d',
'phui-button-bar-css' => 'f1ff5494', 'phui-button-bar-css' => 'f1ff5494',
'phui-button-css' => 'a37aa3a8', 'phui-button-css' => '1863cc6e',
'phui-button-simple-css' => '8e1baf68', 'phui-button-simple-css' => '8e1baf68',
'phui-calendar-css' => 'f1ddf11c', 'phui-calendar-css' => 'f1ddf11c',
'phui-calendar-day-css' => '572b1893', 'phui-calendar-day-css' => '572b1893',
@ -874,7 +874,7 @@ return array(
'phui-tag-view-css' => 'b4719c50', 'phui-tag-view-css' => 'b4719c50',
'phui-theme-css' => '9f261c6b', 'phui-theme-css' => '9f261c6b',
'phui-timeline-view-css' => 'f21db7ca', 'phui-timeline-view-css' => 'f21db7ca',
'phui-two-column-view-css' => '76dcd3d4', 'phui-two-column-view-css' => 'bf86c483',
'phui-workboard-color-css' => '783cdff5', 'phui-workboard-color-css' => '783cdff5',
'phui-workboard-view-css' => '3bc85455', 'phui-workboard-view-css' => '3bc85455',
'phui-workcard-view-css' => 'cca5fa92', 'phui-workcard-view-css' => 'cca5fa92',
@ -882,7 +882,7 @@ return array(
'phuix-action-list-view' => 'b5c256b8', 'phuix-action-list-view' => 'b5c256b8',
'phuix-action-view' => '442efd08', 'phuix-action-view' => '442efd08',
'phuix-autocomplete' => '4b7430ab', 'phuix-autocomplete' => '4b7430ab',
'phuix-button-view' => 'a37126bd', 'phuix-button-view' => '8a91e1ac',
'phuix-dropdown-menu' => '8018ee50', 'phuix-dropdown-menu' => '8018ee50',
'phuix-form-control-view' => '83e03671', 'phuix-form-control-view' => '83e03671',
'phuix-icon-view' => 'bff6884b', 'phuix-icon-view' => 'bff6884b',
@ -1557,6 +1557,10 @@ return array(
'javelin-install', 'javelin-install',
'javelin-dom', 'javelin-dom',
), ),
'8a91e1ac' => array(
'javelin-install',
'javelin-dom',
),
'8ce821c5' => array( '8ce821c5' => array(
'phabricator-notification', 'phabricator-notification',
'javelin-stratcom', 'javelin-stratcom',
@ -1696,10 +1700,6 @@ return array(
'javelin-sound', 'javelin-sound',
'phabricator-notification', 'phabricator-notification',
), ),
'a37126bd' => array(
'javelin-install',
'javelin-dom',
),
'a3a63478' => array( 'a3a63478' => array(
'phui-workcard-view-css', 'phui-workcard-view-css',
), ),

View file

@ -0,0 +1,9 @@
CREATE TABLE {$NAMESPACE}_maniphest.maniphest_task_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};

View file

@ -0,0 +1,7 @@
CREATE TABLE {$NAMESPACE}_maniphest.maniphest_task_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},
normalCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT}
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};

View file

@ -0,0 +1,5 @@
CREATE TABLE {$NAMESPACE}_maniphest.maniphest_task_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};

View file

@ -0,0 +1,4 @@
TRUNCATE TABLE {$NAMESPACE}_maniphest.maniphest_task_ffield;
ALTER TABLE {$NAMESPACE}_maniphest.maniphest_task_ffield
ADD UNIQUE KEY `key_documentfield` (documentID, fieldKey);

View file

@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_maniphest.maniphest_task_ffield
ADD termCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT};

View file

@ -1533,6 +1533,10 @@ phutil_register_library_map(array(
'ManiphestTaskEditBulkJobType' => 'applications/maniphest/bulk/ManiphestTaskEditBulkJobType.php', 'ManiphestTaskEditBulkJobType' => 'applications/maniphest/bulk/ManiphestTaskEditBulkJobType.php',
'ManiphestTaskEditController' => 'applications/maniphest/controller/ManiphestTaskEditController.php', 'ManiphestTaskEditController' => 'applications/maniphest/controller/ManiphestTaskEditController.php',
'ManiphestTaskEditEngineLock' => 'applications/maniphest/editor/ManiphestTaskEditEngineLock.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', 'ManiphestTaskFulltextEngine' => 'applications/maniphest/search/ManiphestTaskFulltextEngine.php',
'ManiphestTaskGraph' => 'infrastructure/graph/ManiphestTaskGraph.php', 'ManiphestTaskGraph' => 'infrastructure/graph/ManiphestTaskGraph.php',
'ManiphestTaskHasCommitEdgeType' => 'applications/maniphest/edge/ManiphestTaskHasCommitEdgeType.php', 'ManiphestTaskHasCommitEdgeType' => 'applications/maniphest/edge/ManiphestTaskHasCommitEdgeType.php',
@ -2828,6 +2832,12 @@ phutil_register_library_map(array(
'PhabricatorFeedStoryNotification' => 'applications/notification/storage/PhabricatorFeedStoryNotification.php', 'PhabricatorFeedStoryNotification' => 'applications/notification/storage/PhabricatorFeedStoryNotification.php',
'PhabricatorFeedStoryPublisher' => 'applications/feed/PhabricatorFeedStoryPublisher.php', 'PhabricatorFeedStoryPublisher' => 'applications/feed/PhabricatorFeedStoryPublisher.php',
'PhabricatorFeedStoryReference' => 'applications/feed/storage/PhabricatorFeedStoryReference.php', 'PhabricatorFeedStoryReference' => 'applications/feed/storage/PhabricatorFeedStoryReference.php',
'PhabricatorFerretDocument' => 'applications/search/ferret/PhabricatorFerretDocument.php',
'PhabricatorFerretEngine' => 'applications/search/ferret/PhabricatorFerretEngine.php',
'PhabricatorFerretField' => 'applications/search/ferret/PhabricatorFerretField.php',
'PhabricatorFerretFulltextEngineExtension' => 'applications/search/engineextension/PhabricatorFerretFulltextEngineExtension.php',
'PhabricatorFerretInterface' => 'applications/search/ferret/PhabricatorFerretInterface.php',
'PhabricatorFerretNgrams' => 'applications/search/ferret/PhabricatorFerretNgrams.php',
'PhabricatorFile' => 'applications/files/storage/PhabricatorFile.php', 'PhabricatorFile' => 'applications/files/storage/PhabricatorFile.php',
'PhabricatorFileAES256StorageFormat' => 'applications/files/format/PhabricatorFileAES256StorageFormat.php', 'PhabricatorFileAES256StorageFormat' => 'applications/files/format/PhabricatorFileAES256StorageFormat.php',
'PhabricatorFileBundleLoader' => 'applications/files/query/PhabricatorFileBundleLoader.php', 'PhabricatorFileBundleLoader' => 'applications/files/query/PhabricatorFileBundleLoader.php',
@ -3195,6 +3205,8 @@ phutil_register_library_map(array(
'PhabricatorNamedQueryQuery' => 'applications/search/query/PhabricatorNamedQueryQuery.php', 'PhabricatorNamedQueryQuery' => 'applications/search/query/PhabricatorNamedQueryQuery.php',
'PhabricatorNavigationRemarkupRule' => 'infrastructure/markup/rule/PhabricatorNavigationRemarkupRule.php', 'PhabricatorNavigationRemarkupRule' => 'infrastructure/markup/rule/PhabricatorNavigationRemarkupRule.php',
'PhabricatorNeverTriggerClock' => 'infrastructure/daemon/workers/clock/PhabricatorNeverTriggerClock.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', 'PhabricatorNgramsIndexEngineExtension' => 'applications/search/engineextension/PhabricatorNgramsIndexEngineExtension.php',
'PhabricatorNgramsInterface' => 'applications/search/interface/PhabricatorNgramsInterface.php', 'PhabricatorNgramsInterface' => 'applications/search/interface/PhabricatorNgramsInterface.php',
'PhabricatorNotificationBuilder' => 'applications/notification/builder/PhabricatorNotificationBuilder.php', 'PhabricatorNotificationBuilder' => 'applications/notification/builder/PhabricatorNotificationBuilder.php',
@ -6659,6 +6671,7 @@ phutil_register_library_map(array(
'PhabricatorSpacesInterface', 'PhabricatorSpacesInterface',
'PhabricatorConduitResultInterface', 'PhabricatorConduitResultInterface',
'PhabricatorFulltextInterface', 'PhabricatorFulltextInterface',
'PhabricatorFerretInterface',
'DoorkeeperBridgedObjectInterface', 'DoorkeeperBridgedObjectInterface',
'PhabricatorEditEngineSubtypeInterface', 'PhabricatorEditEngineSubtypeInterface',
'PhabricatorEditEngineLockableInterface', 'PhabricatorEditEngineLockableInterface',
@ -6682,6 +6695,10 @@ phutil_register_library_map(array(
'ManiphestTaskEditBulkJobType' => 'PhabricatorWorkerBulkJobType', 'ManiphestTaskEditBulkJobType' => 'PhabricatorWorkerBulkJobType',
'ManiphestTaskEditController' => 'ManiphestController', 'ManiphestTaskEditController' => 'ManiphestController',
'ManiphestTaskEditEngineLock' => 'PhabricatorEditEngineLock', 'ManiphestTaskEditEngineLock' => 'PhabricatorEditEngineLock',
'ManiphestTaskFerretDocument' => 'PhabricatorFerretDocument',
'ManiphestTaskFerretEngine' => 'PhabricatorFerretEngine',
'ManiphestTaskFerretField' => 'PhabricatorFerretField',
'ManiphestTaskFerretNgrams' => 'PhabricatorFerretNgrams',
'ManiphestTaskFulltextEngine' => 'PhabricatorFulltextEngine', 'ManiphestTaskFulltextEngine' => 'PhabricatorFulltextEngine',
'ManiphestTaskGraph' => 'PhabricatorObjectGraph', 'ManiphestTaskGraph' => 'PhabricatorObjectGraph',
'ManiphestTaskHasCommitEdgeType' => 'PhabricatorEdgeType', 'ManiphestTaskHasCommitEdgeType' => 'PhabricatorEdgeType',
@ -8147,6 +8164,11 @@ phutil_register_library_map(array(
'PhabricatorFeedStoryNotification' => 'PhabricatorFeedDAO', 'PhabricatorFeedStoryNotification' => 'PhabricatorFeedDAO',
'PhabricatorFeedStoryPublisher' => 'Phobject', 'PhabricatorFeedStoryPublisher' => 'Phobject',
'PhabricatorFeedStoryReference' => 'PhabricatorFeedDAO', 'PhabricatorFeedStoryReference' => 'PhabricatorFeedDAO',
'PhabricatorFerretDocument' => 'PhabricatorSearchDAO',
'PhabricatorFerretEngine' => 'Phobject',
'PhabricatorFerretField' => 'PhabricatorSearchDAO',
'PhabricatorFerretFulltextEngineExtension' => 'PhabricatorFulltextEngineExtension',
'PhabricatorFerretNgrams' => 'PhabricatorSearchDAO',
'PhabricatorFile' => array( 'PhabricatorFile' => array(
'PhabricatorFileDAO', 'PhabricatorFileDAO',
'PhabricatorApplicationTransactionInterface', 'PhabricatorApplicationTransactionInterface',
@ -8565,6 +8587,8 @@ phutil_register_library_map(array(
'PhabricatorNamedQueryQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorNamedQueryQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorNavigationRemarkupRule' => 'PhutilRemarkupRule', 'PhabricatorNavigationRemarkupRule' => 'PhutilRemarkupRule',
'PhabricatorNeverTriggerClock' => 'PhabricatorTriggerClock', 'PhabricatorNeverTriggerClock' => 'PhabricatorTriggerClock',
'PhabricatorNgramEngine' => 'Phobject',
'PhabricatorNgramEngineTestCase' => 'PhabricatorTestCase',
'PhabricatorNgramsIndexEngineExtension' => 'PhabricatorIndexEngineExtension', 'PhabricatorNgramsIndexEngineExtension' => 'PhabricatorIndexEngineExtension',
'PhabricatorNgramsInterface' => 'PhabricatorIndexableInterface', 'PhabricatorNgramsInterface' => 'PhabricatorIndexableInterface',
'PhabricatorNotificationBuilder' => 'Phobject', 'PhabricatorNotificationBuilder' => 'Phobject',

View file

@ -57,6 +57,7 @@ final class DiffusionBranchTableController extends DiffusionController {
$content = id(new PHUIObjectBoxView()) $content = id(new PHUIObjectBoxView())
->setHeaderText($repository->getName()) ->setHeaderText($repository->getName())
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addClass('diffusion-mobile-view')
->setTable($list) ->setTable($list)
->setPager($pager); ->setPager($pager);
} }

View file

@ -371,6 +371,7 @@ final class DiffusionBrowseController extends DiffusionController {
->setHeader($browse_header) ->setHeader($browse_header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setTable($browse_table) ->setTable($browse_table)
->addClass('diffusion-mobile-view')
->setPager($pager); ->setPager($pager);
$path = $drequest->getPath(); $path = $drequest->getPath();
@ -595,6 +596,8 @@ final class DiffusionBrowseController extends DiffusionController {
), ),
$rows); $rows);
$corpus_table = phutil_tag_div('diffusion-source-wrap', $corpus_table);
if ($this->getRequest()->isAjax()) { if ($this->getRequest()->isAjax()) {
return $corpus_table; return $corpus_table;
} }
@ -654,6 +657,7 @@ final class DiffusionBrowseController extends DiffusionController {
->setHeader($header) ->setHeader($header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->appendChild($corpus) ->appendChild($corpus)
->addClass('diffusion-mobile-view')
->setCollapsed(true); ->setCollapsed(true);
$messages = array(); $messages = array();
@ -730,6 +734,7 @@ final class DiffusionBrowseController extends DiffusionController {
->setText($blame_text) ->setText($blame_text)
->setIcon($blame_icon) ->setIcon($blame_icon)
->setUser($viewer) ->setUser($viewer)
->setSelected(!$blame_value)
->setColor(PHUIButtonView::GREY); ->setColor(PHUIButtonView::GREY);
if ($viewer->isLoggedIn()) { if ($viewer->isLoggedIn()) {
@ -859,6 +864,7 @@ final class DiffusionBrowseController extends DiffusionController {
$view = id(new PHUIObjectBoxView()) $view = id(new PHUIObjectBoxView())
->setHeaderText(pht('Owner Packages')) ->setHeaderText(pht('Owner Packages'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addClass('diffusion-mobile-view')
->setObjectList($ownership); ->setObjectList($ownership);
} }
@ -1134,7 +1140,7 @@ final class DiffusionBrowseController extends DiffusionController {
$before_link = null; $before_link = null;
$commit_date = null; $commit_date = null;
$style = 'border-right: 2px solid '.$line['color'].';'; $style = 'border-right: 3px solid '.$line['color'].';';
if ($identifier && !$line['duplicate']) { if ($identifier && !$line['duplicate']) {
if (isset($commit_links[$identifier])) { if (isset($commit_links[$identifier])) {
@ -1340,6 +1346,7 @@ final class DiffusionBrowseController extends DiffusionController {
return id(new PHUIObjectBoxView()) return id(new PHUIObjectBoxView())
->setHeader($header) ->setHeader($header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addClass('diffusion-mobile-view')
->addPropertyList($properties); ->addPropertyList($properties);
} }
@ -1360,6 +1367,7 @@ final class DiffusionBrowseController extends DiffusionController {
$box = id(new PHUIObjectBoxView()) $box = id(new PHUIObjectBoxView())
->setHeader($header) ->setHeader($header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addClass('diffusion-mobile-view')
->appendChild($text); ->appendChild($text);
return $box; return $box;
@ -1692,15 +1700,20 @@ final class DiffusionBrowseController extends DiffusionController {
$header = id(new PHUIHeaderView()) $header = id(new PHUIHeaderView())
->setHeader(pht('Recently Open Revisions')); ->setHeader(pht('Recently Open Revisions'));
$view = id(new DifferentialRevisionListView()) $list = id(new DifferentialRevisionListView())
->setRevisions($revisions)
->setUser($viewer)
->setNoBox(true);
$phids = $list->getRequiredHandlePHIDs();
$handles = $this->loadViewerHandles($phids);
$list->setHandles($handles);
$view = id(new PHUIObjectBoxView())
->setHeader($header) ->setHeader($header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setRevisions($revisions) ->addClass('diffusion-mobile-view')
->setUser($viewer); ->appendChild($list);
$phids = $view->getRequiredHandlePHIDs();
$handles = $this->loadViewerHandles($phids);
$view->setHandles($handles);
return $view; return $view;
} }
@ -1837,6 +1850,7 @@ final class DiffusionBrowseController extends DiffusionController {
$corpus = id(new PHUIObjectBoxView()) $corpus = id(new PHUIObjectBoxView())
->setHeader($header) ->setHeader($header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addClass('diffusion-mobile-view')
->setCollapsed(true); ->setCollapsed(true);
if ($messages) { if ($messages) {
@ -1921,6 +1935,7 @@ final class DiffusionBrowseController extends DiffusionController {
return id(new PHUIObjectBoxView()) return id(new PHUIObjectBoxView())
->setHeader($header) ->setHeader($header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addClass('diffusion-mobile-view')
->setTable($history_table); ->setTable($history_table);
} }

View file

@ -15,6 +15,7 @@ final class DiffusionCompareController extends DiffusionController {
$viewer = $this->getViewer(); $viewer = $this->getViewer();
$drequest = $this->getDiffusionRequest(); $drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository(); $repository = $drequest->getRepository();
require_celerity_resource('diffusion-css');
if (!$repository->supportsBranchComparison()) { if (!$repository->supportsBranchComparison()) {
return $this->newDialog() return $this->newDialog()
@ -315,6 +316,7 @@ final class DiffusionCompareController extends DiffusionController {
->setHeader($header) ->setHeader($header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setTable($history_table) ->setTable($history_table)
->addClass('diffusion-mobile-view')
->setPager($pager); ->setPager($pager);
} }

View file

@ -67,6 +67,7 @@ final class DiffusionGraphController extends DiffusionController {
->setHeaderText(pht('History Graph')) ->setHeaderText(pht('History Graph'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setTable($graph) ->setTable($graph)
->addClass('diffusion-mobile-view')
->setPager($pager); ->setPager($pager);
$tabs = $this->buildTabsView('graph'); $tabs = $this->buildTabsView('graph');

View file

@ -420,7 +420,8 @@ final class DiffusionRepositoryController extends DiffusionController {
$history_table->setIsHead(true); $history_table->setIsHead(true);
$panel = id(new PHUIObjectBoxView()) $panel = id(new PHUIObjectBoxView())
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY); ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addClass('diffusion-mobile-view');
$header = id(new PHUIHeaderView()) $header = id(new PHUIHeaderView())
->setHeader(pht('Recent Commits')); ->setHeader(pht('Recent Commits'));
$panel->setHeader($header); $panel->setHeader($header);
@ -583,6 +584,7 @@ final class DiffusionRepositoryController extends DiffusionController {
->setHeaderText($header) ->setHeaderText($header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setTable($browse_table) ->setTable($browse_table)
->addClass('diffusion-mobile-view')
->setPager($pager); ->setPager($pager);
} }

View file

@ -86,8 +86,11 @@ final class DiffusionRepositoryBranchesManagementPanel
$repository->getHumanReadableDetail('close-commits-filter', array()), $repository->getHumanReadableDetail('close-commits-filter', array()),
phutil_tag('em', array(), pht('Autoclose On All Branches'))); phutil_tag('em', array(), pht('Autoclose On All Branches')));
$autoclose_disabled = false;
if ($repository->getDetail('disable-autoclose')) { if ($repository->getDetail('disable-autoclose')) {
$autoclose_only = phutil_tag('em', array(), pht('Disabled')); $autoclose_disabled = true;
$autoclose_only =
phutil_tag('em', array(), pht('Autoclose has been disabled'));
} }
$view->addProperty(pht('Autoclose Only'), $autoclose_only); $view->addProperty(pht('Autoclose Only'), $autoclose_only);
@ -133,12 +136,18 @@ final class DiffusionRepositoryBranchesManagementPanel
$status = pht('Open'); $status = pht('Open');
} }
if ($autoclose_disabled) {
$autoclose_status = pht('Disabled (Repository)');
} else {
$autoclose_status = pht('Off');
}
$rows[] = array( $rows[] = array(
$icon, $icon,
$branch_name, $branch_name,
$status, $status,
$tracking ? pht('Tracking') : pht('Off'), $tracking ? pht('Tracking') : pht('Off'),
$autoclosing ? pht('Autoclose On') : pht('Off'), $autoclosing ? pht('Autoclose On') : $autoclose_status,
); );
} }
$branch_table = new AphrontTableView($rows); $branch_table = new AphrontTableView($rows);

View file

@ -134,7 +134,7 @@ final class DiffusionBrowseTableView extends DiffusionView {
array( array(
true, true,
false, false,
true, false,
false, false,
false, false,
)); ));

View file

@ -40,6 +40,7 @@ final class DiffusionHistoryListView extends DiffusionHistoryView {
$view[] = id(new PHUIObjectBoxView()) $view[] = id(new PHUIObjectBoxView())
->setHeader($header) ->setHeader($header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addClass('diffusion-mobile-view')
->setObjectList($list); ->setObjectList($list);
} }

View file

@ -105,6 +105,7 @@ final class DiffusionReadmeView extends DiffusionView {
return id(new PHUIObjectBoxView()) return id(new PHUIObjectBoxView())
->setHeader($header) ->setHeader($header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addClass('diffusion-mobile-view')
->appendChild($document) ->appendChild($document)
->addClass('diffusion-readme-view'); ->addClass('diffusion-readme-view');
} }

View file

@ -49,6 +49,8 @@ final class ManiphestTaskSearchEngine
$subtype_map = id(new ManiphestTask())->newEditEngineSubtypeMap(); $subtype_map = id(new ManiphestTask())->newEditEngineSubtypeMap();
$hide_subtypes = (count($subtype_map) == 1); $hide_subtypes = (count($subtype_map) == 1);
$hide_ferret = !PhabricatorEnv::getEnvConfig('phabricator.show-prototypes');
return array( return array(
id(new PhabricatorOwnersSearchField()) id(new PhabricatorOwnersSearchField())
->setLabel(pht('Assigned To')) ->setLabel(pht('Assigned To'))
@ -89,6 +91,10 @@ final class ManiphestTaskSearchEngine
id(new PhabricatorSearchTextField()) id(new PhabricatorSearchTextField())
->setLabel(pht('Contains Words')) ->setLabel(pht('Contains Words'))
->setKey('fulltext'), ->setKey('fulltext'),
id(new PhabricatorSearchTextField())
->setLabel(pht('Query (Prototype)'))
->setKey('query')
->setIsHidden($hide_ferret),
id(new PhabricatorSearchThreeStateField()) id(new PhabricatorSearchThreeStateField())
->setLabel(pht('Open Parents')) ->setLabel(pht('Open Parents'))
->setKey('hasParents') ->setKey('hasParents')
@ -144,6 +150,7 @@ final class ManiphestTaskSearchEngine
'statuses', 'statuses',
'priorities', 'priorities',
'subtypes', 'subtypes',
'query',
'fulltext', 'fulltext',
'hasParents', 'hasParents',
'hasSubtasks', 'hasSubtasks',
@ -224,6 +231,27 @@ final class ManiphestTaskSearchEngine
$query->withFullTextSearch($map['fulltext']); $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']) { if ($map['parentIDs']) {
$query->withParentTaskIDs($map['parentIDs']); $query->withParentTaskIDs($map['parentIDs']);
} }

View file

@ -0,0 +1,18 @@
<?php
final class ManiphestTaskFerretEngine
extends PhabricatorFerretEngine {
public function newNgramsObject() {
return new ManiphestTaskFerretNgrams();
}
public function newDocumentObject() {
return new ManiphestTaskFerretDocument();
}
public function newFieldObject() {
return new ManiphestTaskFerretField();
}
}

View file

@ -16,6 +16,7 @@ final class ManiphestTask extends ManiphestDAO
PhabricatorSpacesInterface, PhabricatorSpacesInterface,
PhabricatorConduitResultInterface, PhabricatorConduitResultInterface,
PhabricatorFulltextInterface, PhabricatorFulltextInterface,
PhabricatorFerretInterface,
DoorkeeperBridgedObjectInterface, DoorkeeperBridgedObjectInterface,
PhabricatorEditEngineSubtypeInterface, PhabricatorEditEngineSubtypeInterface,
PhabricatorEditEngineLockableInterface { PhabricatorEditEngineLockableInterface {
@ -603,4 +604,12 @@ final class ManiphestTask extends ManiphestDAO
return new ManiphestTaskEditEngineLock(); return new ManiphestTaskEditEngineLock();
} }
/* -( PhabricatorFerretInterface )----------------------------------------- */
public function newFerretEngine() {
return new ManiphestTaskFerretEngine();
}
} }

View file

@ -0,0 +1,14 @@
<?php
final class ManiphestTaskFerretDocument
extends PhabricatorFerretDocument {
public function getApplicationName() {
return 'maniphest';
}
public function getIndexKey() {
return 'task';
}
}

View file

@ -0,0 +1,14 @@
<?php
final class ManiphestTaskFerretField
extends PhabricatorFerretField {
public function getApplicationName() {
return 'maniphest';
}
public function getIndexKey() {
return 'task';
}
}

View file

@ -0,0 +1,14 @@
<?php
final class ManiphestTaskFerretNgrams
extends PhabricatorFerretNgrams {
public function getApplicationName() {
return 'maniphest';
}
public function getIndexKey() {
return 'task';
}
}

View file

@ -8,6 +8,17 @@ final class PhabricatorNotificationClearController
$chrono_key = $request->getStr('chronoKey'); $chrono_key = $request->getStr('chronoKey');
if ($request->isDialogFormPost()) { if ($request->isDialogFormPost()) {
$should_clear = true;
} else {
try {
$request->validateCSRF();
$should_clear = true;
} catch (AphrontMalformedRequestException $ex) {
$should_clear = false;
}
}
if ($should_clear) {
$table = new PhabricatorFeedStoryNotification(); $table = new PhabricatorFeedStoryNotification();
queryfx( queryfx(

View file

@ -9,7 +9,7 @@ final class PhabricatorNotificationPanelController
$query = id(new PhabricatorNotificationQuery()) $query = id(new PhabricatorNotificationQuery())
->setViewer($viewer) ->setViewer($viewer)
->withUserPHIDs(array($viewer->getPHID())) ->withUserPHIDs(array($viewer->getPHID()))
->setLimit(15); ->setLimit(10);
$stories = $query->execute(); $stories = $query->execute();

View file

@ -9,11 +9,11 @@ final class PhabricatorProjectsFulltextEngineExtension
return pht('Projects'); return pht('Projects');
} }
public function shouldIndexFulltextObject($object) { public function shouldEnrichFulltextObject($object) {
return ($object instanceof PhabricatorProjectInterface); return ($object instanceof PhabricatorProjectInterface);
} }
public function indexFulltextObject( public function enrichFulltextObject(
$object, $object,
PhabricatorSearchAbstractDocument $document) { PhabricatorSearchAbstractDocument $document) {

View file

@ -609,7 +609,8 @@ final class PhabricatorProjectQuery
} }
if ($this->nameTokens !== null) { if ($this->nameTokens !== null) {
foreach ($this->nameTokens as $key => $token) { $name_tokens = $this->getNameTokensForQuery($this->nameTokens);
foreach ($name_tokens as $key => $token) {
$token_table = 'token_'.$key; $token_table = 'token_'.$key;
$joins[] = qsprintf( $joins[] = qsprintf(
$conn, $conn,
@ -797,4 +798,22 @@ final class PhabricatorProjectQuery
} }
} }
private function getNameTokensForQuery(array $tokens) {
// When querying for projects by name, only actually search for the five
// longest tokens. MySQL can get grumpy with a large number of JOINs
// with LIKEs and queries for more than 5 tokens are essentially never
// legitimate searches for projects, but users copy/pasting nonsense.
// See also PHI47.
$length_map = array();
foreach ($tokens as $token) {
$length_map[$token] = strlen($token);
}
arsort($length_map);
$length_map = array_slice($length_map, 0, 5, true);
return array_keys($length_map);
}
} }

View file

@ -5,5 +5,7 @@ final class PhabricatorSearchDocumentFieldType extends Phobject {
const FIELD_TITLE = 'titl'; const FIELD_TITLE = 'titl';
const FIELD_BODY = 'body'; const FIELD_BODY = 'body';
const FIELD_COMMENT = 'cmnt'; const FIELD_COMMENT = 'cmnt';
const FIELD_ALL = 'full';
const FIELD_CORE = 'core';
} }

View file

@ -0,0 +1,197 @@
<?php
final class PhabricatorFerretFulltextEngineExtension
extends PhabricatorFulltextEngineExtension {
const EXTENSIONKEY = 'ferret';
public function getExtensionName() {
return pht('Ferret Fulltext Engine');
}
public function shouldIndexFulltextObject($object) {
return ($object instanceof PhabricatorFerretInterface);
}
public function indexFulltextObject(
$object,
PhabricatorSearchAbstractDocument $document) {
$phid = $document->getPHID();
$engine = $object->newFerretEngine();
$ferret_document = $engine->newDocumentObject()
->setObjectPHID($phid)
->setIsClosed(0)
->setEpochCreated(0)
->setEpochModified(0);
$stemmer = new PhutilSearchStemmer();
$ngram_engine = id(new PhabricatorNgramEngine());
// 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.
$document_fields = $document->getFieldData();
$virtual_fields = array();
foreach ($document_fields as $field) {
$virtual_fields[] = $field;
list($key, $raw_corpus) = $field;
switch ($key) {
case PhabricatorSearchDocumentFieldType::FIELD_TITLE:
case PhabricatorSearchDocumentFieldType::FIELD_BODY:
$virtual_fields[] = array(
PhabricatorSearchDocumentFieldType::FIELD_CORE,
$raw_corpus,
);
break;
}
}
$key_all = PhabricatorSearchDocumentFieldType::FIELD_ALL;
$empty_template = array(
'raw' => array(),
'term' => array(),
'normal' => array(),
);
$ferret_corpus_map = array(
$key_all => $empty_template,
);
foreach ($virtual_fields as $field) {
list($key, $raw_corpus) = $field;
if (!strlen($raw_corpus)) {
continue;
}
$term_corpus = $ngram_engine->newTermsCorpus($raw_corpus);
$normal_corpus = $stemmer->stemCorpus($raw_corpus);
$normal_coprus = $ngram_engine->newTermsCorpus($normal_corpus);
if (!isset($ferret_corpus_map[$key])) {
$ferret_corpus_map[$key] = $empty_template;
}
$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();
$ngrams_source = array();
foreach ($ferret_corpus_map as $key => $fields) {
$raw_corpus = $fields['raw'];
$raw_corpus = implode("\n", $raw_corpus);
$ngrams_source[] = $raw_corpus;
$normal_corpus = $fields['normal'];
$normal_corpus = implode(' ', $normal_corpus);
if (strlen($normal_corpus)) {
$ngrams_source[] = $normal_corpus;
$normal_corpus = ' '.$normal_corpus.' ';
}
$term_corpus = $fields['term'];
$term_corpus = implode(' ', $term_corpus);
if (strlen($term_corpus)) {
$ngrams_source[] = $term_corpus;
$term_corpus = ' '.$term_corpus.' ';
}
$ferret_fields[] = $engine->newFieldObject()
->setFieldKey($key)
->setRawCorpus($raw_corpus)
->setTermCorpus($term_corpus)
->setNormalCorpus($normal_corpus);
}
$ngrams_source = implode(' ', $ngrams_source);
$ngrams = $ngram_engine->getNgramsFromString($ngrams_source, 'index');
$ferret_document->openTransaction();
try {
$this->deleteOldDocument($engine, $object, $document);
$ferret_document->save();
$document_id = $ferret_document->getID();
foreach ($ferret_fields as $ferret_field) {
$ferret_field
->setDocumentID($document_id)
->save();
}
$ferret_ngrams = $engine->newNgramsObject();
$conn = $ferret_ngrams->establishConnection('w');
$sql = array();
foreach ($ngrams as $ngram) {
$sql[] = qsprintf(
$conn,
'(%d, %s)',
$document_id,
$ngram);
}
foreach (PhabricatorLiskDAO::chunkSQL($sql) as $chunk) {
queryfx(
$conn,
'INSERT INTO %T (documentID, ngram) VALUES %Q',
$ferret_ngrams->getTableName(),
$chunk);
}
} catch (Exception $ex) {
$ferret_document->killTransaction();
throw $ex;
}
$ferret_document->saveTransaction();
}
private function deleteOldDocument(
PhabricatorFerretEngine $engine,
$object,
PhabricatorSearchAbstractDocument $document) {
$old_document = $engine->newDocumentObject()->loadOneWhere(
'objectPHID = %s',
$document->getPHID());
if (!$old_document) {
return;
}
$conn = $old_document->establishConnection('w');
$old_id = $old_document->getID();
queryfx(
$conn,
'DELETE FROM %T WHERE id = %d',
$engine->newDocumentObject()->getTableName(),
$old_id);
queryfx(
$conn,
'DELETE FROM %T WHERE documentID = %d',
$engine->newFieldObject()->getTableName(),
$old_id);
queryfx(
$conn,
'DELETE FROM %T WHERE documentID = %d',
$engine->newNgramsObject()->getTableName(),
$old_id);
}
}

View file

@ -9,7 +9,7 @@ final class PhabricatorLiskFulltextEngineExtension
return pht('Lisk Builtin Properties'); return pht('Lisk Builtin Properties');
} }
public function shouldIndexFulltextObject($object) { public function shouldEnrichFulltextObject($object) {
if (!($object instanceof PhabricatorLiskDAO)) { if (!($object instanceof PhabricatorLiskDAO)) {
return false; return false;
} }
@ -21,7 +21,7 @@ final class PhabricatorLiskFulltextEngineExtension
return true; return true;
} }
public function indexFulltextObject( public function enrichFulltextObject(
$object, $object,
PhabricatorSearchAbstractDocument $document) { PhabricatorSearchAbstractDocument $document) {

View file

@ -0,0 +1,40 @@
<?php
abstract class PhabricatorFerretDocument
extends PhabricatorSearchDAO {
protected $objectPHID;
protected $isClosed;
protected $authorPHID;
protected $ownerPHID;
protected $epochCreated;
protected $epochModified;
abstract public function getIndexKey();
protected function getConfiguration() {
return array(
self::CONFIG_TIMESTAMPS => 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,
),
),
) + parent::getConfiguration();
}
public function getTableName() {
$application = $this->getApplicationName();
$key = $this->getIndexKey();
return "{$application}_{$key}_fdocument";
}
}

View file

@ -0,0 +1,9 @@
<?php
abstract class PhabricatorFerretEngine extends Phobject {
abstract public function newNgramsObject();
abstract public function newDocumentObject();
abstract public function newFieldObject();
}

View file

@ -0,0 +1,39 @@
<?php
abstract class PhabricatorFerretField
extends PhabricatorSearchDAO {
protected $documentID;
protected $fieldKey;
protected $rawCorpus;
protected $termCorpus;
protected $normalCorpus;
abstract public function getIndexKey();
protected function getConfiguration() {
return array(
self::CONFIG_TIMESTAMPS => 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";
}
}

View file

@ -0,0 +1,7 @@
<?php
interface PhabricatorFerretInterface {
public function newFerretEngine();
}

View file

@ -0,0 +1,35 @@
<?php
abstract class PhabricatorFerretNgrams
extends PhabricatorSearchDAO {
protected $documentID;
protected $ngram;
abstract public function getIndexKey();
protected function getConfiguration() {
return array(
self::CONFIG_TIMESTAMPS => 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";
}
}

View file

@ -26,9 +26,16 @@ abstract class PhabricatorFulltextEngine
$object = $this->getObject(); $object = $this->getObject();
$extensions = PhabricatorFulltextEngineExtension::getAllExtensions(); $extensions = PhabricatorFulltextEngineExtension::getAllExtensions();
$enrich_extensions = array();
$index_extensions = array();
foreach ($extensions as $key => $extension) { foreach ($extensions as $key => $extension) {
if (!$extension->shouldIndexFulltextObject($object)) { if ($extension->shouldEnrichFulltextObject($object)) {
unset($extensions[$key]); $enrich_extensions[] = $extension;
}
if ($extension->shouldIndexFulltextObject($object)) {
$index_extensions[] = $extension;
} }
} }
@ -36,7 +43,11 @@ abstract class PhabricatorFulltextEngine
$this->buildAbstractDocument($document, $object); $this->buildAbstractDocument($document, $object);
foreach ($extensions as $extension) { foreach ($enrich_extensions as $extension) {
$extension->enrichFulltextObject($object, $document);
}
foreach ($index_extensions as $extension) {
$extension->indexFulltextObject($object, $document); $extension->indexFulltextObject($object, $document);
} }

View file

@ -12,11 +12,25 @@ abstract class PhabricatorFulltextEngineExtension extends Phobject {
abstract public function getExtensionName(); abstract public function getExtensionName();
abstract public function shouldIndexFulltextObject($object); public function shouldEnrichFulltextObject($object) {
return false;
}
abstract public function indexFulltextObject( public function enrichFulltextObject(
$object, $object,
PhabricatorSearchAbstractDocument $document); PhabricatorSearchAbstractDocument $document) {
return;
}
public function shouldIndexFulltextObject($object) {
return false;
}
public function indexFulltextObject(
$object,
PhabricatorSearchAbstractDocument $document) {
return;
}
final public static function getAllExtensions() { final public static function getAllExtensions() {
return id(new PhutilClassMapQuery()) return id(new PhutilClassMapQuery())

View file

@ -0,0 +1,95 @@
<?php
final class PhabricatorNgramEngine extends Phobject {
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;
}
}

View file

@ -0,0 +1,26 @@
<?php
final class PhabricatorNgramEngineTestCase
extends PhabricatorTestCase {
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',
'http://example.org/path/to/file.jpg' =>
'http example org path to file jpg',
);
$engine = new PhabricatorNgramEngine();
foreach ($map as $input => $expect) {
$actual = $engine->newTermsCorpus($input);
$this->assertEqual(
$expect,
$actual,
pht('Terms corpus for: %s', $input));
}
}
}

View file

@ -205,7 +205,10 @@ final class PhabricatorSettingsMainController
if ($panel->getPanelGroupKey() != $group_key) { if ($panel->getPanelGroupKey() != $group_key) {
$group_key = $panel->getPanelGroupKey(); $group_key = $panel->getPanelGroupKey();
$group = $panel->getPanelGroup(); $group = $panel->getPanelGroup();
$nav->addLabel($group->getPanelGroupName()); $panel_name = $group->getPanelGroupName();
if ($panel_name) {
$nav->addLabel($panel_name);
}
} }
$nav->addFilter($panel->getPanelKey(), $panel->getPanelName()); $nav->addFilter($panel->getPanelKey(), $panel->getPanelName());

View file

@ -6,7 +6,7 @@ final class PhabricatorSettingsAccountPanelGroup
const PANELGROUPKEY = 'account'; const PANELGROUPKEY = 'account';
public function getPanelGroupName() { public function getPanelGroupName() {
return pht('Account'); return null;
} }
protected function getPanelGroupOrder() { protected function getPanelGroupOrder() {

View file

@ -9,11 +9,11 @@ final class PhabricatorSubscriptionsFulltextEngineExtension
return pht('Subscribers'); return pht('Subscribers');
} }
public function shouldIndexFulltextObject($object) { public function shouldEnrichFulltextObject($object) {
return ($object instanceof PhabricatorSubscribableInterface); return ($object instanceof PhabricatorSubscribableInterface);
} }
public function indexFulltextObject( public function enrichFulltextObject(
$object, $object,
PhabricatorSearchAbstractDocument $document) { PhabricatorSearchAbstractDocument $document) {

View file

@ -9,11 +9,11 @@ final class PhabricatorTransactionsFulltextEngineExtension
return pht('Comments'); return pht('Comments');
} }
public function shouldIndexFulltextObject($object) { public function shouldEnrichFulltextObject($object) {
return ($object instanceof PhabricatorApplicationTransactionInterface); return ($object instanceof PhabricatorApplicationTransactionInterface);
} }
public function indexFulltextObject( public function enrichFulltextObject(
$object, $object,
PhabricatorSearchAbstractDocument $document) { PhabricatorSearchAbstractDocument $document) {

View file

@ -83,9 +83,11 @@ final class PHUIButtonExample extends PhabricatorUIExample {
), ),
array( array(
'icon' => 'fa-upload', 'icon' => 'fa-upload',
'disabled' => true,
), ),
array( array(
'icon' => 'fa-street-view', 'icon' => 'fa-street-view',
'selected' => true,
), ),
array( array(
'text' => pht('Copy "Quack" to Clipboard'), 'text' => pht('Copy "Quack" to Clipboard'),
@ -99,6 +101,8 @@ final class PHUIButtonExample extends PhabricatorUIExample {
->setColor(PHUIButtonView::GREY) ->setColor(PHUIButtonView::GREY)
->setIcon(idx($spec, 'icon')) ->setIcon(idx($spec, 'icon'))
->setText(idx($spec, 'text')) ->setText(idx($spec, 'text'))
->setSelected(idx($spec, 'selected'))
->setDisabled(idx($spec, 'disabled'))
->addClass(PHUI::MARGIN_SMALL_RIGHT) ->addClass(PHUI::MARGIN_SMALL_RIGHT)
->setDropdown(idx($spec, 'dropdown')); ->setDropdown(idx($spec, 'dropdown'));

View file

@ -9,11 +9,11 @@ final class PhabricatorCustomFieldFulltextEngineExtension
return pht('Custom Fields'); return pht('Custom Fields');
} }
public function shouldIndexFulltextObject($object) { public function shouldEnrichFulltextObject($object) {
return ($object instanceof PhabricatorCustomFieldInterface); return ($object instanceof PhabricatorCustomFieldInterface);
} }
public function indexFulltextObject( public function enrichFulltextObject(
$object, $object,
PhabricatorSearchAbstractDocument $document) { PhabricatorSearchAbstractDocument $document) {

View file

@ -27,6 +27,9 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery
private $spacePHIDs; private $spacePHIDs;
private $spaceIsArchived; private $spaceIsArchived;
private $ngrams = array(); private $ngrams = array();
private $ferretEngine;
private $ferretTokens;
private $ferretTables;
protected function getPageCursors(array $page) { protected function getPageCursors(array $page) {
return array( return array(
@ -270,6 +273,7 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery
$joins[] = $this->buildEdgeLogicJoinClause($conn); $joins[] = $this->buildEdgeLogicJoinClause($conn);
$joins[] = $this->buildApplicationSearchJoinClause($conn); $joins[] = $this->buildApplicationSearchJoinClause($conn);
$joins[] = $this->buildNgramsJoinClause($conn); $joins[] = $this->buildNgramsJoinClause($conn);
$joins[] = $this->buildFerretJoinClause($conn);
return $joins; return $joins;
} }
@ -292,6 +296,7 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery
$where[] = $this->buildEdgeLogicWhereClause($conn); $where[] = $this->buildEdgeLogicWhereClause($conn);
$where[] = $this->buildSpacesWhereClause($conn); $where[] = $this->buildSpacesWhereClause($conn);
$where[] = $this->buildNgramsWhereClause($conn); $where[] = $this->buildNgramsWhereClause($conn);
$where[] = $this->buildFerretWhereClause($conn);
return $where; return $where;
} }
@ -346,6 +351,10 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery
return true; return true;
} }
if ($this->shouldGroupFerretResultRows()) {
return true;
}
return false; return false;
} }
@ -1373,6 +1382,332 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery
} }
/* -( Ferret )------------------------------------------------------------- */
public function withFerretConstraint(
PhabricatorFerretEngine $engine,
array $fulltext_tokens) {
if ($this->ferretEngine) {
throw new Exception(
pht(
'Query may not have multiple fulltext constraints.'));
}
if (!$fulltext_tokens) {
return $this;
}
$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';
$table_map = array();
$idx = 1;
foreach ($this->ferretTokens as $fulltext_token) {
$raw_token = $fulltext_token->getToken();
$function = $raw_token->getFunction();
if ($function === null) {
$function = $current_function;
}
if (!isset($function_map[$function])) {
throw new PhutilSearchQueryCompilerSyntaxException(
pht(
'Unknown search function "%s".',
$function));
}
if (!isset($table_map[$function])) {
$alias = 'ftfield'.$idx++;
$table_map[$function] = array(
'alias' => $alias,
'key' => $function_map[$function],
);
}
$current_function = $function;
}
$this->ferretTables = $table_map;
return $this;
}
protected function buildFerretJoinClause(AphrontDatabaseConnection $conn) {
if (!$this->ferretEngine) {
return array();
}
$op_sub = PhutilSearchQueryCompiler::OPERATOR_SUBSTRING;
$op_not = PhutilSearchQueryCompiler::OPERATOR_NOT;
$engine = $this->ferretEngine;
$ngram_engine = new PhabricatorNgramEngine();
$stemmer = new PhutilSearchStemmer();
$ngram_table = $engine->newNgramsObject();
$ngram_table_name = $ngram_table->getTableName();
$flat = array();
foreach ($this->ferretTokens as $fulltext_token) {
$raw_token = $fulltext_token->getToken();
// If this is a negated term like "-pomegranate", don't join the ngram
// table since we aren't looking for documents with this term. (We could
// LEFT JOIN the table and require a NULL row, but this is probably more
// trouble than it's worth.)
if ($raw_token->getOperator() == $op_not) {
continue;
}
$value = $raw_token->getValue();
$length = count(phutil_utf8v($value));
if ($raw_token->getOperator() == $op_sub) {
$is_substring = true;
} else {
$is_substring = false;
}
// If the user specified a substring query for a substring which is
// shorter than the ngram length, we can't use the ngram index, so
// don't do a join. We'll fall back to just doing LIKE on the full
// corpus.
if ($is_substring) {
if ($length < 3) {
continue;
}
}
if ($raw_token->isQuoted()) {
$is_stemmed = false;
} else {
$is_stemmed = true;
}
if ($is_substring) {
$ngrams = $ngram_engine->getNgramsFromString($value, 'query');
} else {
$ngrams = $ngram_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_value,
'index');
$ngrams = array_intersect($ngrams, $stem_ngrams);
}
}
foreach ($ngrams as $ngram) {
$flat[] = array(
'table' => $ngram_table_name,
'ngram' => $ngram,
);
}
}
// MySQL only allows us to join a maximum of 61 tables per query. Each
// ngram is going to cost us a join toward that limit, so if the user
// specified a very long query string, just pick 16 of the ngrams
// at random.
if (count($flat) > 16) {
shuffle($flat);
$flat = array_slice($flat, 0, 16);
}
$alias = $this->getPrimaryTableAlias();
if ($alias) {
$phid_column = qsprintf($conn, '%T.%T', $alias, 'phid');
} else {
$phid_column = qsprintf($conn, '%T', 'phid');
}
$document_table = $engine->newDocumentObject();
$field_table = $engine->newFieldObject();
$joins = array();
$joins[] = qsprintf(
$conn,
'JOIN %T ftdoc ON ftdoc.objectPHID = %Q',
$document_table->getTableName(),
$phid_column);
$idx = 1;
foreach ($flat as $spec) {
$table = $spec['table'];
$ngram = $spec['ngram'];
$alias = 'ft'.$idx++;
$joins[] = qsprintf(
$conn,
'JOIN %T %T ON %T.documentID = ftdoc.id AND %T.ngram = %s',
$table,
$alias,
$alias,
$alias,
$ngram);
}
foreach ($this->ferretTables as $table) {
$alias = $table['alias'];
$joins[] = qsprintf(
$conn,
'JOIN %T %T ON ftdoc.id = %T.documentID
AND %T.fieldKey = %s',
$field_table->getTableName(),
$alias,
$alias,
$alias,
$table['key']);
}
return $joins;
}
protected function buildFerretWhereClause(AphrontDatabaseConnection $conn) {
if (!$this->ferretEngine) {
return array();
}
$ngram_engine = new PhabricatorNgramEngine();
$stemmer = new PhutilSearchStemmer();
$table_map = $this->ferretTables;
$op_sub = PhutilSearchQueryCompiler::OPERATOR_SUBSTRING;
$op_not = PhutilSearchQueryCompiler::OPERATOR_NOT;
$where = array();
$current_function = 'all';
foreach ($this->ferretTokens as $fulltext_token) {
$raw_token = $fulltext_token->getToken();
$value = $raw_token->getValue();
$function = $raw_token->getFunction();
if ($function === null) {
$function = $current_function;
}
$current_function = $function;
$table_alias = $table_map[$function]['alias'];
$is_not = ($raw_token->getOperator() == $op_not);
if ($raw_token->getOperator() == $op_sub) {
$is_substring = true;
} else {
$is_substring = false;
}
// If we're doing substring search, we just match against the raw corpus
// and we're done.
if ($is_substring) {
if ($is_not) {
$where[] = qsprintf(
$conn,
'(%T.rawCorpus NOT LIKE %~)',
$table_alias,
$value);
} else {
$where[] = qsprintf(
$conn,
'(%T.rawCorpus LIKE %~)',
$table_alias,
$value);
}
continue;
}
// Otherwise, we need to match against the term corpus and the normal
// corpus, so that searching for "raw" does not find "strawberry".
if ($raw_token->isQuoted()) {
$is_quoted = true;
$is_stemmed = false;
} else {
$is_quoted = false;
$is_stemmed = true;
}
// Never stem negated queries, since this can exclude results users
// did not mean to exclude and generally confuse things.
if ($is_not) {
$is_stemmed = false;
}
$term_constraints = array();
$term_value = ' '.$ngram_engine->newTermsCorpus($value).' ';
if ($is_not) {
$term_constraints[] = qsprintf(
$conn,
'(%T.termCorpus NOT LIKE %~)',
$table_alias,
$term_value);
} else {
$term_constraints[] = qsprintf(
$conn,
'(%T.termCorpus LIKE %~)',
$table_alias,
$term_value);
}
if ($is_stemmed) {
$stem_value = $stemmer->stemToken($value);
$stem_value = $ngram_engine->newTermsCorpus($stem_value);
$stem_value = ' '.$stem_value.' ';
$term_constraints[] = qsprintf(
$conn,
'(%T.normalCorpus LIKE %~)',
$table_alias,
$stem_value);
}
if ($is_not) {
$where[] = qsprintf(
$conn,
'(%Q)',
implode(' AND ', $term_constraints));
} else if ($is_quoted) {
$where[] = qsprintf(
$conn,
'(%T.rawCorpus LIKE %~ AND (%Q))',
$table_alias,
$value,
implode(' OR ', $term_constraints));
} else {
$where[] = qsprintf(
$conn,
'(%Q)',
implode(' OR ', $term_constraints));
}
}
return $where;
}
protected function shouldGroupFerretResultRows() {
return (bool)$this->ferretTokens;
}
/* -( Ngrams )------------------------------------------------------------- */ /* -( Ngrams )------------------------------------------------------------- */

View file

@ -25,6 +25,7 @@ final class PHUIButtonView extends AphrontTagView {
private $href = null; private $href = null;
private $title = null; private $title = null;
private $disabled; private $disabled;
private $selected;
private $name; private $name;
private $tooltip; private $tooltip;
private $noCSS; private $noCSS;
@ -74,6 +75,11 @@ final class PHUIButtonView extends AphrontTagView {
return $this; return $this;
} }
public function setSelected($selected) {
$this->selected = $selected;
return $this;
}
public function setTag($tag) { public function setTag($tag) {
$this->tag = $tag; $this->tag = $tag;
return $this; return $this;
@ -189,6 +195,10 @@ final class PHUIButtonView extends AphrontTagView {
$classes[] = 'disabled'; $classes[] = 'disabled';
} }
if ($this->selected) {
$classes[] = 'selected';
}
switch ($this->getButtonType()) { switch ($this->getButtonType()) {
case self::BUTTONTYPE_DEFAULT: case self::BUTTONTYPE_DEFAULT:
$classes[] = 'phui-button-default'; $classes[] = 'phui-button-default';

View file

@ -150,13 +150,25 @@ final class PHUIFeedStoryView extends AphrontView {
if ($this->getShowTimestamp()) { if ($this->getShowTimestamp()) {
if ($this->epoch) { if ($this->epoch) {
if ($user) { if ($user) {
$foot = phabricator_datetime($this->epoch, $user); $marker = id(new PHUIIconView())
->setIcon('fa-circle')
->addClass('phabricator-notification-status');
$date = phabricator_datetime($this->epoch, $user);
$foot = phutil_tag( $foot = phutil_tag(
'span', 'span',
array( array(
'class' => 'phabricator-notification-date', 'class' => 'phabricator-notification-date',
), ),
$foot); $date);
$foot = phutil_tag(
'div',
array(
'class' => 'phabricator-notification-foot',
),
array(
$marker,
$date,
));
} else { } else {
$foot = null; $foot = null;
} }

View file

@ -11,7 +11,7 @@
.jx-notification { .jx-notification {
width: 240px; width: 240px;
padding: 8px 16px; padding: 8px 12px;
font-size: 11px; font-size: 11px;
overflow: hidden; overflow: hidden;

View file

@ -4,6 +4,7 @@
.aphront-table-wrap { .aphront-table-wrap {
overflow-x: auto; overflow-x: auto;
-webkit-overflow-scrolling: touch;
} }
.aphront-table-view { .aphront-table-view {
@ -128,14 +129,8 @@ th.aphront-table-view-sortable-selected {
padding: 8px 10px; padding: 8px 10px;
} }
.device-tablet .aphront-table-view td,
.device-phone .aphront-table-view td {
padding: 6px;
}
.device-tablet .aphront-table-view th, .device-tablet .aphront-table-view th,
.device-phone .aphront-table-view th { .device-phone .aphront-table-view th {
padding: 6px;
overflow: hidden; overflow: hidden;
} }

View file

@ -4,7 +4,8 @@
.phabricator-notification-menu { .phabricator-notification-menu {
background: {$page.content}; background: {$page.content};
font-size: {$smallestfontsize}; font-size: {$smallerfontsize};
line-height: 18px;
word-wrap: break-word; word-wrap: break-word;
overflow-y: auto; overflow-y: auto;
box-shadow: {$dropshadow}; box-shadow: {$dropshadow};
@ -12,9 +13,8 @@
border-radius: 3px; border-radius: 3px;
} }
.phabricator-notification .phabricator-notification-date { .phabricator-notification {
margin-left: 8px; padding: 8px 12px;
color: {$lightgreytext};
} }
.phabricator-notification-menu-loading { .phabricator-notification-menu-loading {
@ -44,11 +44,7 @@
} }
.phabricator-notification-list .phabricator-notification { .phabricator-notification-list .phabricator-notification {
padding: 10px 4px; padding: 8px;
}
.phabricator-notification {
padding: 6px 8px;
} }
.phabricator-notification-menu .phabricator-notification { .phabricator-notification-menu .phabricator-notification {
@ -56,7 +52,7 @@
} }
.device-desktop .phabricator-notification-menu .phabricator-notification:hover { .device-desktop .phabricator-notification-menu .phabricator-notification:hover {
background: {$hoverblue}; background: {$lightgreybackground};
} }
.device-desktop .phabricator-notification-menu .device-desktop .phabricator-notification-menu
@ -81,9 +77,34 @@
color: {$lightgreytext}; color: {$lightgreytext};
} }
.phabricator-notification-foot {
color: {$lightgreytext};
font-size: {$smallestfontsize};
line-height: 18px;
position: relative;
}
.phabricator-notification-unread .phabricator-notification-foot {
padding-left: 10px;
}
.phabricator-notification-foot .phabricator-notification-status {
display: none;
}
.phabricator-notification-unread .phabricator-notification-foot
.phabricator-notification-status {
font-size: 7px;
color: {$lightgreytext};
position: absolute;
display: inline-block;
top: 6px;
left: 0;
}
.phabricator-notification-header { .phabricator-notification-header {
font-weight: bold; font-weight: bold;
padding: 10px 8px; padding: 10px 12px;
font-size: {$smallerfontsize}; font-size: {$smallerfontsize};
border-bottom: 1px solid {$thinblueborder}; border-bottom: 1px solid {$thinblueborder};
} }

View file

@ -5,6 +5,12 @@
.diffusion-source { .diffusion-source {
width: 100%; width: 100%;
background: {$page.content}; background: {$page.content};
overflow: hidden;
}
.device-phone .diffusion-source-wrap {
overflow: scroll;
-webkit-overflow-scrolling: touch;
} }
.diffusion-source tr.phabricator-source-highlight th, .diffusion-source tr.phabricator-source-highlight th,
@ -27,6 +33,11 @@
word-break: break-all; word-break: break-all;
} }
.device .diffusion-source td {
word-break: normal;
white-space: nowrap;
}
.diffusion-browse-type-form { .diffusion-browse-type-form {
float: right; float: right;
} }

View file

@ -207,16 +207,6 @@
border-color: {$thinblueborder}; border-color: {$thinblueborder};
} }
.device-phone.diffusion-history-view .phui-two-column-view
.phui-two-column-footer .phui-header-view {
text-align: center;
}
.device-phone.diffusion-history-view .phui-two-column-content {
padding: 0;
margin: 0 -4px;
}
.device-phone.diffusion-history-view .phui-oi-attribute-spacer { .device-phone.diffusion-history-view .phui-oi-attribute-spacer {
display: none; display: none;
} }
@ -240,12 +230,10 @@
padding-bottom: 10px; padding-bottom: 10px;
} }
.device-phone.diffusion-history-view .diffusion-history-list .button.has-icon .device-phone .phui-two-column-view .phui-two-column-content
.phui-button-text { .phui-object-box.diffusion-mobile-view {
margin: 0; margin: 0 -12px 20px;
} border-left: none;
border-right: none;
.device-phone.diffusion-history-view .diffusion-history-list .button.has-icon border-color: {$thinblueborder};
.phui-icon-view {
display: none;
} }

View file

@ -40,7 +40,7 @@
padding: 12px 0; padding: 12px 0;
} }
.device-phone .application-search-results .device-phone.application-search-view .application-search-results
.phui-profile-header.phui-header-shell { .phui-profile-header.phui-header-shell {
padding: 12px 0 12px 4px; padding: 12px 0 12px 4px;
} }

View file

@ -105,6 +105,19 @@ button[disabled] {
opacity: 0.5; opacity: 0.5;
} }
button.button-grey.selected,
a.button.button-grey.selected,
button.button-grey.selected:hover,
a.button.button-grey.selected:hover {
border-color: {$sh-orangetext};
color: {$sh-orangetext};
}
button.button-grey.selected .phui-icon-view,
a.button-grey.selected .phui-icon-view {
color: {$sh-orangetext};
}
a.phuix-dropdown-open { a.phuix-dropdown-open {
color: {$greytext}; color: {$greytext};
} }

View file

@ -64,7 +64,7 @@
.phui-basic-nav .phabricator-side-menu .phui-list-item-href { .phui-basic-nav .phabricator-side-menu .phui-list-item-href {
display: block; display: block;
padding: 6px 8px 6px 20px; padding: 6px 8px 6px 12px;
color: {$darkbluetext}; color: {$darkbluetext};
border-top-right-radius: 3px; border-top-right-radius: 3px;
border-bottom-right-radius: 3px; border-bottom-right-radius: 3px;
@ -72,13 +72,8 @@
text-overflow: ellipsis text-overflow: ellipsis
} }
.phui-basic-nav .phabricator-side-menu .phui-list-item-has-icon
.phui-list-item-href {
padding-left: 12px;
}
.phui-basic-nav .phabricator-side-menu .phui-list-item-icon { .phui-basic-nav .phabricator-side-menu .phui-list-item-icon {
margin-left: -4px; margin-left: -8px;
text-align: center; text-align: center;
width: 30px; width: 30px;
} }
@ -100,7 +95,6 @@
.phui-basic-nav .phabricator-side-menu .phui-list-item-selected { .phui-basic-nav .phabricator-side-menu .phui-list-item-selected {
background-color: rgba({$alphablack},.05); background-color: rgba({$alphablack},.05);
border-left: 4px solid {$sky};
border-top-right-radius: 3px; border-top-right-radius: 3px;
border-bottom-right-radius: 3px; border-bottom-right-radius: 3px;
font-weight: bold; font-weight: bold;
@ -109,12 +103,7 @@
.device-desktop .phui-basic-nav .phabricator-side-menu .device-desktop .phui-basic-nav .phabricator-side-menu
.phui-list-item-selected .phui-list-item-selected
a.phui-list-item-href:hover { a.phui-list-item-href:hover {
background-color: rgba({$alphablack},.05); background-color: rgba({$alphablack},.05);
}
.phui-basic-nav .phabricator-side-menu .phui-list-item-selected
.phui-list-item-href {
margin-left: -4px;
} }
.phui-basic-nav .phabricator-side-menu .phui-list-item-type-label { .phui-basic-nav .phabricator-side-menu .phui-list-item-type-label {
@ -124,6 +113,7 @@
font-size: 12px; font-size: 12px;
font-weight: bold; font-weight: bold;
border-style: solid; border-style: solid;
letter-spacing: 0.02em;
} }
.device-desktop .phui-basic-nav .phabricator-side-menu .device-desktop .phui-basic-nav .phabricator-side-menu

View file

@ -281,9 +281,7 @@
.phui-two-column-fixed.phui-two-column-view .phui-two-column-fixed.phui-two-column-view
.phui-basic-nav .phabricator-side-menu .phui-list-item-selected { .phui-basic-nav .phabricator-side-menu .phui-list-item-selected {
border-radius: 3px; border-radius: 3px;
background-color: #f5f9ff; background-color: {$sky};
border: 1px solid {$sky};
padding-left: 3px;
} }
.phui-two-column-fixed.phui-two-column-view .phui-basic-nav .phui-two-column-fixed.phui-two-column-view .phui-basic-nav
@ -291,6 +289,16 @@
border-radius: 3px; border-radius: 3px;
} }
.phui-two-column-fixed.phui-two-column-view .phui-basic-nav
.phabricator-side-menu .phui-list-item-selected a {
color: #fff;
}
.phui-two-column-fixed.phui-two-column-view .phui-basic-nav
.phabricator-side-menu .phui-list-item-selected a .phui-icon-view {
color: #fff;
}
.phui-two-column-fixed.phui-two-column-view .phui-header-action-links .phui-two-column-fixed.phui-two-column-view .phui-header-action-links
.phui-mobile-menu { .phui-mobile-menu {
display: block; display: block;

View file

@ -16,6 +16,7 @@ JX.install('PHUIXButtonView', {
_iconView: null, _iconView: null,
_color: null, _color: null,
_selected: null,
_buttonType: null, _buttonType: null,
setIcon: function(icon) { setIcon: function(icon) {
@ -43,6 +44,13 @@ JX.install('PHUIXButtonView', {
return this; return this;
}, },
setSelected: function(selected) {
var node = this.getNode();
this._selected = selected;
JX.DOM.alterClass(node, 'selected', this._selected);
return this;
},
setButtonType: function(button_type) { setButtonType: function(button_type) {
var self = JX.PHUIXButtonView; var self = JX.PHUIXButtonView;