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:
commit
007fb4c30e
57 changed files with 1196 additions and 113 deletions
|
@ -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',
|
||||||
),
|
),
|
||||||
|
|
9
resources/sql/autopatches/20170828.ferret.01.taskdoc.sql
Normal file
9
resources/sql/autopatches/20170828.ferret.01.taskdoc.sql
Normal 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};
|
|
@ -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};
|
|
@ -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};
|
4
resources/sql/autopatches/20170830.ferret.01.unique.sql
Normal file
4
resources/sql/autopatches/20170830.ferret.01.unique.sql
Normal 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);
|
2
resources/sql/autopatches/20170830.ferret.02.term.sql
Normal file
2
resources/sql/autopatches/20170830.ferret.02.term.sql
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
ALTER TABLE {$NAMESPACE}_maniphest.maniphest_task_ffield
|
||||||
|
ADD termCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT};
|
|
@ -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',
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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');
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -134,7 +134,7 @@ final class DiffusionBrowseTableView extends DiffusionView {
|
||||||
array(
|
array(
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
true,
|
false,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
));
|
));
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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');
|
||||||
}
|
}
|
||||||
|
|
|
@ -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']);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class ManiphestTaskFerretDocument
|
||||||
|
extends PhabricatorFerretDocument {
|
||||||
|
|
||||||
|
public function getApplicationName() {
|
||||||
|
return 'maniphest';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIndexKey() {
|
||||||
|
return 'task';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class ManiphestTaskFerretField
|
||||||
|
extends PhabricatorFerretField {
|
||||||
|
|
||||||
|
public function getApplicationName() {
|
||||||
|
return 'maniphest';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIndexKey() {
|
||||||
|
return 'task';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class ManiphestTaskFerretNgrams
|
||||||
|
extends PhabricatorFerretNgrams {
|
||||||
|
|
||||||
|
public function getApplicationName() {
|
||||||
|
return 'maniphest';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIndexKey() {
|
||||||
|
return 'task';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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(
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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';
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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) {
|
||||||
|
|
||||||
|
|
40
src/applications/search/ferret/PhabricatorFerretDocument.php
Normal file
40
src/applications/search/ferret/PhabricatorFerretDocument.php
Normal 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";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class PhabricatorFerretEngine extends Phobject {
|
||||||
|
|
||||||
|
abstract public function newNgramsObject();
|
||||||
|
abstract public function newDocumentObject();
|
||||||
|
abstract public function newFieldObject();
|
||||||
|
|
||||||
|
}
|
39
src/applications/search/ferret/PhabricatorFerretField.php
Normal file
39
src/applications/search/ferret/PhabricatorFerretField.php
Normal 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";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
interface PhabricatorFerretInterface {
|
||||||
|
|
||||||
|
public function newFerretEngine();
|
||||||
|
|
||||||
|
}
|
35
src/applications/search/ferret/PhabricatorFerretNgrams.php
Normal file
35
src/applications/search/ferret/PhabricatorFerretNgrams.php
Normal 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";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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())
|
||||||
|
|
95
src/applications/search/ngrams/PhabricatorNgramEngine.php
Normal file
95
src/applications/search/ngrams/PhabricatorNgramEngine.php
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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());
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
||||||
|
|
|
@ -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'));
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
||||||
|
|
|
@ -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 )------------------------------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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';
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue