1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-01 03:02:43 +01:00

(stable) Promote 2016 Week 32

This commit is contained in:
epriestley 2016-08-06 14:39:42 -07:00
commit 435f756414
80 changed files with 1692 additions and 563 deletions

View file

@ -1,4 +1,5 @@
{ {
"phabricator.uri": "https://secure.phabricator.com/", "phabricator.uri": "https://secure.phabricator.com/",
"load": ["src/"] "load": ["src/"],
"history.immutable": false
} }

View file

@ -7,8 +7,8 @@
*/ */
return array( return array(
'names' => array( 'names' => array(
'core.pkg.css' => '8b87d014', 'core.pkg.css' => '90c46327',
'core.pkg.js' => '13c7e56a', 'core.pkg.js' => 'b562c3db',
'darkconsole.pkg.js' => 'e7393ebb', 'darkconsole.pkg.js' => 'e7393ebb',
'differential.pkg.css' => '3fb7f532', 'differential.pkg.css' => '3fb7f532',
'differential.pkg.js' => '634399e9', 'differential.pkg.js' => '634399e9',
@ -24,7 +24,7 @@ return array(
'rsrc/css/aphront/multi-column.css' => 'fd18389d', 'rsrc/css/aphront/multi-column.css' => 'fd18389d',
'rsrc/css/aphront/notification.css' => '3f6c89c9', 'rsrc/css/aphront/notification.css' => '3f6c89c9',
'rsrc/css/aphront/panel-view.css' => '8427b78d', 'rsrc/css/aphront/panel-view.css' => '8427b78d',
'rsrc/css/aphront/phabricator-nav-view.css' => 'ac79a758', 'rsrc/css/aphront/phabricator-nav-view.css' => '09f3d0db',
'rsrc/css/aphront/table-view.css' => '832656fd', 'rsrc/css/aphront/table-view.css' => '832656fd',
'rsrc/css/aphront/tokenizer.css' => '056da01b', 'rsrc/css/aphront/tokenizer.css' => '056da01b',
'rsrc/css/aphront/tooltip.css' => '1a07aea8', 'rsrc/css/aphront/tooltip.css' => '1a07aea8',
@ -94,17 +94,18 @@ return array(
'rsrc/css/application/policy/policy.css' => '957ea14c', 'rsrc/css/application/policy/policy.css' => '957ea14c',
'rsrc/css/application/ponder/ponder-view.css' => 'fbd45f96', 'rsrc/css/application/ponder/ponder-view.css' => 'fbd45f96',
'rsrc/css/application/project/project-card-view.css' => '9418c97d', 'rsrc/css/application/project/project-card-view.css' => '9418c97d',
'rsrc/css/application/project/project-view.css' => 'cbaa10a1', 'rsrc/css/application/project/project-view.css' => '9ce99f21',
'rsrc/css/application/releeph/releeph-core.css' => '9b3c5733', 'rsrc/css/application/releeph/releeph-core.css' => '9b3c5733',
'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' => 'b3e0e5ef',
'rsrc/css/application/search/search-results.css' => '7dea472c', 'rsrc/css/application/search/search-results.css' => '7dea472c',
'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',
'rsrc/css/application/uiexample/example.css' => '528b19de', 'rsrc/css/application/uiexample/example.css' => '528b19de',
'rsrc/css/core/core.css' => 'd0801452', 'rsrc/css/core/core.css' => 'd0801452',
'rsrc/css/core/remarkup.css' => '523d34bb', 'rsrc/css/core/remarkup.css' => '5ed06ed8',
'rsrc/css/core/syntax.css' => '769d3498', 'rsrc/css/core/syntax.css' => '769d3498',
'rsrc/css/core/z-index.css' => '5b6fcf3f', 'rsrc/css/core/z-index.css' => '5b6fcf3f',
'rsrc/css/diviner/diviner-shared.css' => 'aa3656aa', 'rsrc/css/diviner/diviner-shared.css' => 'aa3656aa',
@ -113,22 +114,22 @@ return array(
'rsrc/css/font/font-lato.css' => 'c7ccd872', 'rsrc/css/font/font-lato.css' => 'c7ccd872',
'rsrc/css/font/phui-font-icon-base.css' => '6449bce8', 'rsrc/css/font/phui-font-icon-base.css' => '6449bce8',
'rsrc/css/layout/phabricator-filetree-view.css' => 'fccf9f82', 'rsrc/css/layout/phabricator-filetree-view.css' => 'fccf9f82',
'rsrc/css/layout/phabricator-side-menu-view.css' => 'dd849797',
'rsrc/css/layout/phabricator-source-code-view.css' => 'cbeef983', 'rsrc/css/layout/phabricator-source-code-view.css' => 'cbeef983',
'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' => 'fcc9fb41', 'rsrc/css/phui/calendar/phui-calendar-list.css' => 'fcc9fb41',
'rsrc/css/phui/calendar/phui-calendar-month.css' => '8e10e92c', 'rsrc/css/phui/calendar/phui-calendar-month.css' => '8e10e92c',
'rsrc/css/phui/calendar/phui-calendar.css' => 'daadaf39', 'rsrc/css/phui/calendar/phui-calendar.css' => '477acfaa',
'rsrc/css/phui/phui-action-list.css' => 'c5eba19d', 'rsrc/css/phui/phui-action-list.css' => 'c5eba19d',
'rsrc/css/phui/phui-action-panel.css' => '91c7b835', 'rsrc/css/phui/phui-action-panel.css' => '91c7b835',
'rsrc/css/phui/phui-badge.css' => '3baef8db', 'rsrc/css/phui/phui-badge.css' => '3baef8db',
'rsrc/css/phui/phui-basic-nav-view.css' => '7093573b',
'rsrc/css/phui/phui-big-info-view.css' => 'bd903741', 'rsrc/css/phui/phui-big-info-view.css' => 'bd903741',
'rsrc/css/phui/phui-box.css' => '5c8387cf', 'rsrc/css/phui/phui-box.css' => '5c8387cf',
'rsrc/css/phui/phui-button.css' => '4a5fbe3d', 'rsrc/css/phui/phui-button.css' => '4a5fbe3d',
'rsrc/css/phui/phui-chart.css' => '6bf6f78e', 'rsrc/css/phui/phui-chart.css' => '6bf6f78e',
'rsrc/css/phui/phui-crumbs-view.css' => 'b4fa5755', 'rsrc/css/phui/phui-crumbs-view.css' => '9dac418c',
'rsrc/css/phui/phui-curtain-view.css' => '7148ae25', 'rsrc/css/phui/phui-curtain-view.css' => '7148ae25',
'rsrc/css/phui/phui-document-pro.css' => 'a3730b94', 'rsrc/css/phui/phui-document-pro.css' => 'dc3d46ed',
'rsrc/css/phui/phui-document-summary.css' => '9ca48bdf', 'rsrc/css/phui/phui-document-summary.css' => '9ca48bdf',
'rsrc/css/phui/phui-document.css' => '715aedfb', 'rsrc/css/phui/phui-document.css' => '715aedfb',
'rsrc/css/phui/phui-feed-story.css' => 'aa49845d', 'rsrc/css/phui/phui-feed-story.css' => 'aa49845d',
@ -136,7 +137,7 @@ return array(
'rsrc/css/phui/phui-form-view.css' => 'fab0a10f', 'rsrc/css/phui/phui-form-view.css' => 'fab0a10f',
'rsrc/css/phui/phui-form.css' => 'aac1d51d', 'rsrc/css/phui/phui-form.css' => 'aac1d51d',
'rsrc/css/phui/phui-head-thing.css' => 'fd311e5f', 'rsrc/css/phui/phui-head-thing.css' => 'fd311e5f',
'rsrc/css/phui/phui-header-view.css' => '4c7dd8f5', 'rsrc/css/phui/phui-header-view.css' => '06385974',
'rsrc/css/phui/phui-hovercard.css' => 'de1a2119', 'rsrc/css/phui/phui-hovercard.css' => 'de1a2119',
'rsrc/css/phui/phui-icon-set-selector.css' => '1ab67aad', 'rsrc/css/phui/phui-icon-set-selector.css' => '1ab67aad',
'rsrc/css/phui/phui-icon.css' => 'd0534b71', 'rsrc/css/phui/phui-icon.css' => 'd0534b71',
@ -148,7 +149,7 @@ return array(
'rsrc/css/phui/phui-object-item-list-view.css' => '8d99e42b', 'rsrc/css/phui/phui-object-item-list-view.css' => '8d99e42b',
'rsrc/css/phui/phui-pager.css' => 'bea33d23', 'rsrc/css/phui/phui-pager.css' => 'bea33d23',
'rsrc/css/phui/phui-pinboard-view.css' => '2495140e', 'rsrc/css/phui/phui-pinboard-view.css' => '2495140e',
'rsrc/css/phui/phui-profile-menu.css' => 'c8557f33', 'rsrc/css/phui/phui-profile-menu.css' => '8a3fc181',
'rsrc/css/phui/phui-property-list-view.css' => '6d8e58ac', 'rsrc/css/phui/phui-property-list-view.css' => '6d8e58ac',
'rsrc/css/phui/phui-remarkup-preview.css' => '1a8f2591', 'rsrc/css/phui/phui-remarkup-preview.css' => '1a8f2591',
'rsrc/css/phui/phui-segment-bar-view.css' => '46342871', 'rsrc/css/phui/phui-segment-bar-view.css' => '46342871',
@ -498,7 +499,7 @@ return array(
'rsrc/js/core/behavior-more.js' => 'a80d0378', 'rsrc/js/core/behavior-more.js' => 'a80d0378',
'rsrc/js/core/behavior-object-selector.js' => 'e0ec7f2f', 'rsrc/js/core/behavior-object-selector.js' => 'e0ec7f2f',
'rsrc/js/core/behavior-oncopy.js' => '2926fff2', 'rsrc/js/core/behavior-oncopy.js' => '2926fff2',
'rsrc/js/core/behavior-phabricator-nav.js' => '56a1ca03', 'rsrc/js/core/behavior-phabricator-nav.js' => '08675c6d',
'rsrc/js/core/behavior-phabricator-remarkup-assist.js' => '116cf19b', 'rsrc/js/core/behavior-phabricator-remarkup-assist.js' => '116cf19b',
'rsrc/js/core/behavior-read-only-warning.js' => 'ba158207', 'rsrc/js/core/behavior-read-only-warning.js' => 'ba158207',
'rsrc/js/core/behavior-refresh-csrf.js' => 'ab2f381b', 'rsrc/js/core/behavior-refresh-csrf.js' => 'ab2f381b',
@ -541,6 +542,7 @@ return array(
'aphront-tokenizer-control-css' => '056da01b', 'aphront-tokenizer-control-css' => '056da01b',
'aphront-tooltip-css' => '1a07aea8', 'aphront-tooltip-css' => '1a07aea8',
'aphront-typeahead-control-css' => 'd4f16145', 'aphront-typeahead-control-css' => 'd4f16145',
'application-search-view-css' => 'b3e0e5ef',
'auth-css' => '0877ed6e', 'auth-css' => '0877ed6e',
'bulk-job-css' => 'df9c1d4a', 'bulk-job-css' => 'df9c1d4a',
'changeset-view-manager' => 'a2828756', 'changeset-view-manager' => 'a2828756',
@ -658,7 +660,7 @@ return array(
'javelin-behavior-phabricator-keyboard-pager' => 'a8da01f0', 'javelin-behavior-phabricator-keyboard-pager' => 'a8da01f0',
'javelin-behavior-phabricator-keyboard-shortcuts' => '01fca1f0', 'javelin-behavior-phabricator-keyboard-shortcuts' => '01fca1f0',
'javelin-behavior-phabricator-line-linker' => '1499a8cb', 'javelin-behavior-phabricator-line-linker' => '1499a8cb',
'javelin-behavior-phabricator-nav' => '56a1ca03', 'javelin-behavior-phabricator-nav' => '08675c6d',
'javelin-behavior-phabricator-notification-example' => '8ce821c5', 'javelin-behavior-phabricator-notification-example' => '8ce821c5',
'javelin-behavior-phabricator-object-selector' => 'e0ec7f2f', 'javelin-behavior-phabricator-object-selector' => 'e0ec7f2f',
'javelin-behavior-phabricator-oncopy' => '2926fff2', 'javelin-behavior-phabricator-oncopy' => '2926fff2',
@ -784,17 +786,16 @@ return array(
'phabricator-keyboard-shortcut' => '1ae869f2', 'phabricator-keyboard-shortcut' => '1ae869f2',
'phabricator-keyboard-shortcut-manager' => '4a021c10', 'phabricator-keyboard-shortcut-manager' => '4a021c10',
'phabricator-main-menu-view' => 'b623169f', 'phabricator-main-menu-view' => 'b623169f',
'phabricator-nav-view-css' => 'ac79a758', 'phabricator-nav-view-css' => '09f3d0db',
'phabricator-notification' => 'ccf1cbf8', 'phabricator-notification' => 'ccf1cbf8',
'phabricator-notification-css' => '3f6c89c9', 'phabricator-notification-css' => '3f6c89c9',
'phabricator-notification-menu-css' => 'f31c0bde', 'phabricator-notification-menu-css' => 'f31c0bde',
'phabricator-object-selector-css' => '85ee8ce6', 'phabricator-object-selector-css' => '85ee8ce6',
'phabricator-phtize' => 'd254d646', 'phabricator-phtize' => 'd254d646',
'phabricator-prefab' => 'cfd23f37', 'phabricator-prefab' => 'cfd23f37',
'phabricator-remarkup-css' => '523d34bb', 'phabricator-remarkup-css' => '5ed06ed8',
'phabricator-search-results-css' => '7dea472c', 'phabricator-search-results-css' => '7dea472c',
'phabricator-shaped-request' => '7cbe244b', 'phabricator-shaped-request' => '7cbe244b',
'phabricator-side-menu-view-css' => 'dd849797',
'phabricator-slowvote-css' => 'a94b7230', 'phabricator-slowvote-css' => 'a94b7230',
'phabricator-source-code-view-css' => 'cbeef983', 'phabricator-source-code-view-css' => 'cbeef983',
'phabricator-standard-page-view' => 'e709f6d0', 'phabricator-standard-page-view' => 'e709f6d0',
@ -824,26 +825,27 @@ return array(
'phriction-document-css' => '4282e4ad', 'phriction-document-css' => '4282e4ad',
'phui-action-panel-css' => '91c7b835', 'phui-action-panel-css' => '91c7b835',
'phui-badge-view-css' => '3baef8db', 'phui-badge-view-css' => '3baef8db',
'phui-basic-nav-view-css' => '7093573b',
'phui-big-info-view-css' => 'bd903741', 'phui-big-info-view-css' => 'bd903741',
'phui-box-css' => '5c8387cf', 'phui-box-css' => '5c8387cf',
'phui-button-css' => '4a5fbe3d', 'phui-button-css' => '4a5fbe3d',
'phui-calendar-css' => 'daadaf39', 'phui-calendar-css' => '477acfaa',
'phui-calendar-day-css' => '572b1893', 'phui-calendar-day-css' => '572b1893',
'phui-calendar-list-css' => 'fcc9fb41', 'phui-calendar-list-css' => 'fcc9fb41',
'phui-calendar-month-css' => '8e10e92c', 'phui-calendar-month-css' => '8e10e92c',
'phui-chart-css' => '6bf6f78e', 'phui-chart-css' => '6bf6f78e',
'phui-crumbs-view-css' => 'b4fa5755', 'phui-crumbs-view-css' => '9dac418c',
'phui-curtain-view-css' => '7148ae25', 'phui-curtain-view-css' => '7148ae25',
'phui-document-summary-view-css' => '9ca48bdf', 'phui-document-summary-view-css' => '9ca48bdf',
'phui-document-view-css' => '715aedfb', 'phui-document-view-css' => '715aedfb',
'phui-document-view-pro-css' => 'a3730b94', 'phui-document-view-pro-css' => 'dc3d46ed',
'phui-feed-story-css' => 'aa49845d', 'phui-feed-story-css' => 'aa49845d',
'phui-font-icon-base-css' => '6449bce8', 'phui-font-icon-base-css' => '6449bce8',
'phui-fontkit-css' => '9cda225e', 'phui-fontkit-css' => '9cda225e',
'phui-form-css' => 'aac1d51d', 'phui-form-css' => 'aac1d51d',
'phui-form-view-css' => 'fab0a10f', 'phui-form-view-css' => 'fab0a10f',
'phui-head-thing-view-css' => 'fd311e5f', 'phui-head-thing-view-css' => 'fd311e5f',
'phui-header-view-css' => '4c7dd8f5', 'phui-header-view-css' => '06385974',
'phui-hovercard' => '1bd28176', 'phui-hovercard' => '1bd28176',
'phui-hovercard-view-css' => 'de1a2119', 'phui-hovercard-view-css' => 'de1a2119',
'phui-icon-set-selector-css' => '1ab67aad', 'phui-icon-set-selector-css' => '1ab67aad',
@ -857,7 +859,7 @@ return array(
'phui-object-item-list-view-css' => '8d99e42b', 'phui-object-item-list-view-css' => '8d99e42b',
'phui-pager-css' => 'bea33d23', 'phui-pager-css' => 'bea33d23',
'phui-pinboard-view-css' => '2495140e', 'phui-pinboard-view-css' => '2495140e',
'phui-profile-menu-css' => 'c8557f33', 'phui-profile-menu-css' => '8a3fc181',
'phui-property-list-view-css' => '6d8e58ac', 'phui-property-list-view-css' => '6d8e58ac',
'phui-remarkup-preview-css' => '1a8f2591', 'phui-remarkup-preview-css' => '1a8f2591',
'phui-segment-bar-view-css' => '46342871', 'phui-segment-bar-view-css' => '46342871',
@ -882,7 +884,7 @@ return array(
'policy-transaction-detail-css' => '82100a43', 'policy-transaction-detail-css' => '82100a43',
'ponder-view-css' => 'fbd45f96', 'ponder-view-css' => 'fbd45f96',
'project-card-view-css' => '9418c97d', 'project-card-view-css' => '9418c97d',
'project-view-css' => 'cbaa10a1', 'project-view-css' => '9ce99f21',
'releeph-core' => '9b3c5733', 'releeph-core' => '9b3c5733',
'releeph-preview-branch' => 'b7a6f4a5', 'releeph-preview-branch' => 'b7a6f4a5',
'releeph-request-differential-create-dialog' => '8d8b92cd', 'releeph-request-differential-create-dialog' => '8d8b92cd',
@ -980,6 +982,16 @@ return array(
'phabricator-prefab', 'phabricator-prefab',
'phuix-icon-view', 'phuix-icon-view',
), ),
'08675c6d' => array(
'javelin-behavior',
'javelin-behavior-device',
'javelin-stratcom',
'javelin-dom',
'javelin-magical-init',
'javelin-vector',
'javelin-request',
'javelin-util',
),
'087e919c' => array( '087e919c' => array(
'javelin-install', 'javelin-install',
'javelin-dom', 'javelin-dom',
@ -1335,16 +1347,6 @@ return array(
'javelin-stratcom', 'javelin-stratcom',
'javelin-vector', 'javelin-vector',
), ),
'56a1ca03' => array(
'javelin-behavior',
'javelin-behavior-device',
'javelin-stratcom',
'javelin-dom',
'javelin-magical-init',
'javelin-vector',
'javelin-request',
'javelin-util',
),
'58dea2fa' => array( '58dea2fa' => array(
'javelin-install', 'javelin-install',
'javelin-util', 'javelin-util',
@ -2252,7 +2254,7 @@ return array(
'phui-header-view-css', 'phui-header-view-css',
'phabricator-filetree-view-css', 'phabricator-filetree-view-css',
'phabricator-nav-view-css', 'phabricator-nav-view-css',
'phabricator-side-menu-view-css', 'phui-basic-nav-view-css',
'phui-crumbs-view-css', 'phui-crumbs-view-css',
'phui-object-item-list-view-css', 'phui-object-item-list-view-css',
'global-drag-and-drop-css', 'global-drag-and-drop-css',

View file

@ -113,7 +113,7 @@ return array(
'phui-header-view-css', 'phui-header-view-css',
'phabricator-filetree-view-css', 'phabricator-filetree-view-css',
'phabricator-nav-view-css', 'phabricator-nav-view-css',
'phabricator-side-menu-view-css', 'phui-basic-nav-view-css',
'phui-crumbs-view-css', 'phui-crumbs-view-css',
'phui-object-item-list-view-css', 'phui-object-item-list-view-css',
'global-drag-and-drop-css', 'global-drag-and-drop-css',

View file

@ -1106,7 +1106,9 @@ phutil_register_library_map(array(
'HarbormasterBuildEngine' => 'applications/harbormaster/engine/HarbormasterBuildEngine.php', 'HarbormasterBuildEngine' => 'applications/harbormaster/engine/HarbormasterBuildEngine.php',
'HarbormasterBuildFailureException' => 'applications/harbormaster/exception/HarbormasterBuildFailureException.php', 'HarbormasterBuildFailureException' => 'applications/harbormaster/exception/HarbormasterBuildFailureException.php',
'HarbormasterBuildGraph' => 'applications/harbormaster/engine/HarbormasterBuildGraph.php', 'HarbormasterBuildGraph' => 'applications/harbormaster/engine/HarbormasterBuildGraph.php',
'HarbormasterBuildInitiatorDatasource' => 'applications/harbormaster/typeahead/HarbormasterBuildInitiatorDatasource.php',
'HarbormasterBuildLintMessage' => 'applications/harbormaster/storage/build/HarbormasterBuildLintMessage.php', 'HarbormasterBuildLintMessage' => 'applications/harbormaster/storage/build/HarbormasterBuildLintMessage.php',
'HarbormasterBuildListController' => 'applications/harbormaster/controller/HarbormasterBuildListController.php',
'HarbormasterBuildLog' => 'applications/harbormaster/storage/build/HarbormasterBuildLog.php', 'HarbormasterBuildLog' => 'applications/harbormaster/storage/build/HarbormasterBuildLog.php',
'HarbormasterBuildLogChunk' => 'applications/harbormaster/storage/build/HarbormasterBuildLogChunk.php', 'HarbormasterBuildLogChunk' => 'applications/harbormaster/storage/build/HarbormasterBuildLogChunk.php',
'HarbormasterBuildLogChunkIterator' => 'applications/harbormaster/storage/build/HarbormasterBuildLogChunkIterator.php', 'HarbormasterBuildLogChunkIterator' => 'applications/harbormaster/storage/build/HarbormasterBuildLogChunkIterator.php',
@ -1129,6 +1131,10 @@ phutil_register_library_map(array(
'HarbormasterBuildPlanTransactionQuery' => 'applications/harbormaster/query/HarbormasterBuildPlanTransactionQuery.php', 'HarbormasterBuildPlanTransactionQuery' => 'applications/harbormaster/query/HarbormasterBuildPlanTransactionQuery.php',
'HarbormasterBuildQuery' => 'applications/harbormaster/query/HarbormasterBuildQuery.php', 'HarbormasterBuildQuery' => 'applications/harbormaster/query/HarbormasterBuildQuery.php',
'HarbormasterBuildRequest' => 'applications/harbormaster/engine/HarbormasterBuildRequest.php', 'HarbormasterBuildRequest' => 'applications/harbormaster/engine/HarbormasterBuildRequest.php',
'HarbormasterBuildSearchConduitAPIMethod' => 'applications/harbormaster/conduit/HarbormasterBuildSearchConduitAPIMethod.php',
'HarbormasterBuildSearchEngine' => 'applications/harbormaster/query/HarbormasterBuildSearchEngine.php',
'HarbormasterBuildStatus' => 'applications/harbormaster/constants/HarbormasterBuildStatus.php',
'HarbormasterBuildStatusDatasource' => 'applications/harbormaster/typeahead/HarbormasterBuildStatusDatasource.php',
'HarbormasterBuildStep' => 'applications/harbormaster/storage/configuration/HarbormasterBuildStep.php', 'HarbormasterBuildStep' => 'applications/harbormaster/storage/configuration/HarbormasterBuildStep.php',
'HarbormasterBuildStepCoreCustomField' => 'applications/harbormaster/customfield/HarbormasterBuildStepCoreCustomField.php', 'HarbormasterBuildStepCoreCustomField' => 'applications/harbormaster/customfield/HarbormasterBuildStepCoreCustomField.php',
'HarbormasterBuildStepCustomField' => 'applications/harbormaster/customfield/HarbormasterBuildStepCustomField.php', 'HarbormasterBuildStepCustomField' => 'applications/harbormaster/customfield/HarbormasterBuildStepCustomField.php',
@ -1199,6 +1205,7 @@ phutil_register_library_map(array(
'HarbormasterQueryAutotargetsConduitAPIMethod' => 'applications/harbormaster/conduit/HarbormasterQueryAutotargetsConduitAPIMethod.php', 'HarbormasterQueryAutotargetsConduitAPIMethod' => 'applications/harbormaster/conduit/HarbormasterQueryAutotargetsConduitAPIMethod.php',
'HarbormasterQueryBuildablesConduitAPIMethod' => 'applications/harbormaster/conduit/HarbormasterQueryBuildablesConduitAPIMethod.php', 'HarbormasterQueryBuildablesConduitAPIMethod' => 'applications/harbormaster/conduit/HarbormasterQueryBuildablesConduitAPIMethod.php',
'HarbormasterQueryBuildsConduitAPIMethod' => 'applications/harbormaster/conduit/HarbormasterQueryBuildsConduitAPIMethod.php', 'HarbormasterQueryBuildsConduitAPIMethod' => 'applications/harbormaster/conduit/HarbormasterQueryBuildsConduitAPIMethod.php',
'HarbormasterQueryBuildsSearchEngineAttachment' => 'applications/harbormaster/engineextension/HarbormasterQueryBuildsSearchEngineAttachment.php',
'HarbormasterRemarkupRule' => 'applications/harbormaster/remarkup/HarbormasterRemarkupRule.php', 'HarbormasterRemarkupRule' => 'applications/harbormaster/remarkup/HarbormasterRemarkupRule.php',
'HarbormasterRunBuildPlansHeraldAction' => 'applications/harbormaster/herald/HarbormasterRunBuildPlansHeraldAction.php', 'HarbormasterRunBuildPlansHeraldAction' => 'applications/harbormaster/herald/HarbormasterRunBuildPlansHeraldAction.php',
'HarbormasterSchemaSpec' => 'applications/harbormaster/storage/HarbormasterSchemaSpec.php', 'HarbormasterSchemaSpec' => 'applications/harbormaster/storage/HarbormasterSchemaSpec.php',
@ -1277,6 +1284,7 @@ phutil_register_library_map(array(
'HeraldRepetitionPolicyConfig' => 'applications/herald/config/HeraldRepetitionPolicyConfig.php', 'HeraldRepetitionPolicyConfig' => 'applications/herald/config/HeraldRepetitionPolicyConfig.php',
'HeraldRule' => 'applications/herald/storage/HeraldRule.php', 'HeraldRule' => 'applications/herald/storage/HeraldRule.php',
'HeraldRuleController' => 'applications/herald/controller/HeraldRuleController.php', 'HeraldRuleController' => 'applications/herald/controller/HeraldRuleController.php',
'HeraldRuleDatasource' => 'applications/herald/typeahead/HeraldRuleDatasource.php',
'HeraldRuleEditor' => 'applications/herald/editor/HeraldRuleEditor.php', 'HeraldRuleEditor' => 'applications/herald/editor/HeraldRuleEditor.php',
'HeraldRuleListController' => 'applications/herald/controller/HeraldRuleListController.php', 'HeraldRuleListController' => 'applications/herald/controller/HeraldRuleListController.php',
'HeraldRulePHIDType' => 'applications/herald/phid/HeraldRulePHIDType.php', 'HeraldRulePHIDType' => 'applications/herald/phid/HeraldRulePHIDType.php',
@ -2036,6 +2044,9 @@ phutil_register_library_map(array(
'PhabricatorCalendarEventEndDateTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventEndDateTransaction.php', 'PhabricatorCalendarEventEndDateTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventEndDateTransaction.php',
'PhabricatorCalendarEventFrequencyTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventFrequencyTransaction.php', 'PhabricatorCalendarEventFrequencyTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventFrequencyTransaction.php',
'PhabricatorCalendarEventFulltextEngine' => 'applications/calendar/search/PhabricatorCalendarEventFulltextEngine.php', 'PhabricatorCalendarEventFulltextEngine' => 'applications/calendar/search/PhabricatorCalendarEventFulltextEngine.php',
'PhabricatorCalendarEventHeraldAdapter' => 'applications/calendar/herald/PhabricatorCalendarEventHeraldAdapter.php',
'PhabricatorCalendarEventHeraldField' => 'applications/calendar/herald/PhabricatorCalendarEventHeraldField.php',
'PhabricatorCalendarEventHeraldFieldGroup' => 'applications/calendar/herald/PhabricatorCalendarEventHeraldFieldGroup.php',
'PhabricatorCalendarEventHostPolicyRule' => 'applications/calendar/policyrule/PhabricatorCalendarEventHostPolicyRule.php', 'PhabricatorCalendarEventHostPolicyRule' => 'applications/calendar/policyrule/PhabricatorCalendarEventHostPolicyRule.php',
'PhabricatorCalendarEventHostTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventHostTransaction.php', 'PhabricatorCalendarEventHostTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventHostTransaction.php',
'PhabricatorCalendarEventIconTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventIconTransaction.php', 'PhabricatorCalendarEventIconTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventIconTransaction.php',
@ -2046,6 +2057,7 @@ phutil_register_library_map(array(
'PhabricatorCalendarEventJoinController' => 'applications/calendar/controller/PhabricatorCalendarEventJoinController.php', 'PhabricatorCalendarEventJoinController' => 'applications/calendar/controller/PhabricatorCalendarEventJoinController.php',
'PhabricatorCalendarEventListController' => 'applications/calendar/controller/PhabricatorCalendarEventListController.php', 'PhabricatorCalendarEventListController' => 'applications/calendar/controller/PhabricatorCalendarEventListController.php',
'PhabricatorCalendarEventMailReceiver' => 'applications/calendar/mail/PhabricatorCalendarEventMailReceiver.php', 'PhabricatorCalendarEventMailReceiver' => 'applications/calendar/mail/PhabricatorCalendarEventMailReceiver.php',
'PhabricatorCalendarEventNameHeraldField' => 'applications/calendar/herald/PhabricatorCalendarEventNameHeraldField.php',
'PhabricatorCalendarEventNameTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventNameTransaction.php', 'PhabricatorCalendarEventNameTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventNameTransaction.php',
'PhabricatorCalendarEventPHIDType' => 'applications/calendar/phid/PhabricatorCalendarEventPHIDType.php', 'PhabricatorCalendarEventPHIDType' => 'applications/calendar/phid/PhabricatorCalendarEventPHIDType.php',
'PhabricatorCalendarEventQuery' => 'applications/calendar/query/PhabricatorCalendarEventQuery.php', 'PhabricatorCalendarEventQuery' => 'applications/calendar/query/PhabricatorCalendarEventQuery.php',
@ -2254,6 +2266,7 @@ phutil_register_library_map(array(
'PhabricatorCustomFieldNumericIndexStorage' => 'infrastructure/customfield/storage/PhabricatorCustomFieldNumericIndexStorage.php', 'PhabricatorCustomFieldNumericIndexStorage' => 'infrastructure/customfield/storage/PhabricatorCustomFieldNumericIndexStorage.php',
'PhabricatorCustomFieldSearchEngineExtension' => 'infrastructure/customfield/engineextension/PhabricatorCustomFieldSearchEngineExtension.php', 'PhabricatorCustomFieldSearchEngineExtension' => 'infrastructure/customfield/engineextension/PhabricatorCustomFieldSearchEngineExtension.php',
'PhabricatorCustomFieldStorage' => 'infrastructure/customfield/storage/PhabricatorCustomFieldStorage.php', 'PhabricatorCustomFieldStorage' => 'infrastructure/customfield/storage/PhabricatorCustomFieldStorage.php',
'PhabricatorCustomFieldStorageQuery' => 'infrastructure/customfield/query/PhabricatorCustomFieldStorageQuery.php',
'PhabricatorCustomFieldStringIndexStorage' => 'infrastructure/customfield/storage/PhabricatorCustomFieldStringIndexStorage.php', 'PhabricatorCustomFieldStringIndexStorage' => 'infrastructure/customfield/storage/PhabricatorCustomFieldStringIndexStorage.php',
'PhabricatorCustomHeaderConfigType' => 'applications/config/custom/PhabricatorCustomHeaderConfigType.php', 'PhabricatorCustomHeaderConfigType' => 'applications/config/custom/PhabricatorCustomHeaderConfigType.php',
'PhabricatorDaemon' => 'infrastructure/daemon/PhabricatorDaemon.php', 'PhabricatorDaemon' => 'infrastructure/daemon/PhabricatorDaemon.php',
@ -5630,6 +5643,7 @@ phutil_register_library_map(array(
'HarbormasterDAO', 'HarbormasterDAO',
'PhabricatorApplicationTransactionInterface', 'PhabricatorApplicationTransactionInterface',
'PhabricatorPolicyInterface', 'PhabricatorPolicyInterface',
'PhabricatorConduitResultInterface',
), ),
'HarbormasterBuildAbortedException' => 'Exception', 'HarbormasterBuildAbortedException' => 'Exception',
'HarbormasterBuildActionController' => 'HarbormasterController', 'HarbormasterBuildActionController' => 'HarbormasterController',
@ -5646,7 +5660,9 @@ phutil_register_library_map(array(
'HarbormasterBuildEngine' => 'Phobject', 'HarbormasterBuildEngine' => 'Phobject',
'HarbormasterBuildFailureException' => 'Exception', 'HarbormasterBuildFailureException' => 'Exception',
'HarbormasterBuildGraph' => 'AbstractDirectedGraph', 'HarbormasterBuildGraph' => 'AbstractDirectedGraph',
'HarbormasterBuildInitiatorDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
'HarbormasterBuildLintMessage' => 'HarbormasterDAO', 'HarbormasterBuildLintMessage' => 'HarbormasterDAO',
'HarbormasterBuildListController' => 'HarbormasterController',
'HarbormasterBuildLog' => array( 'HarbormasterBuildLog' => array(
'HarbormasterDAO', 'HarbormasterDAO',
'PhabricatorPolicyInterface', 'PhabricatorPolicyInterface',
@ -5682,6 +5698,10 @@ phutil_register_library_map(array(
'HarbormasterBuildPlanTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'HarbormasterBuildPlanTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
'HarbormasterBuildQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'HarbormasterBuildQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'HarbormasterBuildRequest' => 'Phobject', 'HarbormasterBuildRequest' => 'Phobject',
'HarbormasterBuildSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod',
'HarbormasterBuildSearchEngine' => 'PhabricatorApplicationSearchEngine',
'HarbormasterBuildStatus' => 'Phobject',
'HarbormasterBuildStatusDatasource' => 'PhabricatorTypeaheadDatasource',
'HarbormasterBuildStep' => array( 'HarbormasterBuildStep' => array(
'HarbormasterDAO', 'HarbormasterDAO',
'PhabricatorApplicationTransactionInterface', 'PhabricatorApplicationTransactionInterface',
@ -5765,6 +5785,7 @@ phutil_register_library_map(array(
'HarbormasterQueryAutotargetsConduitAPIMethod' => 'HarbormasterConduitAPIMethod', 'HarbormasterQueryAutotargetsConduitAPIMethod' => 'HarbormasterConduitAPIMethod',
'HarbormasterQueryBuildablesConduitAPIMethod' => 'HarbormasterConduitAPIMethod', 'HarbormasterQueryBuildablesConduitAPIMethod' => 'HarbormasterConduitAPIMethod',
'HarbormasterQueryBuildsConduitAPIMethod' => 'HarbormasterConduitAPIMethod', 'HarbormasterQueryBuildsConduitAPIMethod' => 'HarbormasterConduitAPIMethod',
'HarbormasterQueryBuildsSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment',
'HarbormasterRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'HarbormasterRemarkupRule' => 'PhabricatorObjectRemarkupRule',
'HarbormasterRunBuildPlansHeraldAction' => 'HeraldAction', 'HarbormasterRunBuildPlansHeraldAction' => 'HeraldAction',
'HarbormasterSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'HarbormasterSchemaSpec' => 'PhabricatorConfigSchemaSpec',
@ -5856,6 +5877,7 @@ phutil_register_library_map(array(
'PhabricatorSubscribableInterface', 'PhabricatorSubscribableInterface',
), ),
'HeraldRuleController' => 'HeraldController', 'HeraldRuleController' => 'HeraldController',
'HeraldRuleDatasource' => 'PhabricatorTypeaheadDatasource',
'HeraldRuleEditor' => 'PhabricatorApplicationTransactionEditor', 'HeraldRuleEditor' => 'PhabricatorApplicationTransactionEditor',
'HeraldRuleListController' => 'HeraldController', 'HeraldRuleListController' => 'HeraldController',
'HeraldRulePHIDType' => 'PhabricatorPHIDType', 'HeraldRulePHIDType' => 'PhabricatorPHIDType',
@ -6739,6 +6761,9 @@ phutil_register_library_map(array(
'PhabricatorCalendarEventEndDateTransaction' => 'PhabricatorCalendarEventDateTransaction', 'PhabricatorCalendarEventEndDateTransaction' => 'PhabricatorCalendarEventDateTransaction',
'PhabricatorCalendarEventFrequencyTransaction' => 'PhabricatorCalendarEventTransactionType', 'PhabricatorCalendarEventFrequencyTransaction' => 'PhabricatorCalendarEventTransactionType',
'PhabricatorCalendarEventFulltextEngine' => 'PhabricatorFulltextEngine', 'PhabricatorCalendarEventFulltextEngine' => 'PhabricatorFulltextEngine',
'PhabricatorCalendarEventHeraldAdapter' => 'HeraldAdapter',
'PhabricatorCalendarEventHeraldField' => 'HeraldField',
'PhabricatorCalendarEventHeraldFieldGroup' => 'HeraldFieldGroup',
'PhabricatorCalendarEventHostPolicyRule' => 'PhabricatorPolicyRule', 'PhabricatorCalendarEventHostPolicyRule' => 'PhabricatorPolicyRule',
'PhabricatorCalendarEventHostTransaction' => 'PhabricatorCalendarEventTransactionType', 'PhabricatorCalendarEventHostTransaction' => 'PhabricatorCalendarEventTransactionType',
'PhabricatorCalendarEventIconTransaction' => 'PhabricatorCalendarEventTransactionType', 'PhabricatorCalendarEventIconTransaction' => 'PhabricatorCalendarEventTransactionType',
@ -6752,6 +6777,7 @@ phutil_register_library_map(array(
'PhabricatorCalendarEventJoinController' => 'PhabricatorCalendarController', 'PhabricatorCalendarEventJoinController' => 'PhabricatorCalendarController',
'PhabricatorCalendarEventListController' => 'PhabricatorCalendarController', 'PhabricatorCalendarEventListController' => 'PhabricatorCalendarController',
'PhabricatorCalendarEventMailReceiver' => 'PhabricatorObjectMailReceiver', 'PhabricatorCalendarEventMailReceiver' => 'PhabricatorObjectMailReceiver',
'PhabricatorCalendarEventNameHeraldField' => 'PhabricatorCalendarEventHeraldField',
'PhabricatorCalendarEventNameTransaction' => 'PhabricatorCalendarEventTransactionType', 'PhabricatorCalendarEventNameTransaction' => 'PhabricatorCalendarEventTransactionType',
'PhabricatorCalendarEventPHIDType' => 'PhabricatorPHIDType', 'PhabricatorCalendarEventPHIDType' => 'PhabricatorPHIDType',
'PhabricatorCalendarEventQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorCalendarEventQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
@ -6986,6 +7012,7 @@ phutil_register_library_map(array(
'PhabricatorCustomFieldNumericIndexStorage' => 'PhabricatorCustomFieldIndexStorage', 'PhabricatorCustomFieldNumericIndexStorage' => 'PhabricatorCustomFieldIndexStorage',
'PhabricatorCustomFieldSearchEngineExtension' => 'PhabricatorSearchEngineExtension', 'PhabricatorCustomFieldSearchEngineExtension' => 'PhabricatorSearchEngineExtension',
'PhabricatorCustomFieldStorage' => 'PhabricatorLiskDAO', 'PhabricatorCustomFieldStorage' => 'PhabricatorLiskDAO',
'PhabricatorCustomFieldStorageQuery' => 'Phobject',
'PhabricatorCustomFieldStringIndexStorage' => 'PhabricatorCustomFieldIndexStorage', 'PhabricatorCustomFieldStringIndexStorage' => 'PhabricatorCustomFieldIndexStorage',
'PhabricatorCustomHeaderConfigType' => 'PhabricatorConfigOptionType', 'PhabricatorCustomHeaderConfigType' => 'PhabricatorConfigOptionType',
'PhabricatorDaemon' => 'PhutilDaemon', 'PhabricatorDaemon' => 'PhutilDaemon',

View file

@ -289,5 +289,19 @@ final class PhabricatorCalendarEventEditor
return $body; return $body;
} }
protected function shouldApplyHeraldRules(
PhabricatorLiskDAO $object,
array $xactions) {
return true;
}
protected function buildHeraldAdapter(
PhabricatorLiskDAO $object,
array $xactions) {
return id(new PhabricatorCalendarEventHeraldAdapter())
->setObject($object);
}
} }

View file

@ -0,0 +1,56 @@
<?php
final class PhabricatorCalendarEventHeraldAdapter extends HeraldAdapter {
private $object;
public function getAdapterApplicationClass() {
return 'PhabricatorCalendarApplication';
}
public function getAdapterContentDescription() {
return pht('React to events being created or updated.');
}
protected function newObject() {
return new PhabricatorCalendarEvent();
}
public function isTestAdapterForObject($object) {
return ($object instanceof PhabricatorCalendarEvent);
}
public function getAdapterTestDescription() {
return pht(
'Test rules which run when an event is created or updated.');
}
public function setObject($object) {
$this->object = $object;
return $this;
}
public function getObject() {
return $this->object;
}
public function getAdapterContentName() {
return pht('Calendar Events');
}
public function supportsRuleType($rule_type) {
switch ($rule_type) {
case HeraldRuleTypeConfig::RULE_TYPE_GLOBAL:
case HeraldRuleTypeConfig::RULE_TYPE_PERSONAL:
return true;
case HeraldRuleTypeConfig::RULE_TYPE_OBJECT:
default:
return false;
}
}
public function getHeraldName() {
return $this->getObject()->getMonogram();
}
}

View file

@ -0,0 +1,13 @@
<?php
abstract class PhabricatorCalendarEventHeraldField extends HeraldField {
public function supportsObject($object) {
return ($object instanceof PhabricatorCalendarEvent);
}
public function getFieldGroupKey() {
return PhabricatorCalendarEventHeraldFieldGroup::FIELDGROUPKEY;
}
}

View file

@ -0,0 +1,16 @@
<?php
final class PhabricatorCalendarEventHeraldFieldGroup
extends HeraldFieldGroup {
const FIELDGROUPKEY = 'calendar.event';
public function getGroupLabel() {
return pht('Event Fields');
}
protected function getGroupOrder() {
return 1000;
}
}

View file

@ -0,0 +1,20 @@
<?php
final class PhabricatorCalendarEventNameHeraldField
extends PhabricatorCalendarEventHeraldField {
const FIELDCONST = 'calendar.event.name';
public function getHeraldFieldName() {
return pht('Name');
}
public function getHeraldFieldValue($object) {
return $object->getName();
}
protected function getHeraldFieldStandardType() {
return self::STANDARD_TEXT;
}
}

View file

@ -369,13 +369,13 @@ final class PhabricatorCalendarEventSearchEngine
->setName($from->format('F Y')); ->setName($from->format('F Y'));
$header = id(new PHUIHeaderView()) $header = id(new PHUIHeaderView())
->setProfileHeader(true)
->setHeader($from->format('F Y')); ->setHeader($from->format('F Y'));
return id(new PhabricatorApplicationSearchResultView()) return id(new PhabricatorApplicationSearchResultView())
->setCrumbs($crumbs) ->setCrumbs($crumbs)
->setHeader($header) ->setHeader($header)
->setContent($month_view) ->setContent($month_view);
->setCollapsed(true);
} }
private function buildCalendarDayView( private function buildCalendarDayView(
@ -443,13 +443,13 @@ final class PhabricatorCalendarEventSearchEngine
); );
$header = id(new PHUIHeaderView()) $header = id(new PHUIHeaderView())
->setProfileHeader(true)
->setHeader($from->format('D, F jS')); ->setHeader($from->format('D, F jS'));
return id(new PhabricatorApplicationSearchResultView()) return id(new PhabricatorApplicationSearchResultView())
->setCrumbs($crumbs) ->setCrumbs($crumbs)
->setHeader($header) ->setHeader($header)
->setContent($day_view) ->setContent($day_view);
->setCollapsed(true);
} }
private function getDisplayYearAndMonthAndDay( private function getDisplayYearAndMonthAndDay(

View file

@ -194,6 +194,7 @@ final class CelerityDefaultPostprocessor
// Background color for "most" themes. // Background color for "most" themes.
'page.background' => '#f8f8fb', 'page.background' => '#f8f8fb',
'page.sidenav' => '#f0f0f2',
'menu.profile.text' => 'rgba(255,255,255,.8)', 'menu.profile.text' => 'rgba(255,255,255,.8)',
'menu.profile.text.selected' => 'rgba(255,255,255,1)', 'menu.profile.text.selected' => 'rgba(255,255,255,1)',

View file

@ -25,7 +25,7 @@ final class ConduitResultSearchEngineExtension
return $object->getFieldSpecificationsForConduit(); return $object->getFieldSpecificationsForConduit();
} }
public function getFieldValuesForConduit($object) { public function getFieldValuesForConduit($object, $data) {
return $object->getFieldValuesForConduit(); return $object->getFieldValuesForConduit();
} }

View file

@ -150,21 +150,69 @@ abstract class DifferentialConduitAPIMethod extends ConduitAPIMethod {
array $revisions) { array $revisions) {
assert_instances_of($revisions, 'DifferentialRevision'); assert_instances_of($revisions, 'DifferentialRevision');
$results = array(); if (!$revisions) {
return array();
}
$field_lists = array();
foreach ($revisions as $revision) { foreach ($revisions as $revision) {
// TODO: This is inefficient and issues a query for each object. $revision_phid = $revision->getPHID();
$field_list = PhabricatorCustomField::getObjectFields( $field_list = PhabricatorCustomField::getObjectFields(
$revision, $revision,
PhabricatorCustomField::ROLE_CONDUIT); PhabricatorCustomField::ROLE_CONDUIT);
$field_list $field_list
->setViewer($viewer) ->setViewer($viewer)
->readFieldsFromStorage($revision); ->readFieldsFromObject($revision);
$field_lists[$revision_phid] = $field_list;
}
$all_fields = array();
foreach ($field_lists as $field_list) {
foreach ($field_list->getFields() as $field) {
$all_fields[] = $field;
}
}
id(new PhabricatorCustomFieldStorageQuery())
->addFields($all_fields)
->execute();
$results = array();
foreach ($field_lists as $revision_phid => $field_list) {
$results[$revision_phid] = array();
foreach ($field_list->getFields() as $field) { foreach ($field_list->getFields() as $field) {
$field_key = $field->getFieldKeyForConduit(); $field_key = $field->getFieldKeyForConduit();
$value = $field->getConduitDictionaryValue(); $value = $field->getConduitDictionaryValue();
$results[$revision->getPHID()][$field_key] = $value; $results[$revision_phid][$field_key] = $value;
}
}
// For compatibility, fill in these "custom fields" by querying for them
// efficiently. See T11404 for discussion.
$legacy_edge_map = array(
'phabricator:projects' =>
PhabricatorProjectObjectHasProjectEdgeType::EDGECONST,
'phabricator:depends-on' =>
DifferentialRevisionDependsOnRevisionEdgeType::EDGECONST,
);
$query = id(new PhabricatorEdgeQuery())
->withSourcePHIDs(array_keys($results))
->withEdgeTypes($legacy_edge_map);
$query->execute();
foreach ($results as $revision_phid => $dict) {
foreach ($legacy_edge_map as $edge_key => $edge_type) {
$phid_list = $query->getDestinationPHIDs(
array($revision_phid),
array($edge_type));
$results[$revision_phid][$edge_key] = $phid_list;
} }
} }

View file

@ -7,10 +7,6 @@ final class DifferentialParentRevisionsField
return 'differential:depends-on'; return 'differential:depends-on';
} }
public function getFieldKeyForConduit() {
return 'phabricator:depends-on';
}
public function getFieldName() { public function getFieldName() {
return pht('Parent Revisions'); return pht('Parent Revisions');
} }
@ -33,7 +29,10 @@ final class DifferentialParentRevisionsField
} }
public function shouldAppearInConduitDictionary() { public function shouldAppearInConduitDictionary() {
return true; // To improve performance, we exclude this field from Conduit results.
// See T11404 for discussion. In modern "differential.revision.search",
// this information is available efficiently as an attachment.
return false;
} }
public function getConduitDictionaryValue() { public function getConduitDictionaryValue() {

View file

@ -91,7 +91,10 @@ final class DifferentialProjectsField
} }
public function shouldAppearInConduitDictionary() { public function shouldAppearInConduitDictionary() {
return true; // To improve performance, we exclude this field from Conduit results.
// See T11404 for discussion. In modern "differential.revision.search",
// this information is available efficiently as an attachment.
return false;
} }
public function getApplicationTransactionMetadata() { public function getApplicationTransactionMetadata() {

View file

@ -20,6 +20,21 @@ final class HeraldDifferentialRevisionAdapter
return new DifferentialRevision(); return new DifferentialRevision();
} }
public function isTestAdapterForObject($object) {
return ($object instanceof DifferentialRevision);
}
public function getAdapterTestDescription() {
return pht(
'Test rules which run when a revision is created or updated.');
}
public function newTestAdapter($object) {
return self::newLegacyAdapter(
$object,
$object->loadActiveDiff());
}
protected function initializeNewAdapter() { protected function initializeNewAdapter() {
$this->revision = $this->newObject(); $this->revision = $this->newObject();
} }

View file

@ -27,10 +27,24 @@ final class HeraldCommitAdapter
return new PhabricatorRepositoryCommit(); return new PhabricatorRepositoryCommit();
} }
public function isTestAdapterForObject($object) {
return ($object instanceof PhabricatorRepositoryCommit);
}
public function getAdapterTestDescription() {
return pht(
'Test rules which run after a commit is discovered and imported.');
}
protected function initializeNewAdapter() { protected function initializeNewAdapter() {
$this->commit = $this->newObject(); $this->commit = $this->newObject();
} }
public function setObject($object) {
$this->commit = $object;
return $this;
}
public function getObject() { public function getObject() {
return $this->commit; return $this->commit;
} }

View file

@ -25,6 +25,20 @@ abstract class HeraldPreCommitAdapter extends HeraldAdapter {
return 'PhabricatorDiffusionApplication'; return 'PhabricatorDiffusionApplication';
} }
public function isTestAdapterForObject($object) {
return ($object instanceof PhabricatorRepositoryCommit);
}
public function canCreateTestAdapterForObject($object) {
return false;
}
public function getAdapterTestDescription() {
return pht(
'Commit hook events depend on repository state which is only available '.
'at push time, and can not be run in test mode.');
}
protected function initializeNewAdapter() { protected function initializeNewAdapter() {
$this->log = new PhabricatorRepositoryPushLog(); $this->log = new PhabricatorRepositoryPushLog();
} }

View file

@ -70,6 +70,7 @@ final class PhabricatorHarbormasterApplication extends PhabricatorApplication {
=> 'HarbormasterBuildableActionController', => 'HarbormasterBuildableActionController',
), ),
'build/' => array( 'build/' => array(
$this->getQueryRoutePattern() => 'HarbormasterBuildListController',
'(?P<id>\d+)/' => 'HarbormasterBuildViewController', '(?P<id>\d+)/' => 'HarbormasterBuildViewController',
'(?P<action>pause|resume|restart|abort)/'. '(?P<action>pause|resume|restart|abort)/'.
'(?P<id>\d+)/(?:(?P<via>[^/]+)/)?' '(?P<id>\d+)/(?:(?P<via>[^/]+)/)?'

View file

@ -0,0 +1,18 @@
<?php
final class HarbormasterBuildSearchConduitAPIMethod
extends PhabricatorSearchEngineAPIMethod {
public function getAPIMethodName() {
return 'harbormaster.build.search';
}
public function newSearchEngine() {
return new HarbormasterBuildSearchEngine();
}
public function getMethodSummary() {
return pht('Find out information about builds.');
}
}

View file

@ -11,6 +11,14 @@ final class HarbormasterQueryBuildsConduitAPIMethod
return pht('Query Harbormaster builds.'); return pht('Query Harbormaster builds.');
} }
public function getMethodStatus() {
return self::METHOD_STATUS_DEPRECATED;
}
public function getMethodStatusDescription() {
return pht('Use %s instead.', 'harbormaster.build.search');
}
protected function defineParamTypes() { protected function defineParamTypes() {
return array( return array(
'ids' => 'optional list<id>', 'ids' => 'optional list<id>',
@ -27,64 +35,42 @@ final class HarbormasterQueryBuildsConduitAPIMethod
protected function execute(ConduitAPIRequest $request) { protected function execute(ConduitAPIRequest $request) {
$viewer = $request->getUser(); $viewer = $request->getUser();
$call = new ConduitCall(
'harbormaster.build.search',
array_filter(array(
'constraints' => array_filter(array(
'ids' => $request->getValue('ids'),
'phids' => $request->getValue('phids'),
'statuses' => $request->getValue('buildStatuses'),
'buildables' => $request->getValue('buildablePHIDs'),
'plans' => $request->getValue('buildPlanPHIDs'),
)),
'attachments' => array(
'querybuilds' => true,
),
'limit' => $request->getValue('limit'),
'before' => $request->getValue('before'),
'after' => $request->getValue('after'),
)));
$query = id(new HarbormasterBuildQuery()) $subsumption = $call->setUser($viewer)
->setViewer($viewer); ->execute();
$ids = $request->getValue('ids');
if ($ids !== null) {
$query->withIDs($ids);
}
$phids = $request->getValue('phids');
if ($phids !== null) {
$query->withPHIDs($phids);
}
$statuses = $request->getValue('buildStatuses');
if ($statuses !== null) {
$query->withBuildStatuses($statuses);
}
$buildable_phids = $request->getValue('buildablePHIDs');
if ($buildable_phids !== null) {
$query->withBuildablePHIDs($buildable_phids);
}
$build_plan_phids = $request->getValue('buildPlanPHIDs');
if ($build_plan_phids !== null) {
$query->withBuildPlanPHIDs($build_plan_phids);
}
$pager = $this->newPager($request);
$builds = $query->executeWithCursorPager($pager);
$data = array(); $data = array();
foreach ($builds as $build) { foreach ($subsumption['data'] as $build_data) {
$querybuilds = idxv(
$id = $build->getID(); $build_data,
$uri = '/harbormaster/build/'.$id.'/'; array('attachments', 'querybuilds'),
$status = $build->getBuildStatus(); array());
$fields = idx($build_data, 'fields', array());
$data[] = array( unset($build_data['fields']);
'id' => $id, unset($build_data['attachments']);
'phid' => $build->getPHID(), $data[] = array_mergev(array($build_data, $querybuilds, $fields));
'uri' => PhabricatorEnv::getProductionURI($uri),
'name' => $build->getBuildPlan()->getName(),
'buildablePHID' => $build->getBuildablePHID(),
'buildPlanPHID' => $build->getBuildPlanPHID(),
'buildStatus' => $status,
'buildStatusName' => HarbormasterBuild::getBuildStatusName($status),
);
} }
$results = array( $subsumption['data'] = $data;
'data' => $data,
);
$results = $this->addPagerResults($results, $pager); return $subsumption;
return $results;
} }
} }

View file

@ -0,0 +1,145 @@
<?php
final class HarbormasterBuildStatus extends Phobject {
/**
* Not currently being built.
*/
const STATUS_INACTIVE = 'inactive';
/**
* Pending pick up by the Harbormaster daemon.
*/
const STATUS_PENDING = 'pending';
/**
* Current building the buildable.
*/
const STATUS_BUILDING = 'building';
/**
* The build has passed.
*/
const STATUS_PASSED = 'passed';
/**
* The build has failed.
*/
const STATUS_FAILED = 'failed';
/**
* The build has aborted.
*/
const STATUS_ABORTED = 'aborted';
/**
* The build encountered an unexpected error.
*/
const STATUS_ERROR = 'error';
/**
* The build has been paused.
*/
const STATUS_PAUSED = 'paused';
/**
* The build has been deadlocked.
*/
const STATUS_DEADLOCKED = 'deadlocked';
/**
* Get a human readable name for a build status constant.
*
* @param const Build status constant.
* @return string Human-readable name.
*/
public static function getBuildStatusName($status) {
$map = self::getBuildStatusMap();
return idx($map, $status, pht('Unknown ("%s")', $status));
}
public static function getBuildStatusMap() {
return array(
self::STATUS_INACTIVE => pht('Inactive'),
self::STATUS_PENDING => pht('Pending'),
self::STATUS_BUILDING => pht('Building'),
self::STATUS_PASSED => pht('Passed'),
self::STATUS_FAILED => pht('Failed'),
self::STATUS_ABORTED => pht('Aborted'),
self::STATUS_ERROR => pht('Unexpected Error'),
self::STATUS_PAUSED => pht('Paused'),
self::STATUS_DEADLOCKED => pht('Deadlocked'),
);
}
public static function getBuildStatusIcon($status) {
switch ($status) {
case self::STATUS_INACTIVE:
case self::STATUS_PENDING:
return PHUIStatusItemView::ICON_OPEN;
case self::STATUS_BUILDING:
return PHUIStatusItemView::ICON_RIGHT;
case self::STATUS_PASSED:
return PHUIStatusItemView::ICON_ACCEPT;
case self::STATUS_FAILED:
return PHUIStatusItemView::ICON_REJECT;
case self::STATUS_ABORTED:
return PHUIStatusItemView::ICON_MINUS;
case self::STATUS_ERROR:
return PHUIStatusItemView::ICON_MINUS;
case self::STATUS_PAUSED:
return PHUIStatusItemView::ICON_MINUS;
case self::STATUS_DEADLOCKED:
return PHUIStatusItemView::ICON_WARNING;
default:
return PHUIStatusItemView::ICON_QUESTION;
}
}
public static function getBuildStatusColor($status) {
switch ($status) {
case self::STATUS_INACTIVE:
return 'dark';
case self::STATUS_PENDING:
case self::STATUS_BUILDING:
return 'blue';
case self::STATUS_PASSED:
return 'green';
case self::STATUS_FAILED:
case self::STATUS_ABORTED:
case self::STATUS_ERROR:
case self::STATUS_DEADLOCKED:
return 'red';
case self::STATUS_PAUSED:
return 'dark';
default:
return 'bluegrey';
}
}
public static function getWaitingStatusConstants() {
return array(
self::STATUS_INACTIVE,
self::STATUS_PENDING,
);
}
public static function getActiveStatusConstants() {
return array(
self::STATUS_BUILDING,
self::STATUS_PAUSED,
);
}
public static function getCompletedStatusConstants() {
return array(
self::STATUS_PASSED,
self::STATUS_FAILED,
self::STATUS_ABORTED,
self::STATUS_ERROR,
self::STATUS_DEADLOCKED,
);
}
}

View file

@ -0,0 +1,15 @@
<?php
final class HarbormasterBuildListController extends HarbormasterController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
return id(new HarbormasterBuildSearchEngine())
->setController($this)
->buildResponse();
}
}

View file

@ -581,9 +581,9 @@ final class HarbormasterBuildViewController
} else { } else {
$status = $build->getBuildStatus(); $status = $build->getBuildStatus();
$status_name = $status_name =
HarbormasterBuild::getBuildStatusName($status); HarbormasterBuildStatus::getBuildStatusName($status);
$icon = HarbormasterBuild::getBuildStatusIcon($status); $icon = HarbormasterBuildStatus::getBuildStatusIcon($status);
$color = HarbormasterBuild::getBuildStatusColor($status); $color = HarbormasterBuildStatus::getBuildStatusColor($status);
} }
$item->setTarget($status_name); $item->setTarget($status_name);

View file

@ -9,6 +9,15 @@ final class HarbormasterBuildableListController extends HarbormasterController {
public function handleRequest(AphrontRequest $request) { public function handleRequest(AphrontRequest $request) {
$items = array(); $items = array();
$items[] = id(new PHUIListItemView())
->setType(PHUIListItemView::TYPE_LABEL)
->setName(pht('Builds'));
$items[] = id(new PHUIListItemView())
->setType(PHUIListItemView::TYPE_LINK)
->setName(pht('Browse Builds'))
->setHref($this->getApplicationURI('build/'));
$items[] = id(new PHUIListItemView()) $items[] = id(new PHUIListItemView())
->setType(PHUIListItemView::TYPE_LABEL) ->setType(PHUIListItemView::TYPE_LABEL)
->setName(pht('Build Plans')); ->setName(pht('Build Plans'));

View file

@ -196,11 +196,10 @@ final class HarbormasterBuildableViewController
->setHref($view_uri); ->setHref($view_uri);
$status = $build->getBuildStatus(); $status = $build->getBuildStatus();
$item->setStatusIcon( $status_color = HarbormasterBuildStatus::getBuildStatusColor($status);
'fa-dot-circle-o '.HarbormasterBuild::getBuildStatusColor($status), $status_name = HarbormasterBuildStatus::getBuildStatusName($status);
HarbormasterBuild::getBuildStatusName($status)); $item->setStatusIcon('fa-dot-circle-o '.$status_color, $status_name);
$item->addAttribute($status_name);
$item->addAttribute(HarbormasterBuild::getBuildStatusName($status));
if ($build->isRestarting()) { if ($build->isRestarting()) {
$item->addIcon('fa-repeat', pht('Restarting')); $item->addIcon('fa-repeat', pht('Restarting'));

View file

@ -63,7 +63,7 @@ final class HarbormasterBuildEngine extends Phobject {
// If any exception is raised, the build is marked as a failure and the // If any exception is raised, the build is marked as a failure and the
// exception is re-thrown (this ensures we don't leave builds in an // exception is re-thrown (this ensures we don't leave builds in an
// inconsistent state). // inconsistent state).
$build->setBuildStatus(HarbormasterBuild::STATUS_ERROR); $build->setBuildStatus(HarbormasterBuildStatus::STATUS_ERROR);
$build->save(); $build->save();
$lock->unlock(); $lock->unlock();
@ -106,30 +106,30 @@ final class HarbormasterBuildEngine extends Phobject {
private function updateBuild(HarbormasterBuild $build) { private function updateBuild(HarbormasterBuild $build) {
if ($build->isAborting()) { if ($build->isAborting()) {
$this->releaseAllArtifacts($build); $this->releaseAllArtifacts($build);
$build->setBuildStatus(HarbormasterBuild::STATUS_ABORTED); $build->setBuildStatus(HarbormasterBuildStatus::STATUS_ABORTED);
$build->save(); $build->save();
} }
if (($build->getBuildStatus() == HarbormasterBuild::STATUS_PENDING) || if (($build->getBuildStatus() == HarbormasterBuildStatus::STATUS_PENDING) ||
($build->isRestarting())) { ($build->isRestarting())) {
$this->restartBuild($build); $this->restartBuild($build);
$build->setBuildStatus(HarbormasterBuild::STATUS_BUILDING); $build->setBuildStatus(HarbormasterBuildStatus::STATUS_BUILDING);
$build->save(); $build->save();
} }
if ($build->isResuming()) { if ($build->isResuming()) {
$build->setBuildStatus(HarbormasterBuild::STATUS_BUILDING); $build->setBuildStatus(HarbormasterBuildStatus::STATUS_BUILDING);
$build->save(); $build->save();
} }
if ($build->isPausing() && !$build->isComplete()) { if ($build->isPausing() && !$build->isComplete()) {
$build->setBuildStatus(HarbormasterBuild::STATUS_PAUSED); $build->setBuildStatus(HarbormasterBuildStatus::STATUS_PAUSED);
$build->save(); $build->save();
} }
$build->deleteUnprocessedCommands(); $build->deleteUnprocessedCommands();
if ($build->getBuildStatus() == HarbormasterBuild::STATUS_BUILDING) { if ($build->getBuildStatus() == HarbormasterBuildStatus::STATUS_BUILDING) {
$this->updateBuildSteps($build); $this->updateBuildSteps($build);
} }
} }
@ -243,7 +243,7 @@ final class HarbormasterBuildEngine extends Phobject {
// If any step failed, fail the whole build, then bail. // If any step failed, fail the whole build, then bail.
if (count($failed)) { if (count($failed)) {
$build->setBuildStatus(HarbormasterBuild::STATUS_FAILED); $build->setBuildStatus(HarbormasterBuildStatus::STATUS_FAILED);
$build->save(); $build->save();
return; return;
} }
@ -251,7 +251,7 @@ final class HarbormasterBuildEngine extends Phobject {
// If every step is complete, we're done with this build. Mark it passed // If every step is complete, we're done with this build. Mark it passed
// and bail. // and bail.
if (count($complete) == count($steps)) { if (count($complete) == count($steps)) {
$build->setBuildStatus(HarbormasterBuild::STATUS_PASSED); $build->setBuildStatus(HarbormasterBuildStatus::STATUS_PASSED);
$build->save(); $build->save();
return; return;
} }
@ -287,7 +287,7 @@ final class HarbormasterBuildEngine extends Phobject {
if (!$runnable && !$waiting && !$underway) { if (!$runnable && !$waiting && !$underway) {
// This means the build is deadlocked, and the user has configured // This means the build is deadlocked, and the user has configured
// circular dependencies. // circular dependencies.
$build->setBuildStatus(HarbormasterBuild::STATUS_DEADLOCKED); $build->setBuildStatus(HarbormasterBuildStatus::STATUS_DEADLOCKED);
$build->save(); $build->save();
return; return;
} }
@ -443,14 +443,14 @@ final class HarbormasterBuildEngine extends Phobject {
$all_pass = true; $all_pass = true;
$any_fail = false; $any_fail = false;
foreach ($buildable->getBuilds() as $build) { foreach ($buildable->getBuilds() as $build) {
if ($build->getBuildStatus() != HarbormasterBuild::STATUS_PASSED) { if ($build->getBuildStatus() != HarbormasterBuildStatus::STATUS_PASSED) {
$all_pass = false; $all_pass = false;
} }
if ($build->getBuildStatus() == HarbormasterBuild::STATUS_FAILED || $any_fail = in_array($build->getBuildStatus(), array(
$build->getBuildStatus() == HarbormasterBuild::STATUS_ERROR || HarbormasterBuildStatus::STATUS_FAILED,
$build->getBuildStatus() == HarbormasterBuild::STATUS_DEADLOCKED) { HarbormasterBuildStatus::STATUS_ERROR,
$any_fail = true; HarbormasterBuildStatus::STATUS_DEADLOCKED,
} ));
} }
if ($any_fail) { if ($any_fail) {

View file

@ -0,0 +1,28 @@
<?php
final class HarbormasterQueryBuildsSearchEngineAttachment
extends PhabricatorSearchEngineAttachment {
public function getAttachmentName() {
return pht('Harbormaster Query Builds');
}
public function getAttachmentDescription() {
return pht(
'This attachment exists solely to provide compatibility with the '.
'message format returned by an outdated API method. It will be '.
'taken away at some point and you should not rely on these fields '.
'being available.');
}
public function getAttachmentForObject($object, $data, $spec) {
$status_name = HarbormasterBuildStatus::getBuildStatusName(
$object->getBuildStatus());
return array(
'uri' => PhabricatorEnv::getProductionURI($object->getURI()),
'name' => $object->getName(),
'buildStatusName' => $status_name,
);
}
}

View file

@ -132,9 +132,9 @@ final class HarbormasterUIEventListener
} }
$status = $build->getBuildStatus(); $status = $build->getBuildStatus();
$status_name = HarbormasterBuild::getBuildStatusName($status); $status_name = HarbormasterBuildStatus::getBuildStatusName($status);
$icon = HarbormasterBuild::getBuildStatusIcon($status); $icon = HarbormasterBuildStatus::getBuildStatusIcon($status);
$color = HarbormasterBuild::getBuildStatusColor($status); $color = HarbormasterBuildStatus::getBuildStatusColor($status);
$item->setIcon($icon, $color, $status_name); $item->setIcon($icon, $color, $status_name);

View file

@ -8,6 +8,7 @@ final class HarbormasterBuildQuery
private $buildStatuses; private $buildStatuses;
private $buildablePHIDs; private $buildablePHIDs;
private $buildPlanPHIDs; private $buildPlanPHIDs;
private $initiatorPHIDs;
private $needBuildTargets; private $needBuildTargets;
public function withIDs(array $ids) { public function withIDs(array $ids) {
@ -35,6 +36,11 @@ final class HarbormasterBuildQuery
return $this; return $this;
} }
public function withInitiatorPHIDs(array $initiator_phids) {
$this->initiatorPHIDs = $initiator_phids;
return $this;
}
public function needBuildTargets($need_targets) { public function needBuildTargets($need_targets) {
$this->needBuildTargets = $need_targets; $this->needBuildTargets = $need_targets;
return $this; return $this;
@ -167,6 +173,13 @@ final class HarbormasterBuildQuery
$this->buildPlanPHIDs); $this->buildPlanPHIDs);
} }
if ($this->initiatorPHIDs !== null) {
$where[] = qsprintf(
$conn,
'initiatorPHID IN (%Ls)',
$this->initiatorPHIDs);
}
return $where; return $where;
} }

View file

@ -0,0 +1,172 @@
<?php
final class HarbormasterBuildSearchEngine
extends PhabricatorApplicationSearchEngine {
public function getResultTypeDescription() {
return pht('Harbormaster Builds');
}
public function getApplicationClassName() {
return 'PhabricatorHarbormasterApplication';
}
public function newQuery() {
return new HarbormasterBuildQuery();
}
protected function buildCustomSearchFields() {
return array(
id(new PhabricatorSearchDatasourceField())
->setLabel(pht('Build Plans'))
->setKey('plans')
->setAliases(array('plan'))
->setDescription(
pht('Search for builds running a given build plan.'))
->setDatasource(new HarbormasterBuildPlanDatasource()),
id(new PhabricatorPHIDsSearchField())
->setLabel(pht('Buildables'))
->setKey('buildables')
->setAliases(array('buildable'))
->setDescription(
pht('Search for builds running against particular buildables.')),
id(new PhabricatorSearchDatasourceField())
->setLabel(pht('Statuses'))
->setKey('statuses')
->setAliases(array('status'))
->setDescription(
pht('Search for builds with given statuses.'))
->setDatasource(new HarbormasterBuildStatusDatasource()),
id(new PhabricatorSearchDatasourceField())
->setLabel(pht('Initiators'))
->setKey('initiators')
->setAliases(array('initiator'))
->setDescription(
pht(
'Search for builds started by someone or something in particular.'))
->setDatasource(new HarbormasterBuildInitiatorDatasource()),
);
}
protected function getHiddenFields() {
return array(
'buildables',
);
}
protected function buildQueryFromParameters(array $map) {
$query = $this->newQuery();
if ($map['plans']) {
$query->withBuildPlanPHIDs($map['plans']);
}
if ($map['statuses']) {
$query->withBuildStatuses($map['statuses']);
}
if ($map['initiators']) {
$query->withInitiatorPHIDs($map['initiators']);
}
return $query;
}
protected function getURI($path) {
return '/harbormaster/build/'.$path;
}
protected function getBuiltinQueryNames() {
return array(
'initiated' => pht('My Builds'),
'all' => pht('All Builds'),
'waiting' => pht('Waiting'),
'active' => pht('Active'),
'completed' => pht('Completed'),
);
}
public function buildSavedQueryFromBuiltin($query_key) {
$query = $this->newSavedQuery();
$query->setQueryKey($query_key);
switch ($query_key) {
case 'initiated':
$viewer = $this->requireViewer();
return $query->setParameter('initiators', array($viewer->getPHID()));
case 'all':
return $query;
case 'waiting':
return $query
->setParameter(
'statuses',
HarbormasterBuildStatus::getWaitingStatusConstants());
case 'active':
return $query
->setParameter(
'statuses',
HarbormasterBuildStatus::getActiveStatusConstants());
case 'completed':
return $query
->setParameter(
'statuses',
HarbormasterBuildStatus::getCompletedStatusConstants());
}
return parent::buildSavedQueryFromBuiltin($query_key);
}
protected function renderResultList(
array $builds,
PhabricatorSavedQuery $query,
array $handles) {
assert_instances_of($builds, 'HarbormasterBuild');
$viewer = $this->requireViewer();
$buildables = mpull($builds, 'getBuildable');
$object_phids = mpull($buildables, 'getBuildablePHID');
$initiator_phids = mpull($builds, 'getInitiatorPHID');
$phids = array_mergev(array($initiator_phids, $object_phids));
$phids = array_unique(array_filter($phids));
$handles = $viewer->loadHandles($phids);
$list = new PHUIObjectItemListView();
foreach ($builds as $build) {
$id = $build->getID();
$initiator = $handles[$build->getInitiatorPHID()];
$buildable_object = $handles[$build->getBuildable()->getBuildablePHID()];
$item = id(new PHUIObjectItemView())
->setViewer($viewer)
->setObject($build)
->setObjectName(pht('Build %d', $build->getID()))
->setHeader($build->getName())
->setHref($build->getURI())
->setEpoch($build->getDateCreated())
->addAttribute($buildable_object->getName());
if ($initiator) {
$item->addHandleIcon($initiator, $initiator->getName());
}
$status = $build->getBuildStatus();
$status_icon = HarbormasterBuildStatus::getBuildStatusIcon($status);
$status_color = HarbormasterBuildStatus::getBuildStatusColor($status);
$status_label = HarbormasterBuildStatus::getBuildStatusName($status);
$item->setStatusIcon("{$status_icon} {$status_color}", $status_label);
$list->addItem($item);
}
$result = new PhabricatorApplicationSearchResultView();
$result->setObjectList($list);
$result->setNoDataString(pht('No builds found.'));
return $result;
}
}

View file

@ -170,7 +170,7 @@ final class HarbormasterBuildable extends HarbormasterDAO
->setBuildablePHID($this->getPHID()) ->setBuildablePHID($this->getPHID())
->setBuildPlanPHID($plan->getPHID()) ->setBuildPlanPHID($plan->getPHID())
->setBuildParameters($parameters) ->setBuildParameters($parameters)
->setBuildStatus(HarbormasterBuild::STATUS_PENDING); ->setBuildStatus(HarbormasterBuildStatus::STATUS_PENDING);
if ($initiator_phid) { if ($initiator_phid) {
$build->setInitiatorPHID($initiator_phid); $build->setInitiatorPHID($initiator_phid);
} }

View file

@ -3,7 +3,8 @@
final class HarbormasterBuild extends HarbormasterDAO final class HarbormasterBuild extends HarbormasterDAO
implements implements
PhabricatorApplicationTransactionInterface, PhabricatorApplicationTransactionInterface,
PhabricatorPolicyInterface { PhabricatorPolicyInterface,
PhabricatorConduitResultInterface {
protected $buildablePHID; protected $buildablePHID;
protected $buildPlanPHID; protected $buildPlanPHID;
@ -18,131 +19,9 @@ final class HarbormasterBuild extends HarbormasterDAO
private $buildTargets = self::ATTACHABLE; private $buildTargets = self::ATTACHABLE;
private $unprocessedCommands = self::ATTACHABLE; private $unprocessedCommands = self::ATTACHABLE;
/**
* Not currently being built.
*/
const STATUS_INACTIVE = 'inactive';
/**
* Pending pick up by the Harbormaster daemon.
*/
const STATUS_PENDING = 'pending';
/**
* Current building the buildable.
*/
const STATUS_BUILDING = 'building';
/**
* The build has passed.
*/
const STATUS_PASSED = 'passed';
/**
* The build has failed.
*/
const STATUS_FAILED = 'failed';
/**
* The build has aborted.
*/
const STATUS_ABORTED = 'aborted';
/**
* The build encountered an unexpected error.
*/
const STATUS_ERROR = 'error';
/**
* The build has been paused.
*/
const STATUS_PAUSED = 'paused';
/**
* The build has been deadlocked.
*/
const STATUS_DEADLOCKED = 'deadlocked';
/**
* Get a human readable name for a build status constant.
*
* @param const Build status constant.
* @return string Human-readable name.
*/
public static function getBuildStatusName($status) {
switch ($status) {
case self::STATUS_INACTIVE:
return pht('Inactive');
case self::STATUS_PENDING:
return pht('Pending');
case self::STATUS_BUILDING:
return pht('Building');
case self::STATUS_PASSED:
return pht('Passed');
case self::STATUS_FAILED:
return pht('Failed');
case self::STATUS_ABORTED:
return pht('Aborted');
case self::STATUS_ERROR:
return pht('Unexpected Error');
case self::STATUS_PAUSED:
return pht('Paused');
case self::STATUS_DEADLOCKED:
return pht('Deadlocked');
default:
return pht('Unknown');
}
}
public static function getBuildStatusIcon($status) {
switch ($status) {
case self::STATUS_INACTIVE:
case self::STATUS_PENDING:
return PHUIStatusItemView::ICON_OPEN;
case self::STATUS_BUILDING:
return PHUIStatusItemView::ICON_RIGHT;
case self::STATUS_PASSED:
return PHUIStatusItemView::ICON_ACCEPT;
case self::STATUS_FAILED:
return PHUIStatusItemView::ICON_REJECT;
case self::STATUS_ABORTED:
return PHUIStatusItemView::ICON_MINUS;
case self::STATUS_ERROR:
return PHUIStatusItemView::ICON_MINUS;
case self::STATUS_PAUSED:
return PHUIStatusItemView::ICON_MINUS;
case self::STATUS_DEADLOCKED:
return PHUIStatusItemView::ICON_WARNING;
default:
return PHUIStatusItemView::ICON_QUESTION;
}
}
public static function getBuildStatusColor($status) {
switch ($status) {
case self::STATUS_INACTIVE:
return 'dark';
case self::STATUS_PENDING:
case self::STATUS_BUILDING:
return 'blue';
case self::STATUS_PASSED:
return 'green';
case self::STATUS_FAILED:
case self::STATUS_ABORTED:
case self::STATUS_ERROR:
case self::STATUS_DEADLOCKED:
return 'red';
case self::STATUS_PAUSED:
return 'dark';
default:
return 'bluegrey';
}
}
public static function initializeNewBuild(PhabricatorUser $actor) { public static function initializeNewBuild(PhabricatorUser $actor) {
return id(new HarbormasterBuild()) return id(new HarbormasterBuild())
->setBuildStatus(self::STATUS_INACTIVE) ->setBuildStatus(HarbormasterBuildStatus::STATUS_INACTIVE)
->setBuildGeneration(0); ->setBuildGeneration(0);
} }
@ -181,6 +60,9 @@ final class HarbormasterBuild extends HarbormasterDAO
'columns' => array('buildablePHID', 'planAutoKey'), 'columns' => array('buildablePHID', 'planAutoKey'),
'unique' => true, 'unique' => true,
), ),
'key_initiator' => array(
'columns' => array('initiatorPHID'),
),
), ),
) + parent::getConfiguration(); ) + parent::getConfiguration();
} }
@ -226,8 +108,9 @@ final class HarbormasterBuild extends HarbormasterDAO
} }
public function isBuilding() { public function isBuilding() {
return $this->getBuildStatus() === self::STATUS_PENDING || return
$this->getBuildStatus() === self::STATUS_BUILDING; $this->getBuildStatus() === HarbormasterBuildStatus::STATUS_PENDING ||
$this->getBuildStatus() === HarbormasterBuildStatus::STATUS_BUILDING;
} }
public function isAutobuild() { public function isAutobuild() {
@ -290,20 +173,13 @@ final class HarbormasterBuild extends HarbormasterDAO
} }
public function isComplete() { public function isComplete() {
switch ($this->getBuildStatus()) { return in_array(
case self::STATUS_PASSED: $this->getBuildStatus(),
case self::STATUS_FAILED: HarbormasterBuildStatus::getCompletedStatusConstants());
case self::STATUS_ABORTED:
case self::STATUS_ERROR:
case self::STATUS_PAUSED:
return true;
}
return false;
} }
public function isPaused() { public function isPaused() {
return ($this->getBuildStatus() == self::STATUS_PAUSED); return ($this->getBuildStatus() == HarbormasterBuildStatus::STATUS_PAUSED);
} }
public function getURI() { public function getURI() {
@ -522,4 +398,49 @@ final class HarbormasterBuild extends HarbormasterDAO
return pht('A build inherits policies from its buildable.'); return pht('A build inherits policies from its buildable.');
} }
/* -( PhabricatorConduitResultInterface )---------------------------------- */
public function getFieldSpecificationsForConduit() {
return array(
id(new PhabricatorConduitSearchFieldSpecification())
->setKey('buildablePHID')
->setType('phid')
->setDescription(pht('PHID of the object this build is building.')),
id(new PhabricatorConduitSearchFieldSpecification())
->setKey('buildPlanPHID')
->setType('phid')
->setDescription(pht('PHID of the build plan being run.')),
id(new PhabricatorConduitSearchFieldSpecification())
->setKey('buildStatus')
->setType('map<string, wild>')
->setDescription(pht('The current status of this build.')),
id(new PhabricatorConduitSearchFieldSpecification())
->setKey('initiatorPHID')
->setType('phid')
->setDescription(pht('The person (or thing) that started this build.')),
);
}
public function getFieldValuesForConduit() {
$status = $this->getBuildStatus();
return array(
'buildablePHID' => $this->getBuildablePHID(),
'buildPlanPHID' => $this->getBuildPlanPHID(),
'buildStatus' => array(
'value' => $status,
'name' => HarbormasterBuildStatus::getBuildStatusName($status),
),
'initiatorPHID' => nonempty($this->getInitiatorPHID(), null),
);
}
public function getConduitSearchAttachments() {
return array(
id(new HarbormasterQueryBuildsSearchEngineAttachment())
->setAttachmentKey('querybuilds'),
);
}
} }

View file

@ -0,0 +1,22 @@
<?php
final class HarbormasterBuildInitiatorDatasource
extends PhabricatorTypeaheadCompositeDatasource {
public function getBrowseTitle() {
return pht('Browse Build Initiators');
}
public function getPlaceholderText() {
return pht('Type the name of a user, application or Herald rule...');
}
public function getComponentDatasources() {
return array(
new PhabricatorApplicationDatasource(),
new PhabricatorPeopleUserFunctionDatasource(),
new HeraldRuleDatasource(),
);
}
}

View file

@ -0,0 +1,45 @@
<?php
final class HarbormasterBuildStatusDatasource
extends PhabricatorTypeaheadDatasource {
public function getBrowseTitle() {
return pht('Choose Build Statuses');
}
public function getPlaceholderText() {
return pht('Type a build status name...');
}
public function getDatasourceApplicationClass() {
return 'PhabricatorHarbormasterApplication';
}
public function loadResults() {
$results = $this->buildResults();
return $this->filterResultsAgainstTokens($results);
}
public function renderTokens(array $values) {
return $this->renderTokensFromResults($this->buildResults(), $values);
}
private function buildResults() {
$results = array();
$status_map = HarbormasterBuildStatus::getBuildStatusMap();
foreach ($status_map as $value => $name) {
$result = id(new PhabricatorTypeaheadResult())
->setIcon(HarbormasterBuildStatus::getBuildStatusIcon($value))
->setColor(HarbormasterBuildStatus::getBuildStatusColor($value))
->setPHID($value)
->setName($name)
->addAttribute(pht('Status'));
$results[$value] = $result;
}
return $results;
}
}

View file

@ -189,7 +189,6 @@ abstract class HeraldAdapter extends Phobject {
abstract public function getAdapterApplicationClass(); abstract public function getAdapterApplicationClass();
abstract public function getObject(); abstract public function getObject();
/** /**
* Return a new characteristic object for this adapter. * Return a new characteristic object for this adapter.
* *
@ -217,6 +216,23 @@ abstract class HeraldAdapter extends Phobject {
return false; return false;
} }
public function isTestAdapterForObject($object) {
return false;
}
public function canCreateTestAdapterForObject($object) {
return $this->isTestAdapterForObject($object);
}
public function newTestAdapter($object) {
return id(clone $this)
->setObject($object);
}
public function getAdapterTestDescription() {
return null;
}
public function explainValidTriggerObjects() { public function explainValidTriggerObjects() {
return pht('This adapter can not trigger on objects.'); return pht('This adapter can not trigger on objects.');
} }
@ -752,7 +768,10 @@ abstract class HeraldAdapter extends Phobject {
); );
} }
abstract protected function initializeNewAdapter(); protected function initializeNewAdapter() {
$this->setObject($this->newObject());
return $this;
}
/** /**
* Does this adapter's event fire only once? * Does this adapter's event fire only once?

View file

@ -2,14 +2,76 @@
final class HeraldTestConsoleController extends HeraldController { final class HeraldTestConsoleController extends HeraldController {
private $testObject;
private $testAdapter;
public function setTestObject($test_object) {
$this->testObject = $test_object;
return $this;
}
public function getTestObject() {
return $this->testObject;
}
public function setTestAdapter(HeraldAdapter $test_adapter) {
$this->testAdapter = $test_adapter;
return $this;
}
public function getTestAdapter() {
return $this->testAdapter;
}
public function handleRequest(AphrontRequest $request) { public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer(); $viewer = $request->getViewer();
$object_name = trim($request->getStr('object_name'));
$response = $this->loadTestObject($request);
if ($response) {
return $response;
}
$response = $this->loadAdapter($request);
if ($response) {
return $response;
}
$object = $this->getTestObject();
$adapter = $this->getTestAdapter();
$adapter->setIsNewObject(false);
$rules = id(new HeraldRuleQuery())
->setViewer($viewer)
->withContentTypes(array($adapter->getAdapterContentType()))
->withDisabled(false)
->needConditionsAndActions(true)
->needAppliedToPHIDs(array($object->getPHID()))
->needValidateAuthors(true)
->execute();
$engine = id(new HeraldEngine())
->setDryRun(true);
$effects = $engine->applyRules($rules, $adapter);
$engine->applyEffects($effects, $adapter, $rules);
$xscript = $engine->getTranscript();
return id(new AphrontRedirectResponse())
->setURI('/herald/transcript/'.$xscript->getID().'/');
}
private function loadTestObject(AphrontRequest $request) {
$viewer = $this->getViewer();
$e_name = true; $e_name = true;
$v_name = null;
$errors = array(); $errors = array();
if ($request->isFormPost()) { if ($request->isFormPost()) {
if (!$object_name) { $v_name = trim($request->getStr('object_name'));
if (!$v_name) {
$e_name = pht('Required'); $e_name = pht('Required');
$errors[] = pht('An object name is required.'); $errors[] = pht('An object name is required.');
} }
@ -17,66 +79,18 @@ final class HeraldTestConsoleController extends HeraldController {
if (!$errors) { if (!$errors) {
$object = id(new PhabricatorObjectQuery()) $object = id(new PhabricatorObjectQuery())
->setViewer($viewer) ->setViewer($viewer)
->withNames(array($object_name)) ->withNames(array($v_name))
->executeOne(); ->executeOne();
if (!$object) { if (!$object) {
$e_name = pht('Invalid'); $e_name = pht('Invalid');
$errors[] = pht('No object exists with that name.'); $errors[] = pht('No object exists with that name.');
} }
}
if (!$errors) { if (!$errors) {
$this->setTestObject($object);
// TODO: Let the adapters claim objects instead. return null;
if ($object instanceof DifferentialRevision) {
$adapter = HeraldDifferentialRevisionAdapter::newLegacyAdapter(
$object,
$object->loadActiveDiff());
} else if ($object instanceof PhabricatorRepositoryCommit) {
$adapter = id(new HeraldCommitAdapter())
->setCommit($object);
} else if ($object instanceof ManiphestTask) {
$adapter = id(new HeraldManiphestTaskAdapter())
->setTask($object);
} else if ($object instanceof PholioMock) {
$adapter = id(new HeraldPholioMockAdapter())
->setMock($object);
} else if ($object instanceof PhrictionDocument) {
$adapter = id(new PhrictionDocumentHeraldAdapter())
->setDocument($object);
} else if ($object instanceof PonderQuestion) {
$adapter = id(new HeraldPonderQuestionAdapter())
->setQuestion($object);
} else if ($object instanceof PhabricatorMetaMTAMail) {
$adapter = id(new PhabricatorMailOutboundMailHeraldAdapter())
->setObject($object);
} else {
throw new Exception(pht('Can not build adapter for object!'));
}
$adapter->setIsNewObject(false);
$rules = id(new HeraldRuleQuery())
->setViewer($viewer)
->withContentTypes(array($adapter->getAdapterContentType()))
->withDisabled(false)
->needConditionsAndActions(true)
->needAppliedToPHIDs(array($object->getPHID()))
->needValidateAuthors(true)
->execute();
$engine = id(new HeraldEngine())
->setDryRun(true);
$effects = $engine->applyRules($rules, $adapter);
$engine->applyEffects($effects, $adapter, $rules);
$xscript = $engine->getTranscript();
return id(new AphrontRedirectResponse())
->setURI('/herald/transcript/'.$xscript->getID().'/');
}
} }
} }
@ -92,11 +106,89 @@ final class HeraldTestConsoleController extends HeraldController {
->setLabel(pht('Object Name')) ->setLabel(pht('Object Name'))
->setName('object_name') ->setName('object_name')
->setError($e_name) ->setError($e_name)
->setValue($object_name)) ->setValue($v_name))
->appendChild( ->appendChild(
id(new AphrontFormSubmitControl()) id(new AphrontFormSubmitControl())
->setValue(pht('Test Rules'))); ->setValue(pht('Continue')));
return $this->buildTestConsoleResponse($form, $errors);
}
private function loadAdapter(AphrontRequest $request) {
$viewer = $this->getViewer();
$object = $this->getTestObject();
$adapter_key = $request->getStr('adapter');
$adapters = HeraldAdapter::getAllAdapters();
$can_select = array();
$display_adapters = array();
foreach ($adapters as $key => $adapter) {
if (!$adapter->isTestAdapterForObject($object)) {
continue;
}
if (!$adapter->isAvailableToUser($viewer)) {
continue;
}
$display_adapters[$key] = $adapter;
if ($adapter->canCreateTestAdapterForObject($object)) {
$can_select[$key] = $adapter;
}
}
if ($request->isFormPost() && $adapter_key) {
if (isset($can_select[$adapter_key])) {
$adapter = $can_select[$adapter_key]->newTestAdapter($object);
$this->setTestAdapter($adapter);
return null;
}
}
$form = id(new AphrontFormView())
->addHiddenInput('object_name', $request->getStr('object_name'))
->setViewer($viewer);
$cancel_uri = $this->getApplicationURI();
if (!$display_adapters) {
$form
->appendRemarkupInstructions(
pht('//There are no available Herald events for this object.//'))
->appendControl(
id(new AphrontFormSubmitControl())
->addCancelButton($cancel_uri));
} else {
$adapter_control = id(new AphrontFormRadioButtonControl())
->setLabel(pht('Event'))
->setName('adapter')
->setValue(head_key($can_select));
foreach ($display_adapters as $adapter_key => $adapter) {
$is_disabled = empty($can_select[$adapter_key]);
$adapter_control->addButton(
$adapter_key,
$adapter->getAdapterContentName(),
$adapter->getAdapterTestDescription(),
null,
$is_disabled);
}
$form
->appendControl($adapter_control)
->appendControl(
id(new AphrontFormSubmitControl())
->setValue(pht('Run Test')));
}
return $this->buildTestConsoleResponse($form, array());
}
private function buildTestConsoleResponse($form, array $errors) {
$box = id(new PHUIObjectBoxView()) $box = id(new PHUIObjectBoxView())
->setFormErrors($errors) ->setFormErrors($errors)
->setForm($form); ->setForm($form);
@ -118,11 +210,7 @@ final class HeraldTestConsoleController extends HeraldController {
return $this->newPage() return $this->newPage()
->setTitle($title) ->setTitle($title)
->setCrumbs($crumbs) ->setCrumbs($crumbs)
->appendChild( ->appendChild($view);
array(
$view,
));
} }
} }

View file

@ -8,6 +8,7 @@ final class HeraldRuleQuery extends PhabricatorCursorPagedPolicyAwareQuery {
private $ruleTypes; private $ruleTypes;
private $contentTypes; private $contentTypes;
private $disabled; private $disabled;
private $datasourceQuery;
private $triggerObjectPHIDs; private $triggerObjectPHIDs;
private $needConditionsAndActions; private $needConditionsAndActions;
@ -49,6 +50,11 @@ final class HeraldRuleQuery extends PhabricatorCursorPagedPolicyAwareQuery {
return $this; return $this;
} }
public function withDatasourceQuery($query) {
$this->datasourceQuery = $query;
return $this;
}
public function withTriggerObjectPHIDs(array $phids) { public function withTriggerObjectPHIDs(array $phids) {
$this->triggerObjectPHIDs = $phids; $this->triggerObjectPHIDs = $phids;
return $this; return $this;
@ -219,6 +225,13 @@ final class HeraldRuleQuery extends PhabricatorCursorPagedPolicyAwareQuery {
(int)$this->disabled); (int)$this->disabled);
} }
if ($this->datasourceQuery) {
$where[] = qsprintf(
$conn_r,
'rule.name LIKE %>',
$this->datasourceQuery);
}
if ($this->triggerObjectPHIDs) { if ($this->triggerObjectPHIDs) {
$where[] = qsprintf( $where[] = qsprintf(
$conn_r, $conn_r,

View file

@ -34,7 +34,7 @@ final class HeraldRule extends HeraldDAO
return array( return array(
self::CONFIG_AUX_PHID => true, self::CONFIG_AUX_PHID => true,
self::CONFIG_COLUMN_SCHEMA => array( self::CONFIG_COLUMN_SCHEMA => array(
'name' => 'text255', 'name' => 'sort255',
'contentType' => 'text255', 'contentType' => 'text255',
'mustMatchAll' => 'bool', 'mustMatchAll' => 'bool',
'configVersion' => 'uint32', 'configVersion' => 'uint32',
@ -47,6 +47,9 @@ final class HeraldRule extends HeraldDAO
'repetitionPolicy' => 'uint32?', 'repetitionPolicy' => 'uint32?',
), ),
self::CONFIG_KEY_SCHEMA => array( self::CONFIG_KEY_SCHEMA => array(
'key_name' => array(
'columns' => array('name(128)'),
),
'key_author' => array( 'key_author' => array(
'columns' => array('authorPHID'), 'columns' => array('authorPHID'),
), ),

View file

@ -0,0 +1,49 @@
<?php
final class HeraldRuleDatasource
extends PhabricatorTypeaheadDatasource {
public function getPlaceholderText() {
return pht('Type a Herald rule name...');
}
public function getBrowseTitle() {
return pht('Browse Herald Rules');
}
public function getDatasourceApplicationClass() {
return 'PhabricatorHeraldApplication';
}
public function loadResults() {
$viewer = $this->getViewer();
$raw_query = $this->getRawQuery();
$rules = id(new HeraldRuleQuery())
->setViewer($viewer)
->withDatasourceQuery($raw_query)
->execute();
$handles = id(new PhabricatorHandleQuery())
->setViewer($viewer)
->withPHIDs(mpull($rules, 'getPHID'))
->execute();
$results = array();
foreach ($rules as $rule) {
$handle = $handles[$rule->getPHID()];
$result = id(new PhabricatorTypeaheadResult())
->setName($handle->getFullName())
->setPHID($handle->getPHID());
if ($rule->getIsDisabled()) {
$result->setClosed(pht('Archived'));
}
$results[] = $result;
}
return $results;
}
}

View file

@ -53,6 +53,7 @@ final class PhabricatorHomeMainController extends PhabricatorHomeController {
return $this->newPage() return $this->newPage()
->setTitle('Phabricator') ->setTitle('Phabricator')
->addClass('phabricator-home')
->appendChild($content); ->appendChild($content);
} }

View file

@ -31,7 +31,9 @@ final class ManiphestExportController extends ManiphestController {
'<p>%s</p>'. '<p>%s</p>'.
'<br />'. '<br />'.
'<p>'. '<p>'.
'<a href="http://www.phpexcel.net/">http://www.phpexcel.net/</a>'. '<a href="https://github.com/PHPOffice/PHPExcel">'.
'https://github.com/PHPOffice/PHPExcel'.
'</a>'.
'</p>'. '</p>'.
'<br />'. '<br />'.
'<p>%s</p>', '<p>%s</p>',

View file

@ -16,6 +16,15 @@ final class HeraldManiphestTaskAdapter extends HeraldAdapter {
return pht('React to tasks being created or updated.'); return pht('React to tasks being created or updated.');
} }
public function isTestAdapterForObject($object) {
return ($object instanceof ManiphestTask);
}
public function getAdapterTestDescription() {
return pht(
'Test rules which run when a task is created or updated.');
}
protected function initializeNewAdapter() { protected function initializeNewAdapter() {
$this->task = $this->newObject(); $this->task = $this->newObject();
} }
@ -46,10 +55,16 @@ final class HeraldManiphestTaskAdapter extends HeraldAdapter {
$this->task = $task; $this->task = $task;
return $this; return $this;
} }
public function getTask() { public function getTask() {
return $this->task; return $this->task;
} }
public function setObject($object) {
$this->task = $object;
return $this;
}
public function getObject() { public function getObject() {
return $this->task; return $this->task;
} }

View file

@ -96,7 +96,7 @@ final class ManiphestTaskListView extends ManiphestView {
$project_handles = array_select_keys( $project_handles = array_select_keys(
$handles, $handles,
$task->getProjectPHIDs()); array_reverse($task->getProjectPHIDs()));
$item->addAttribute( $item->addAttribute(
id(new PHUIHandleTagListView()) id(new PHUIHandleTagListView())

View file

@ -21,6 +21,17 @@ final class PhabricatorMailOutboundMailHeraldAdapter
return new PhabricatorMetaMTAMail(); return new PhabricatorMetaMTAMail();
} }
public function isTestAdapterForObject($object) {
return ($object instanceof PhabricatorMetaMTAMail);
}
public function getAdapterTestDescription() {
return pht(
'Test rules which run when outbound mail is being prepared for '.
'delivery.');
}
public function getObject() { public function getObject() {
return $this->mail; return $this->mail;
} }

View file

@ -20,6 +20,20 @@ final class HeraldPholioMockAdapter extends HeraldAdapter {
return new PholioMock(); return new PholioMock();
} }
public function isTestAdapterForObject($object) {
return ($object instanceof PholioMock);
}
public function getAdapterTestDescription() {
return pht(
'Test rules which run when a mock is created or updated.');
}
public function setObject($object) {
$this->mock = $object;
return $this;
}
public function getObject() { public function getObject() {
return $this->mock; return $this->mock;
} }
@ -28,6 +42,7 @@ final class HeraldPholioMockAdapter extends HeraldAdapter {
$this->mock = $mock; $this->mock = $mock;
return $this; return $this;
} }
public function getMock() { public function getMock() {
return $this->mock; return $this->mock;
} }

View file

@ -20,6 +20,20 @@ final class PhrictionDocumentHeraldAdapter extends HeraldAdapter {
return new PhrictionDocument(); return new PhrictionDocument();
} }
public function isTestAdapterForObject($object) {
return ($object instanceof PhrictionDocument);
}
public function getAdapterTestDescription() {
return pht(
'Test rules which run when a wiki document is created or updated.');
}
public function setObject($object) {
$this->document = $object;
return $this;
}
public function getObject() { public function getObject() {
return $this->document; return $this->document;
} }

View file

@ -30,7 +30,7 @@ final class PhabricatorPolicySearchEngineExtension
); );
} }
public function getFieldValuesForConduit($object) { public function getFieldValuesForConduit($object, $data) {
$capabilities = $object->getCapabilities(); $capabilities = $object->getCapabilities();
$map = array(); $map = array();

View file

@ -20,6 +20,21 @@ final class HeraldPonderQuestionAdapter extends HeraldAdapter {
$this->question = $this->newObject(); $this->question = $this->newObject();
} }
public function isTestAdapterForObject($object) {
return ($object instanceof PonderQuestion);
}
public function getAdapterTestDescription() {
return pht(
'Test rules which run when a question is created or updated.');
}
public function setObject($object) {
$this->question = $object;
return $this;
}
public function supportsApplicationEmail() { public function supportsApplicationEmail() {
return true; return true;
} }

View file

@ -128,6 +128,7 @@ final class ProjectBoardTaskCard extends Phobject {
} }
if ($project_handles) { if ($project_handles) {
$project_handles = array_reverse($project_handles);
$tag_list = id(new PHUIHandleTagListView()) $tag_list = id(new PHUIHandleTagListView())
->setSlim(true) ->setSlim(true)
->setHandles($project_handles); ->setHandles($project_handles);

View file

@ -193,10 +193,12 @@ final class PhabricatorApplicationSearchController
} }
$header = id(new PHUIHeaderView()) $header = id(new PHUIHeaderView())
->setHeader($title); ->setHeader($title)
->setProfileHeader(true);
$box = id(new PHUIObjectBoxView()) $box = id(new PHUIObjectBoxView())
->setHeader($header); ->setHeader($header)
->addClass('application-search-results');
if ($run_query || $named_query) { if ($run_query || $named_query) {
$box->setShowHide( $box->setShowHide(
@ -281,9 +283,8 @@ final class PhabricatorApplicationSearchController
if ($pager->willShowPagingControls()) { if ($pager->willShowPagingControls()) {
$pager_box = id(new PHUIBoxView()) $pager_box = id(new PHUIBoxView())
->addPadding(PHUI::PADDING_MEDIUM) ->setColor(PHUIBoxView::GREY)
->addMargin(PHUI::MARGIN_LARGE) ->addClass('application-search-pager')
->setBorder(true)
->appendChild($pager); ->appendChild($pager);
$body[] = $pager_box; $body[] = $pager_box;
} }
@ -308,7 +309,8 @@ final class PhabricatorApplicationSearchController
} }
$crumbs = $parent $crumbs = $parent
->buildApplicationCrumbs(); ->buildApplicationCrumbs()
->setBorder(true);
if ($more_crumbs) { if ($more_crumbs) {
$query_uri = $engine->getQueryResultsPageURI($saved_query->getQueryKey()); $query_uri = $engine->getQueryResultsPageURI($saved_query->getQueryKey());
@ -321,12 +323,15 @@ final class PhabricatorApplicationSearchController
$crumbs->addTextCrumb($title); $crumbs->addTextCrumb($title);
} }
require_celerity_resource('application-search-view-css');
return $this->newPage() return $this->newPage()
->setApplicationMenu($this->buildApplicationMenu()) ->setApplicationMenu($this->buildApplicationMenu())
->setTitle(pht('Query: %s', $title)) ->setTitle(pht('Query: %s', $title))
->setCrumbs($crumbs) ->setCrumbs($crumbs)
->setNavigation($nav) ->setNavigation($nav)
->appendChild($body); ->appendChild($body)
->addClass('application-search-view');
} }
private function processEditRequest() { private function processEditRequest() {
@ -403,19 +408,28 @@ final class PhabricatorApplicationSearchController
$crumbs = $parent $crumbs = $parent
->buildApplicationCrumbs() ->buildApplicationCrumbs()
->addTextCrumb(pht('Saved Queries'), $engine->getQueryManagementURI()); ->addTextCrumb(pht('Saved Queries'), $engine->getQueryManagementURI())
->setBorder(true);
$nav->selectFilter('query/edit'); $nav->selectFilter('query/edit');
$header = id(new PHUIHeaderView())
->setHeader(pht('Saved Queries'))
->setProfileHeader(true);
$box = id(new PHUIObjectBoxView()) $box = id(new PHUIObjectBoxView())
->setHeaderText(pht('Saved Queries')) ->setHeader($header)
->setObjectList($list); ->setObjectList($list)
->addClass('application-search-results');
require_celerity_resource('application-search-view-css');
return $this->newPage() return $this->newPage()
->setApplicationMenu($this->buildApplicationMenu()) ->setApplicationMenu($this->buildApplicationMenu())
->setTitle(pht('Saved Queries')) ->setTitle(pht('Saved Queries'))
->setCrumbs($crumbs) ->setCrumbs($crumbs)
->setNavigation($nav) ->setNavigation($nav)
->addClass('application-search-view')
->appendChild($box); ->appendChild($box);
} }

View file

@ -1138,6 +1138,11 @@ abstract class PhabricatorApplicationSearchEngine extends Phobject {
if ($objects) { if ($objects) {
$field_extensions = $this->getConduitFieldExtensions(); $field_extensions = $this->getConduitFieldExtensions();
$extension_data = array();
foreach ($field_extensions as $key => $extension) {
$extension_data[$key] = $extension->loadExtensionConduitData($objects);
}
$attachment_data = array(); $attachment_data = array();
foreach ($attachments as $key => $attachment) { foreach ($attachments as $key => $attachment) {
$attachment_data[$key] = $attachment->loadAttachmentData( $attachment_data[$key] = $attachment->loadAttachmentData(
@ -1148,7 +1153,8 @@ abstract class PhabricatorApplicationSearchEngine extends Phobject {
foreach ($objects as $object) { foreach ($objects as $object) {
$field_map = $this->getObjectWireFieldsForConduit( $field_map = $this->getObjectWireFieldsForConduit(
$object, $object,
$field_extensions); $field_extensions,
$extension_data);
$attachment_map = array(); $attachment_map = array();
foreach ($attachments as $key => $attachment) { foreach ($attachments as $key => $attachment) {
@ -1312,11 +1318,13 @@ abstract class PhabricatorApplicationSearchEngine extends Phobject {
protected function getObjectWireFieldsForConduit( protected function getObjectWireFieldsForConduit(
$object, $object,
array $field_extensions) { array $field_extensions,
array $extension_data) {
$fields = array(); $fields = array();
foreach ($field_extensions as $extension) { foreach ($field_extensions as $key => $extension) {
$fields += $extension->getFieldValuesForConduit($object); $data = idx($extension_data, $key, array());
$fields += $extension->getFieldValuesForConduit($object, $data);
} }
return $fields; return $fields;

View file

@ -44,7 +44,7 @@ final class PhabricatorLiskSearchEngineExtension
); );
} }
public function getFieldValuesForConduit($object) { public function getFieldValuesForConduit($object, $data) {
return array( return array(
'dateCreated' => (int)$object->getDateCreated(), 'dateCreated' => (int)$object->getDateCreated(),
'dateModified' => (int)$object->getDateModified(), 'dateModified' => (int)$object->getDateModified(),

View file

@ -56,7 +56,11 @@ abstract class PhabricatorSearchEngineExtension extends Phobject {
return array(); return array();
} }
public function getFieldValuesForConduit($object) { public function loadExtensionConduitData(array $objects) {
return null;
}
public function getFieldValuesForConduit($object, $data) {
return array(); return array();
} }

View file

@ -140,7 +140,10 @@ final class PhabricatorMotivatorProfilePanel
'to launch their attacks. Watch out!'), 'to launch their attacks. Watch out!'),
pht('Cats prefer vanilla ice cream.'), pht('Cats prefer vanilla ice cream.'),
pht('Taco cat spelled backwards is taco cat.'), pht('Taco cat spelled backwards is taco cat.'),
); pht(
'Cats will often bring you their prey because they feel sorry '.
'for your inability to hunt.'),
);
} }
private function selectFact(array $facts) { private function selectFact(array $facts) {

View file

@ -63,7 +63,7 @@ final class PhabricatorSpacesSearchEngineExtension
); );
} }
public function getFieldValuesForConduit($object) { public function getFieldValuesForConduit($object, $data) {
return array( return array(
'spacePHID' => $object->getSpacePHID(), 'spacePHID' => $object->getSpacePHID(),
); );

View file

@ -14,7 +14,7 @@ For an introduction to Conduit, see @{article:Conduit API Overview}.
In general, you'll use these API methods: In general, you'll use these API methods:
- `diffusion.repository.edit`: Create and edit repositorie. - `diffusion.repository.edit`: Create and edit repositories.
- `diffusion.uri.edit`: Create and edit repository URIs to configure - `diffusion.uri.edit`: Create and edit repository URIs to configure
observation, mirroring, and cloning. observation, mirroring, and cloning.

View file

@ -80,17 +80,42 @@ final class PhabricatorCustomFieldSearchEngineExtension
return $map; return $map;
} }
public function getFieldValuesForConduit($object) { public function loadExtensionConduitData(array $objects) {
// TODO: This is currently very inefficient. We should bulk-load these $viewer = $this->getViewer();
// field values instead.
$fields = PhabricatorCustomField::getObjectFields( $field_map = array();
$object, foreach ($objects as $object) {
PhabricatorCustomField::ROLE_CONDUIT); $object_phid = $object->getPHID();
$fields $fields = PhabricatorCustomField::getObjectFields(
->setViewer($this->getViewer()) $object,
->readFieldsFromStorage($object); PhabricatorCustomField::ROLE_CONDUIT);
$fields
->setViewer($viewer)
->readFieldsFromObject($object);
$field_map[$object_phid] = $fields;
}
$all_fields = array();
foreach ($field_map as $field_list) {
foreach ($field_list->getFields() as $field) {
$all_fields[] = $field;
}
}
id(new PhabricatorCustomFieldStorageQuery())
->addFields($all_fields)
->execute();
return array(
'fields' => $field_map,
);
}
public function getFieldValuesForConduit($object, $data) {
$fields = $data['fields'][$object->getPHID()];
$map = array(); $map = array();
foreach ($fields->getFields() as $field) { foreach ($fields->getFields() as $field) {

View file

@ -112,20 +112,13 @@ abstract class PhabricatorCustomField extends Phobject {
$object, $object,
array $options = array()) { array $options = array()) {
PhutilTypeSpec::checkMap( $field_objects = id(new PhutilClassMapQuery())
$options,
array(
'withDisabled' => 'optional bool',
));
$field_objects = id(new PhutilSymbolLoader())
->setAncestorClass($base_class) ->setAncestorClass($base_class)
->loadObjects(); ->execute();
$fields = array(); $fields = array();
$from_map = array();
foreach ($field_objects as $field_object) { foreach ($field_objects as $field_object) {
$current_class = get_class($field_object); $field_object = clone $field_object;
foreach ($field_object->createFields($object) as $field) { foreach ($field_object->createFields($object) as $field) {
$key = $field->getFieldKey(); $key = $field->getFieldKey();
if (isset($fields[$key])) { if (isset($fields[$key])) {
@ -133,11 +126,10 @@ abstract class PhabricatorCustomField extends Phobject {
pht( pht(
"Both '%s' and '%s' define a custom field with ". "Both '%s' and '%s' define a custom field with ".
"field key '%s'. Field keys must be unique.", "field key '%s'. Field keys must be unique.",
$from_map[$key], get_class($fields[$key]),
$current_class, get_class($field),
$key)); $key));
} }
$from_map[$key] = $current_class;
$fields[$key] = $field; $fields[$key] = $field;
} }
} }
@ -152,11 +144,13 @@ abstract class PhabricatorCustomField extends Phobject {
if (empty($options['withDisabled'])) { if (empty($options['withDisabled'])) {
foreach ($fields as $key => $field) { foreach ($fields as $key => $field) {
$config = idx($spec, $key, array()) + array( if (isset($spec[$key]['disabled'])) {
'disabled' => $field->shouldDisableByDefault(), $is_disabled = $spec[$key]['disabled'];
); } else {
$is_disabled = $field->shouldDisableByDefault();
}
if (!empty($config['disabled'])) { if ($is_disabled) {
if ($field->canDisableField()) { if ($field->canDisableField()) {
unset($fields[$key]); unset($fields[$key]);
} }

View file

@ -29,6 +29,19 @@ final class PhabricatorCustomFieldList extends Phobject {
return $this; return $this;
} }
public function readFieldsFromObject(
PhabricatorCustomFieldInterface $object) {
$fields = $this->getFields();
foreach ($fields as $field) {
$field
->setObject($object)
->readValueFromObject($object);
}
return $this;
}
/** /**
* Read stored values for all fields which support storage. * Read stored values for all fields which support storage.
@ -39,48 +52,12 @@ final class PhabricatorCustomFieldList extends Phobject {
public function readFieldsFromStorage( public function readFieldsFromStorage(
PhabricatorCustomFieldInterface $object) { PhabricatorCustomFieldInterface $object) {
foreach ($this->fields as $field) { $this->readFieldsFromObject($object);
$field->setObject($object);
$field->readValueFromObject($object);
}
$keys = array(); $fields = $this->getFields();
foreach ($this->fields as $field) { id(new PhabricatorCustomFieldStorageQuery())
if ($field->shouldEnableForRole(PhabricatorCustomField::ROLE_STORAGE)) { ->addFields($fields)
$keys[$field->getFieldIndex()] = $field; ->execute();
}
}
if (!$keys) {
return $this;
}
// NOTE: We assume all fields share the same storage. This isn't guaranteed
// to be true, but always is for now.
$table = head($keys)->newStorageObject();
$objects = array();
if ($object->getPHID()) {
$objects = $table->loadAllWhere(
'objectPHID = %s AND fieldIndex IN (%Ls)',
$object->getPHID(),
array_keys($keys));
$objects = mpull($objects, null, 'getFieldIndex');
}
foreach ($keys as $key => $field) {
$storage = idx($objects, $key);
if ($storage) {
$field->setValueFromStorage($storage->getFieldValue());
$field->didSetValueFromStorage();
} else if ($object->getPHID()) {
// NOTE: We set this only if the object exists. Otherwise, we allow the
// field to retain any default value it may have.
$field->setValueFromStorage(null);
$field->didSetValueFromStorage();
}
}
return $this; return $this;
} }

View file

@ -0,0 +1,84 @@
<?php
/**
* Load custom field data from storage.
*
* This query loads the data directly into the field objects and does not
* return it to the caller. It can bulk load data for any list of fields,
* even if they have different objects or object types.
*/
final class PhabricatorCustomFieldStorageQuery extends Phobject {
private $fieldMap = array();
private $storageSources = array();
public function addFields(array $fields) {
assert_instances_of($fields, 'PhabricatorCustomField');
foreach ($fields as $field) {
$this->addField($field);
}
return $this;
}
public function addField(PhabricatorCustomField $field) {
$role_storage = PhabricatorCustomField::ROLE_STORAGE;
if (!$field->shouldEnableForRole($role_storage)) {
return $this;
}
$storage = $field->newStorageObject();
$source_key = $storage->getStorageSourceKey();
$this->fieldMap[$source_key][] = $field;
if (empty($this->storageSources[$source_key])) {
$this->storageSources[$source_key] = $storage;
}
return $this;
}
public function execute() {
foreach ($this->storageSources as $source_key => $storage) {
$fields = idx($this->fieldMap, $source_key, array());
$this->loadFieldsFromStorage($storage, $fields);
}
}
private function loadFieldsFromStorage($storage, array $fields) {
// Only try to load fields which have a persisted object.
$loadable = array();
foreach ($fields as $key => $field) {
$object = $field->getObject();
$phid = $object->getPHID();
if (!$phid) {
continue;
}
$loadable[$key] = $field;
}
if ($loadable) {
$data = $storage->loadStorageSourceData($loadable);
} else {
$data = array();
}
foreach ($fields as $key => $field) {
if (array_key_exists($key, $data)) {
$value = $data[$key];
$field->setValueFromStorage($value);
$field->didSetValueFromStorage();
} else if (isset($loadable[$key])) {
// NOTE: We set this only if the object exists. Otherwise, we allow
// the field to retain any default value it may have.
$field->setValueFromStorage(null);
$field->didSetValueFromStorage();
}
}
}
}

View file

@ -23,4 +23,68 @@ abstract class PhabricatorCustomFieldStorage
) + parent::getConfiguration(); ) + parent::getConfiguration();
} }
/**
* Get a key which uniquely identifies this storage source.
*
* When loading custom fields, fields using sources with the same source key
* are loaded in bulk.
*
* @return string Source identifier.
*/
final public function getStorageSourceKey() {
return $this->getApplicationName().'/'.$this->getTableName();
}
/**
* Load stored data for custom fields.
*
* Given a map of fields, return a map with any stored data for those fields.
* The keys in the result should correspond to the keys in the input. The
* fields in the list may belong to different objects.
*
* @param map<string, PhabricatorCustomField> Map of fields.
* @return map<String, PhabricatorCustomField> Map of available field data.
*/
final public function loadStorageSourceData(array $fields) {
$map = array();
$indexes = array();
$object_phids = array();
foreach ($fields as $key => $field) {
$index = $field->getFieldIndex();
$object_phid = $field->getObject()->getPHID();
$map[$index][$object_phid] = $key;
$indexes[$index] = $index;
$object_phids[$object_phid] = $object_phid;
}
if (!$indexes) {
return array();
}
$conn = $this->establishConnection('r');
$rows = queryfx_all(
$conn,
'SELECT objectPHID, fieldIndex, fieldValue FROM %T
WHERE objectPHID IN (%Ls) AND fieldIndex IN (%Ls)',
$this->getTableName(),
$object_phids,
$indexes);
$result = array();
foreach ($rows as $row) {
$index = $row['fieldIndex'];
$object_phid = $row['objectPHID'];
$value = $row['fieldValue'];
$key = $map[$index][$object_phid];
$result[$key] = $value;
}
return $result;
}
} }

View file

@ -148,7 +148,7 @@ final class AphrontCursorPagerView extends AphrontView {
->setHref($first_uri) ->setHref($first_uri)
->setIcon($icon) ->setIcon($icon)
->addClass('mml') ->addClass('mml')
->setColor(PHUIButtonView::SIMPLE) ->setColor(PHUIButtonView::GREY)
->setText(pht('First')); ->setText(pht('First'));
} }
@ -161,7 +161,7 @@ final class AphrontCursorPagerView extends AphrontView {
->setHref($prev_uri) ->setHref($prev_uri)
->setIcon($icon) ->setIcon($icon)
->addClass('mml') ->addClass('mml')
->setColor(PHUIButtonView::SIMPLE) ->setColor(PHUIButtonView::GREY)
->setText(pht('Prev')); ->setText(pht('Prev'));
} }
@ -174,7 +174,7 @@ final class AphrontCursorPagerView extends AphrontView {
->setHref($next_uri) ->setHref($next_uri)
->setIcon($icon, false) ->setIcon($icon, false)
->addClass('mml') ->addClass('mml')
->setColor(PHUIButtonView::SIMPLE) ->setColor(PHUIButtonView::GREY)
->setText(pht('Next')); ->setText(pht('Next'));
} }

View file

@ -193,24 +193,18 @@ final class AphrontSideNavFilterView extends AphrontView {
} }
} }
require_celerity_resource('phabricator-side-menu-view-css'); require_celerity_resource('phui-basic-nav-view-css');
return $this->renderFlexNav(); return $this->renderFlexNav();
} }
private function renderFlexNav() { private function renderFlexNav() {
require_celerity_resource('phabricator-nav-view-css'); require_celerity_resource('phabricator-nav-view-css');
require_celerity_resource('phui-profile-menu-css');
$nav_classes = array(); $nav_classes = array();
$nav_classes[] = 'phabricator-nav'; $nav_classes[] = 'phabricator-nav';
if ($this->getIsProfileMenu()) {
require_celerity_resource('phui-profile-menu-css');
// No class, we're going to put it on the shell instead.
} else {
$nav_classes[] = 'phabricator-basic-nav';
}
$nav_id = null; $nav_id = null;
$drag_id = null; $drag_id = null;
$content_id = celerity_generate_unique_node_id(); $content_id = celerity_generate_unique_node_id();
@ -260,6 +254,8 @@ final class AphrontSideNavFilterView extends AphrontView {
if ($this->flexible) { if ($this->flexible) {
if (!$this->collapsed) { if (!$this->collapsed) {
$nav_classes[] = 'has-drag-nav'; $nav_classes[] = 'has-drag-nav';
} else {
$nav_classes[] = 'has-closed-nav';
} }
Javelin::initBehavior( Javelin::initBehavior(
@ -284,16 +280,6 @@ final class AphrontSideNavFilterView extends AphrontView {
$nav_classes = array_merge($nav_classes, $this->classes); $nav_classes = array_merge($nav_classes, $this->classes);
$footer = $this->footer;
if ($this->getIsProfileMenu()) {
$internal_footer = $footer;
$external_footer = null;
} else {
$internal_footer = null;
$external_footer = $footer;
}
$menu = phutil_tag( $menu = phutil_tag(
'div', 'div',
array( array(
@ -312,26 +298,28 @@ final class AphrontSideNavFilterView extends AphrontView {
array( array(
$crumbs, $crumbs,
$this->renderChildren(), $this->renderChildren(),
$internal_footer, $this->footer,
)), )),
)); ));
$classes = array();
$classes[] = 'phui-navigation-shell';
if ($this->getIsProfileMenu()) { if ($this->getIsProfileMenu()) {
$shell = phutil_tag( $classes[] = 'phui-profile-menu';
'div',
array(
'class' => 'phui-navigation-shell phui-profile-menu',
),
array(
$menu,
));
} else { } else {
$shell = array( $classes[] = 'phui-basic-nav';
$menu,
$external_footer,
);
} }
$shell = phutil_tag(
'div',
array(
'class' => implode(' ', $classes),
),
array(
$menu,
));
return $shell; return $shell;
} }

View file

@ -204,6 +204,7 @@ final class PHUIObjectBoxView extends AphrontTagView {
->addSigil('reveal-content') ->addSigil('reveal-content')
->setID($hide_action_id) ->setID($hide_action_id)
->setStyle($hide_style) ->setStyle($hide_style)
->setIcon('fa-search')
->setHref($this->showHideHref) ->setHref($this->showHideHref)
->setMetaData( ->setMetaData(
array( array(
@ -216,6 +217,7 @@ final class PHUIObjectBoxView extends AphrontTagView {
->setTag('a') ->setTag('a')
->addSigil('reveal-content') ->addSigil('reveal-content')
->setStyle($show_style) ->setStyle($show_style)
->setIcon('fa-search')
->setHref('#') ->setHref('#')
->setID($show_action_id) ->setID($show_action_id)
->setMetaData( ->setMetaData(

View file

@ -204,7 +204,7 @@ final class PHUIPagerView extends AphrontView {
$rendered_links[] = id(new PHUIButtonView()) $rendered_links[] = id(new PHUIButtonView())
->setTag('a') ->setTag('a')
->setHref($link) ->setHref($link)
->setColor(PHUIButtonView::SIMPLE) ->setColor(PHUIButtonView::GREY)
->addClass('mml') ->addClass('mml')
->addClass($class) ->addClass($class)
->setText($label); ->setText($label);

View file

@ -191,6 +191,10 @@ final class PHUICalendarDayView extends AphrontView {
->addColumn($table_box, 'thirds phui-day-view-column') ->addColumn($table_box, 'thirds phui-day-view-column')
->setFluidLayout(true); ->setFluidLayout(true);
$layout = id(new PHUIBoxView())
->appendChild($layout)
->addClass('phui-calendar-box');
return $layout; return $layout;
} }

View file

@ -183,7 +183,8 @@ final class PHUICalendarMonthView extends AphrontView {
$box = id(new PHUIObjectBoxView()) $box = id(new PHUIObjectBoxView())
->setHeader($this->renderCalendarHeader($this->getDateTime())) ->setHeader($this->renderCalendarHeader($this->getDateTime()))
->appendChild($table) ->appendChild($table)
->setFormErrors($warnings); ->setFormErrors($warnings)
->addClass('phui-calendar-box');
if ($this->error) { if ($this->error) {
$box->setInfoView($this->error); $box->setInfoView($this->error);

View file

@ -6,8 +6,10 @@
cursor: col-resize; cursor: col-resize;
} }
.phabricator-nav-local, .device-desktop .has-closed-nav div.phabricator-nav-local,
.phabricator-nav-drag { .device-desktop .has-closed-nav div.phabricator-nav-drag,
.device .phui-navigation-shell div.phabricator-nav-local,
.device .phui-navigation-shell div.phabricator-nav-drag {
display: none; display: none;
} }
@ -16,27 +18,25 @@
display: block; display: block;
} }
.device .phabricator-side-menu-home .phabricator-nav-local { .device-phone .phabricator-side-menu-home .phabricator-nav-local {
display: block; display: block;
} }
.device-desktop .phabricator-side-menu-home .phabricator-nav-content, /* Home Sidenav */
.device-tablet .phabricator-side-menu-home .phabricator-nav-content { .phui-basic-nav.phui-navigation-shell
margin-left: 205px; .phabricator-side-menu-home .phabricator-nav-local {
padding-top: 16px;
padding-right: 0;
background-color: transparent;
width: 205px;
} }
.phabricator-nav-local { .device-phone .phui-basic-nav.phui-navigation-shell
width: 205px; .phabricator-side-menu-home .phabricator-nav-local {
position: absolute; padding-top: 0;
left: 0; padding-right: 0;
white-space: nowrap; background-color: transparent;
overflow-x: hidden; width: auto;
overflow-y: auto;
margin-top: 8px;
}
.phabricator-side-menu-home .phabricator-nav-local {
margin-top: 16px;
} }
.phabricator-nav-drag { .phabricator-nav-drag {
@ -68,8 +68,10 @@
margin-left: 212px; margin-left: 212px;
} }
.device-desktop .has-local-nav .phabricator-nav-content { .device-desktop .phui-navigation-shell .has-drag-nav .phabricator-nav-local {
margin-left: 205px; width: 205px;
padding: 0;
background: transparent;
} }
.device-phone .phabricator-side-menu-home .phabricator-nav-content { .device-phone .phabricator-side-menu-home .phabricator-nav-content {

View file

@ -91,7 +91,3 @@
.profile-no-badges { .profile-no-badges {
padding: 24px 0; padding: 24px 0;
} }
.project-view-home .phabricator-remarkup .remarkup-code-block pre {
white-space: pre-wrap;
}

View file

@ -0,0 +1,50 @@
/**
* @provides application-search-view-css
*/
.application-search-view {
background-color: #fff;
}
.application-search-view .application-search-results.phui-object-box {
margin: 0;
padding: 0 16px 24px;
}
.application-search-view .application-search-results .phui-profile-header {
padding: 16px 8px;
border-bottom: 1px solid {$thinblueborder};
}
.application-search-results
.phui-profile-header.phui-header-shell .phui-header-header {
font-size: 20px;
}
.device-phone.application-search-view .application-search-results
.phui-profile-header {
padding: 12px 0;
}
.device-phone .application-search-results
.phui-profile-header.phui-header-shell .phui-header-header {
font-size: 16px;
}
.device-phone.application-search-view
.application-search-results.phui-object-box {
padding: 0 12px;
}
.application-search-view .phui-box-border {
border: none;
}
.application-search-pager {
margin: 0 16px 16px 16px;
padding: 8px;
}
.device-phone .application-search-pager {
margin: 12px;
}

View file

@ -51,6 +51,7 @@
overflow: auto; overflow: auto;
padding: 12px; padding: 12px;
border-radius: 3px; border-radius: 3px;
white-space: pre-wrap;
} }
.phabricator-remarkup pre.remarkup-counterexample { .phabricator-remarkup pre.remarkup-counterexample {

View file

@ -1,59 +0,0 @@
/**
* @provides phabricator-side-menu-view-css
*/
.phabricator-basic-nav .phabricator-side-menu .phui-list-item-view {
display: block;
white-space: nowrap;
text-decoration: none;
font-size: 13px;
-webkit-font-smoothing: antialiased;
}
.phabricator-basic-nav .phabricator-side-menu .phui-list-item-href {
display: block;
padding: 6px 8px 6px 24px;
color: {$darkbluetext};
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
}
.phabricator-basic-nav .phabricator-side-menu .phui-list-item-icon {
margin-left: -12px;
text-align: center;
width: 24px;
}
.phabricator-basic-nav .phabricator-side-menu .phui-list-item-selected {
background-color: rgba({$alphablack},.05);
border-left: 4px solid {$sky};
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
font-weight: bold;
}
.device-desktop .phabricator-basic-nav .phabricator-side-menu
.phui-list-item-selected
a.phui-list-item-href:hover {
background-color: rgba({$alphablack},.05);
}
.phabricator-basic-nav .phabricator-side-menu .phui-list-item-selected
.phui-list-item-href {
padding-left: 20px;
}
.phabricator-basic-nav .phabricator-side-menu .phui-list-item-type-label {
padding: 6px 8px 4px 12px;
color: {$darkbluetext};
text-transform: uppercase;
font-size: 12px;
font-weight: bold;
border-style: solid;
}
.device-desktop .phabricator-basic-nav .phabricator-side-menu
a.phui-list-item-href:hover {
text-decoration: none;
background-color: rgba({$alphablack},.07);
}

View file

@ -8,6 +8,13 @@
background: rgba(255, 255, 255, 0.75); background: rgba(255, 255, 255, 0.75);
} }
.application-search-view div.phui-calendar-box {
border-left: 1px solid {$thinblueborder};
border-right: 1px solid {$thinblueborder};
border-bottom: 1px solid {$lightblueborder};
border-radius: 0;
}
.phui-calendar-list a { .phui-calendar-list a {
color: {$greytext}; color: {$greytext};
} }

View file

@ -0,0 +1,110 @@
/**
* @provides phui-basic-nav-view-css
*/
.device-desktop .phui-navigation-shell,
.phabricator-home.device .phui-navigation-shell {
display: table;
width: 100%;
height: calc(100vh - {$menu.main.height});
}
.device-desktop .phui-navigation-shell .phabricator-nav,
.phabricator-home.device .phui-navigation-shell .phabricator-nav {
display: table-row;
}
.device-desktop .phui-navigation-shell .phabricator-nav-local,
.phabricator-home.device .phui-navigation-shell .phabricator-nav-local {
display: table-cell;
position: relative;
vertical-align: top;
width: {$menu.profile.width};
max-width: {$menu.profile.width};
margin-top: 0;
overflow: hidden;
}
.phui-basic-nav.phui-navigation-shell .phabricator-nav-local {
width: 205px;
padding-top: 4px;
padding-right: 8px;
}
.phui-basic-nav .phabricator-side-menu {
background-color: {$page.sidenav};
}
.phui-two-column-view .phui-basic-nav.phui-navigation-shell
.phabricator-nav-local {
width: {$menu.profile.width};
max-width: {$menu.profile.width};
padding-right: 0;
padding-top: 0;
}
.phui-two-column-view .phui-basic-nav .phabricator-side-menu {
background-color: #fff;
}
.phui-basic-nav .phabricator-side-menu {
background-color: {$page.sidenav};
}
.phui-basic-nav .phabricator-side-menu .phui-list-item-view {
display: block;
white-space: nowrap;
text-decoration: none;
font-size: 13px;
-webkit-font-smoothing: antialiased;
}
.phui-basic-nav .phabricator-side-menu .phui-list-item-href {
display: block;
padding: 6px 8px 6px 24px;
color: {$darkbluetext};
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
overflow: hidden;
text-overflow: ellipsis
}
.phui-basic-nav .phabricator-side-menu .phui-list-item-icon {
margin-left: -12px;
text-align: center;
width: 24px;
}
.phui-basic-nav .phabricator-side-menu .phui-list-item-selected {
background-color: rgba({$alphablack},.05);
border-left: 4px solid {$sky};
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
font-weight: bold;
}
.device-desktop .phui-basic-nav .phabricator-side-menu
.phui-list-item-selected
a.phui-list-item-href:hover {
background-color: rgba({$alphablack},.05);
}
.phui-basic-nav .phabricator-side-menu .phui-list-item-selected
.phui-list-item-href {
padding-left: 20px;
}
.phui-basic-nav .phabricator-side-menu .phui-list-item-type-label {
padding: 6px 8px 4px 12px;
color: {$darkbluetext};
text-transform: uppercase;
font-size: 12px;
font-weight: bold;
border-style: solid;
}
.device-desktop .phui-basic-nav .phabricator-side-menu
a.phui-list-item-href:hover {
text-decoration: none;
background-color: rgba({$alphablack},.07);
}

View file

@ -5,11 +5,12 @@
.phui-crumbs-view { .phui-crumbs-view {
overflow: hidden; overflow: hidden;
vertical-align: top; vertical-align: top;
padding: 0 20px 0 28px; padding: 0 12px 0 20px;
/* TODO: Position this over the slider for Differential's file tree view. /* TODO: Position this over the slider for Differential's file tree view.
Remove this once that gets sorted out. */ Remove this once that gets sorted out. */
position: relative; position: relative;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
background-color: {$page.background};
} }
.phui-crumbs-view, .phui-crumbs-view,

View file

@ -37,7 +37,7 @@
} }
.device-phone .phui-document-view.phui-document-view-pro { .device-phone .phui-document-view.phui-document-view-pro {
padding: 0 8px; padding: 0 12px;
margin: 0 auto; margin: 0 auto;
} }
@ -132,6 +132,11 @@ a.button.phui-document-toc {
color: #000; color: #000;
} }
.device-phone .phui-document-view.phui-document-view-pro .phui-header-tall
.phui-header-header {
font-size: 18px;
}
.device-phone .phui-document-view-pro .phui-header-subheader { .device-phone .phui-document-view-pro .phui-header-subheader {
display: block; display: block;
padding: 8px 0 0 0; padding: 8px 0 0 0;

View file

@ -323,6 +323,7 @@ body .phui-header-shell.phui-bleed-header
.phui-profile-header.phui-header-shell .phui-header-header { .phui-profile-header.phui-header-shell .phui-header-header {
font-family: 'Aleo', {$fontfamily}; font-family: 'Aleo', {$fontfamily};
font-size: 24px; font-size: 24px;
color: #000;
} }
.phui-profile-header .phui-header-col3 { .phui-profile-header .phui-header-col3 {

View file

@ -2,26 +2,6 @@
* @provides phui-profile-menu-css * @provides phui-profile-menu-css
*/ */
.device-desktop .phui-navigation-shell.phui-profile-menu {
display: table;
width: 100%;
height: calc(100vh - {$menu.main.height});
}
.device-desktop .phui-profile-menu .phabricator-nav {
display: table-row;
}
.device-desktop .phui-profile-menu .phabricator-nav-local {
display: table-cell;
position: relative;
vertical-align: top;
width: {$menu.profile.width};
max-width: {$menu.profile.width};
margin-top: 0;
overflow: hidden;
}
.device-desktop .phui-profile-menu-collapsed .phabricator-nav-local { .device-desktop .phui-profile-menu-collapsed .phabricator-nav-local {
width: {$menu.profile.width.collapsed}; width: {$menu.profile.width.collapsed};
max-width: {$menu.profile.width.collapsed}; max-width: {$menu.profile.width.collapsed};
@ -32,9 +12,12 @@
margin-left: 0; margin-left: 0;
} }
.phui-profile-menu .phui-basic-nav {
width: 205px;
}
.phui-profile-menu .phabricator-side-menu { .phui-profile-menu .phabricator-side-menu {
background: #525867; background: #525867;
box-shadow: inset -2px 0 2px rgba({$alphablack}, 0.150);
width: 240px; width: 240px;
} }

View file

@ -108,6 +108,7 @@ JX.behavior('phabricator-nav', function(config) {
collapsed = !collapsed; collapsed = !collapsed;
JX.DOM.alterClass(main, 'has-local-nav', !collapsed); JX.DOM.alterClass(main, 'has-local-nav', !collapsed);
JX.DOM.alterClass(main, 'has-drag-nav', !collapsed); JX.DOM.alterClass(main, 'has-drag-nav', !collapsed);
JX.DOM.alterClass(main, 'has-closed-nav', collapsed);
resetdrag(); resetdrag();
new JX.Request('/settings/adjust/', JX.bag) new JX.Request('/settings/adjust/', JX.bag)
.setData({ key : 'nav-collapsed', value : (collapsed ? 1 : 0) }) .setData({ key : 'nav-collapsed', value : (collapsed ? 1 : 0) })