mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-25 08:12:40 +01:00
(stable) Promote 2016 Week 8
This commit is contained in:
commit
ad53db0979
155 changed files with 2077 additions and 945 deletions
|
@ -7,8 +7,8 @@
|
|||
*/
|
||||
return array(
|
||||
'names' => array(
|
||||
'core.pkg.css' => 'b59766ad',
|
||||
'core.pkg.js' => 'd7daa6d8',
|
||||
'core.pkg.css' => '7935f211',
|
||||
'core.pkg.js' => '7d8faf57',
|
||||
'darkconsole.pkg.js' => 'e7393ebb',
|
||||
'differential.pkg.css' => '2de124c9',
|
||||
'differential.pkg.js' => 'd0cd0df6',
|
||||
|
@ -17,19 +17,19 @@ return array(
|
|||
'maniphest.pkg.css' => '4845691a',
|
||||
'maniphest.pkg.js' => '949a7498',
|
||||
'rsrc/css/aphront/aphront-bars.css' => '231ac33c',
|
||||
'rsrc/css/aphront/dark-console.css' => '6378ef3d',
|
||||
'rsrc/css/aphront/dark-console.css' => 'f54bf286',
|
||||
'rsrc/css/aphront/dialog-view.css' => 'b4334e08',
|
||||
'rsrc/css/aphront/lightbox-attachment.css' => '7acac05d',
|
||||
'rsrc/css/aphront/list-filter-view.css' => '5d6f0526',
|
||||
'rsrc/css/aphront/multi-column.css' => 'fd18389d',
|
||||
'rsrc/css/aphront/notification.css' => '9c279160',
|
||||
'rsrc/css/aphront/notification.css' => '7f684b62',
|
||||
'rsrc/css/aphront/panel-view.css' => '8427b78d',
|
||||
'rsrc/css/aphront/phabricator-nav-view.css' => 'a24cb589',
|
||||
'rsrc/css/aphront/phabricator-nav-view.css' => 'ac79a758',
|
||||
'rsrc/css/aphront/table-view.css' => '6d01d468',
|
||||
'rsrc/css/aphront/tokenizer.css' => '056da01b',
|
||||
'rsrc/css/aphront/tooltip.css' => '7672b60f',
|
||||
'rsrc/css/aphront/tooltip.css' => '1a07aea8',
|
||||
'rsrc/css/aphront/typeahead-browse.css' => 'd8581d2c',
|
||||
'rsrc/css/aphront/typeahead.css' => '0e403212',
|
||||
'rsrc/css/aphront/typeahead.css' => 'd4f16145',
|
||||
'rsrc/css/application/almanac/almanac.css' => 'dbb9b3af',
|
||||
'rsrc/css/application/auth/auth.css' => '0877ed6e',
|
||||
'rsrc/css/application/base/main-menu-view.css' => 'd00a795a',
|
||||
|
@ -65,10 +65,10 @@ return array(
|
|||
'rsrc/css/application/differential/revision-list.css' => 'f3c47d33',
|
||||
'rsrc/css/application/differential/table-of-contents.css' => 'ae4b7a55',
|
||||
'rsrc/css/application/diffusion/diffusion-icons.css' => '2941baf1',
|
||||
'rsrc/css/application/diffusion/diffusion-readme.css' => '2106ea08',
|
||||
'rsrc/css/application/diffusion/diffusion-readme.css' => '356a4f3c',
|
||||
'rsrc/css/application/diffusion/diffusion-source.css' => '075ba788',
|
||||
'rsrc/css/application/feed/feed.css' => 'ecd4ec57',
|
||||
'rsrc/css/application/files/global-drag-and-drop.css' => '697324ad',
|
||||
'rsrc/css/application/files/global-drag-and-drop.css' => '5c1b47c2',
|
||||
'rsrc/css/application/flag/flag.css' => '5337623f',
|
||||
'rsrc/css/application/harbormaster/harbormaster.css' => 'b0758ca5',
|
||||
'rsrc/css/application/herald/herald-test.css' => 'a52e323e',
|
||||
|
@ -81,10 +81,10 @@ return array(
|
|||
'rsrc/css/application/owners/owners-path-editor.css' => '2f00933b',
|
||||
'rsrc/css/application/paste/paste.css' => 'a5157c48',
|
||||
'rsrc/css/application/people/people-profile.css' => '2473d929',
|
||||
'rsrc/css/application/phame/phame.css' => '1dbbacf9',
|
||||
'rsrc/css/application/phame/phame.css' => '4ca6fd6c',
|
||||
'rsrc/css/application/pholio/pholio-edit.css' => '3ad9d1ee',
|
||||
'rsrc/css/application/pholio/pholio-inline-comments.css' => '8e545e49',
|
||||
'rsrc/css/application/pholio/pholio.css' => '95174bdd',
|
||||
'rsrc/css/application/pholio/pholio.css' => 'ca89d380',
|
||||
'rsrc/css/application/phortune/phortune-credit-card-form.css' => '8391eb02',
|
||||
'rsrc/css/application/phortune/phortune.css' => '9149f103',
|
||||
'rsrc/css/application/phrequent/phrequent.css' => 'ffc185ad',
|
||||
|
@ -92,9 +92,9 @@ return array(
|
|||
'rsrc/css/application/policy/policy-edit.css' => '815c66f7',
|
||||
'rsrc/css/application/policy/policy-transaction-detail.css' => '82100a43',
|
||||
'rsrc/css/application/policy/policy.css' => '957ea14c',
|
||||
'rsrc/css/application/ponder/ponder-view.css' => '7b0df4da',
|
||||
'rsrc/css/application/ponder/ponder-view.css' => 'b40dc156',
|
||||
'rsrc/css/application/project/project-card-view.css' => '9418c97d',
|
||||
'rsrc/css/application/project/project-view.css' => '4693497c',
|
||||
'rsrc/css/application/project/project-view.css' => '83bb6654',
|
||||
'rsrc/css/application/releeph/releeph-core.css' => '9b3c5733',
|
||||
'rsrc/css/application/releeph/releeph-preview-branch.css' => 'b7a6f4a5',
|
||||
'rsrc/css/application/releeph/releeph-request-differential-create-dialog.css' => '8d8b92cd',
|
||||
|
@ -104,7 +104,7 @@ return array(
|
|||
'rsrc/css/application/tokens/tokens.css' => '3d0f239e',
|
||||
'rsrc/css/application/uiexample/example.css' => '528b19de',
|
||||
'rsrc/css/core/core.css' => '5b3563c8',
|
||||
'rsrc/css/core/remarkup.css' => 'e1c8b32f',
|
||||
'rsrc/css/core/remarkup.css' => 'fc228f08',
|
||||
'rsrc/css/core/syntax.css' => '9fd11da8',
|
||||
'rsrc/css/core/z-index.css' => '5b6fcf3f',
|
||||
'rsrc/css/diviner/diviner-shared.css' => 'aa3656aa',
|
||||
|
@ -123,30 +123,30 @@ return array(
|
|||
'rsrc/css/phui/phui-action-panel.css' => '91c7b835',
|
||||
'rsrc/css/phui/phui-badge.css' => 'f25c3476',
|
||||
'rsrc/css/phui/phui-big-info-view.css' => 'bd903741',
|
||||
'rsrc/css/phui/phui-box.css' => '6e8ac7fd',
|
||||
'rsrc/css/phui/phui-button.css' => 'd6ac72db',
|
||||
'rsrc/css/phui/phui-box.css' => 'dd1294d3',
|
||||
'rsrc/css/phui/phui-button.css' => 'edf464e9',
|
||||
'rsrc/css/phui/phui-chart.css' => '6bf6f78e',
|
||||
'rsrc/css/phui/phui-crumbs-view.css' => '79d536e5',
|
||||
'rsrc/css/phui/phui-document-pro.css' => '8799acf7',
|
||||
'rsrc/css/phui/phui-document-pro.css' => 'a8872307',
|
||||
'rsrc/css/phui/phui-document-summary.css' => '9ca48bdf',
|
||||
'rsrc/css/phui/phui-document.css' => '9c71d2bf',
|
||||
'rsrc/css/phui/phui-feed-story.css' => '04aec08f',
|
||||
'rsrc/css/phui/phui-fontkit.css' => '9cda225e',
|
||||
'rsrc/css/phui/phui-form-view.css' => '4a1a0f5e',
|
||||
'rsrc/css/phui/phui-form.css' => '0b98e572',
|
||||
'rsrc/css/phui/phui-header-view.css' => 'd53cc835',
|
||||
'rsrc/css/phui/phui-form.css' => 'aac1d51d',
|
||||
'rsrc/css/phui/phui-header-view.css' => '50c5cb6a',
|
||||
'rsrc/css/phui/phui-hovercard.css' => 'de1a2119',
|
||||
'rsrc/css/phui/phui-icon-set-selector.css' => '1ab67aad',
|
||||
'rsrc/css/phui/phui-icon.css' => '3f33ab57',
|
||||
'rsrc/css/phui/phui-image-mask.css' => '5a8b09c8',
|
||||
'rsrc/css/phui/phui-image-mask.css' => 'a8498f9c',
|
||||
'rsrc/css/phui/phui-info-panel.css' => '27ea50a1',
|
||||
'rsrc/css/phui/phui-info-view.css' => '6d7c3509',
|
||||
'rsrc/css/phui/phui-list.css' => '9da2aa00',
|
||||
'rsrc/css/phui/phui-object-box.css' => '407eaf5a',
|
||||
'rsrc/css/phui/phui-object-item-list-view.css' => 'be31c3a7',
|
||||
'rsrc/css/phui/phui-object-item-list-view.css' => '18b2ce8e',
|
||||
'rsrc/css/phui/phui-pager.css' => 'bea33d23',
|
||||
'rsrc/css/phui/phui-pinboard-view.css' => '2495140e',
|
||||
'rsrc/css/phui/phui-profile-menu.css' => 'f709256c',
|
||||
'rsrc/css/phui/phui-profile-menu.css' => '7e92a89a',
|
||||
'rsrc/css/phui/phui-property-list-view.css' => '27b2849e',
|
||||
'rsrc/css/phui/phui-remarkup-preview.css' => '1a8f2591',
|
||||
'rsrc/css/phui/phui-segment-bar-view.css' => '46342871',
|
||||
|
@ -154,10 +154,11 @@ return array(
|
|||
'rsrc/css/phui/phui-status.css' => '888cedb8',
|
||||
'rsrc/css/phui/phui-tag-view.css' => '9d5d4400',
|
||||
'rsrc/css/phui/phui-timeline-view.css' => '2efceff8',
|
||||
'rsrc/css/phui/phui-two-column-view.css' => 'c75bfc5b',
|
||||
'rsrc/css/phui/workboards/phui-workboard.css' => 'e9e56029',
|
||||
'rsrc/css/phui/phui-two-column-view.css' => '0763177e',
|
||||
'rsrc/css/phui/workboards/phui-workboard-color.css' => 'ac6fe6a7',
|
||||
'rsrc/css/phui/workboards/phui-workboard.css' => 'e6d89647',
|
||||
'rsrc/css/phui/workboards/phui-workcard.css' => '3646fb96',
|
||||
'rsrc/css/phui/workboards/phui-workpanel.css' => 'a78c0661',
|
||||
'rsrc/css/phui/workboards/phui-workpanel.css' => '92197373',
|
||||
'rsrc/css/sprite-login.css' => '60e8560e',
|
||||
'rsrc/css/sprite-menu.css' => '9dd65b92',
|
||||
'rsrc/css/sprite-tokens.css' => '4f399012',
|
||||
|
@ -461,7 +462,7 @@ return array(
|
|||
'rsrc/js/core/Notification.js' => 'ccf1cbf8',
|
||||
'rsrc/js/core/Prefab.js' => 'e67df814',
|
||||
'rsrc/js/core/ShapedRequest.js' => '7cbe244b',
|
||||
'rsrc/js/core/TextAreaUtils.js' => '9e54692d',
|
||||
'rsrc/js/core/TextAreaUtils.js' => '5813016a',
|
||||
'rsrc/js/core/Title.js' => 'df5e11d2',
|
||||
'rsrc/js/core/ToolTip.js' => '6323f942',
|
||||
'rsrc/js/core/behavior-active-nav.js' => 'e379b58e',
|
||||
|
@ -500,7 +501,7 @@ return array(
|
|||
'rsrc/js/core/behavior-time-typeahead.js' => 'f80d6bf0',
|
||||
'rsrc/js/core/behavior-toggle-class.js' => '5d7c9f33',
|
||||
'rsrc/js/core/behavior-tokenizer.js' => 'b3a4b884',
|
||||
'rsrc/js/core/behavior-tooltip.js' => '3ee3408b',
|
||||
'rsrc/js/core/behavior-tooltip.js' => '42fcb747',
|
||||
'rsrc/js/core/behavior-watch-anchor.js' => '9f36c42d',
|
||||
'rsrc/js/core/behavior-workflow.js' => '0a3f3021',
|
||||
'rsrc/js/core/phtize.js' => 'd254d646',
|
||||
|
@ -517,15 +518,15 @@ return array(
|
|||
'symbols' => array(
|
||||
'almanac-css' => 'dbb9b3af',
|
||||
'aphront-bars' => '231ac33c',
|
||||
'aphront-dark-console-css' => '6378ef3d',
|
||||
'aphront-dark-console-css' => 'f54bf286',
|
||||
'aphront-dialog-view-css' => 'b4334e08',
|
||||
'aphront-list-filter-view-css' => '5d6f0526',
|
||||
'aphront-multi-column-view-css' => 'fd18389d',
|
||||
'aphront-panel-view-css' => '8427b78d',
|
||||
'aphront-table-view-css' => '6d01d468',
|
||||
'aphront-tokenizer-control-css' => '056da01b',
|
||||
'aphront-tooltip-css' => '7672b60f',
|
||||
'aphront-typeahead-control-css' => '0e403212',
|
||||
'aphront-tooltip-css' => '1a07aea8',
|
||||
'aphront-typeahead-control-css' => 'd4f16145',
|
||||
'auth-css' => '0877ed6e',
|
||||
'bulk-job-css' => 'df9c1d4a',
|
||||
'changeset-view-manager' => 'a2828756',
|
||||
|
@ -550,13 +551,13 @@ return array(
|
|||
'differential-revision-list-css' => 'f3c47d33',
|
||||
'differential-table-of-contents-css' => 'ae4b7a55',
|
||||
'diffusion-icons-css' => '2941baf1',
|
||||
'diffusion-readme-css' => '2106ea08',
|
||||
'diffusion-readme-css' => '356a4f3c',
|
||||
'diffusion-source-css' => '075ba788',
|
||||
'diviner-shared-css' => 'aa3656aa',
|
||||
'font-aleo' => '8bdb2835',
|
||||
'font-fontawesome' => 'c43323c5',
|
||||
'font-lato' => 'c7ccd872',
|
||||
'global-drag-and-drop-css' => '697324ad',
|
||||
'global-drag-and-drop-css' => '5c1b47c2',
|
||||
'harbormaster-css' => 'b0758ca5',
|
||||
'herald-css' => '826075fa',
|
||||
'herald-rule-editor' => '746ca158',
|
||||
|
@ -647,7 +648,7 @@ return array(
|
|||
'javelin-behavior-phabricator-reveal-content' => '60821bc7',
|
||||
'javelin-behavior-phabricator-search-typeahead' => '06c32383',
|
||||
'javelin-behavior-phabricator-show-older-transactions' => 'dbbf48b6',
|
||||
'javelin-behavior-phabricator-tooltips' => '3ee3408b',
|
||||
'javelin-behavior-phabricator-tooltips' => '42fcb747',
|
||||
'javelin-behavior-phabricator-transaction-comment-form' => 'b23b49e6',
|
||||
'javelin-behavior-phabricator-transaction-list' => '13c739ea',
|
||||
'javelin-behavior-phabricator-watch-anchor' => '9f36c42d',
|
||||
|
@ -760,21 +761,21 @@ return array(
|
|||
'phabricator-keyboard-shortcut' => '1ae869f2',
|
||||
'phabricator-keyboard-shortcut-manager' => 'c1700f6f',
|
||||
'phabricator-main-menu-view' => 'd00a795a',
|
||||
'phabricator-nav-view-css' => 'a24cb589',
|
||||
'phabricator-nav-view-css' => 'ac79a758',
|
||||
'phabricator-notification' => 'ccf1cbf8',
|
||||
'phabricator-notification-css' => '9c279160',
|
||||
'phabricator-notification-css' => '7f684b62',
|
||||
'phabricator-notification-menu-css' => 'f31c0bde',
|
||||
'phabricator-object-selector-css' => '85ee8ce6',
|
||||
'phabricator-phtize' => 'd254d646',
|
||||
'phabricator-prefab' => 'e67df814',
|
||||
'phabricator-remarkup-css' => 'e1c8b32f',
|
||||
'phabricator-remarkup-css' => 'fc228f08',
|
||||
'phabricator-search-results-css' => '7dea472c',
|
||||
'phabricator-shaped-request' => '7cbe244b',
|
||||
'phabricator-side-menu-view-css' => '3a3d9f41',
|
||||
'phabricator-slowvote-css' => 'da0afb1b',
|
||||
'phabricator-source-code-view-css' => 'cbeef983',
|
||||
'phabricator-standard-page-view' => 'e709f6d0',
|
||||
'phabricator-textareautils' => '9e54692d',
|
||||
'phabricator-textareautils' => '5813016a',
|
||||
'phabricator-title' => 'df5e11d2',
|
||||
'phabricator-tooltip' => '6323f942',
|
||||
'phabricator-ui-example-css' => '528b19de',
|
||||
|
@ -789,8 +790,8 @@ return array(
|
|||
'phabricator-uiexample-reactor-sendclass' => '1def2711',
|
||||
'phabricator-uiexample-reactor-sendproperties' => 'b1f0ccee',
|
||||
'phabricator-zindex-css' => '5b6fcf3f',
|
||||
'phame-css' => '1dbbacf9',
|
||||
'pholio-css' => '95174bdd',
|
||||
'phame-css' => '4ca6fd6c',
|
||||
'pholio-css' => 'ca89d380',
|
||||
'pholio-edit-css' => '3ad9d1ee',
|
||||
'pholio-inline-comments-css' => '8e545e49',
|
||||
'phortune-credit-card-form' => '2290aeef',
|
||||
|
@ -801,8 +802,8 @@ return array(
|
|||
'phui-action-panel-css' => '91c7b835',
|
||||
'phui-badge-view-css' => 'f25c3476',
|
||||
'phui-big-info-view-css' => 'bd903741',
|
||||
'phui-box-css' => '6e8ac7fd',
|
||||
'phui-button-css' => 'd6ac72db',
|
||||
'phui-box-css' => 'dd1294d3',
|
||||
'phui-button-css' => 'edf464e9',
|
||||
'phui-calendar-css' => 'ccabe893',
|
||||
'phui-calendar-day-css' => 'd1cf6f93',
|
||||
'phui-calendar-list-css' => 'c1c7f338',
|
||||
|
@ -811,27 +812,27 @@ return array(
|
|||
'phui-crumbs-view-css' => '79d536e5',
|
||||
'phui-document-summary-view-css' => '9ca48bdf',
|
||||
'phui-document-view-css' => '9c71d2bf',
|
||||
'phui-document-view-pro-css' => '8799acf7',
|
||||
'phui-document-view-pro-css' => 'a8872307',
|
||||
'phui-feed-story-css' => '04aec08f',
|
||||
'phui-font-icon-base-css' => 'ecbbb4c2',
|
||||
'phui-fontkit-css' => '9cda225e',
|
||||
'phui-form-css' => '0b98e572',
|
||||
'phui-form-css' => 'aac1d51d',
|
||||
'phui-form-view-css' => '4a1a0f5e',
|
||||
'phui-header-view-css' => 'd53cc835',
|
||||
'phui-header-view-css' => '50c5cb6a',
|
||||
'phui-hovercard' => '1bd28176',
|
||||
'phui-hovercard-view-css' => 'de1a2119',
|
||||
'phui-icon-set-selector-css' => '1ab67aad',
|
||||
'phui-icon-view-css' => '3f33ab57',
|
||||
'phui-image-mask-css' => '5a8b09c8',
|
||||
'phui-image-mask-css' => 'a8498f9c',
|
||||
'phui-info-panel-css' => '27ea50a1',
|
||||
'phui-info-view-css' => '6d7c3509',
|
||||
'phui-inline-comment-view-css' => '0fdb3667',
|
||||
'phui-list-view-css' => '9da2aa00',
|
||||
'phui-object-box-css' => '407eaf5a',
|
||||
'phui-object-item-list-view-css' => 'be31c3a7',
|
||||
'phui-object-item-list-view-css' => '18b2ce8e',
|
||||
'phui-pager-css' => 'bea33d23',
|
||||
'phui-pinboard-view-css' => '2495140e',
|
||||
'phui-profile-menu-css' => 'f709256c',
|
||||
'phui-profile-menu-css' => '7e92a89a',
|
||||
'phui-property-list-view-css' => '27b2849e',
|
||||
'phui-remarkup-preview-css' => '1a8f2591',
|
||||
'phui-segment-bar-view-css' => '46342871',
|
||||
|
@ -840,10 +841,11 @@ return array(
|
|||
'phui-tag-view-css' => '9d5d4400',
|
||||
'phui-theme-css' => 'ab7b848c',
|
||||
'phui-timeline-view-css' => '2efceff8',
|
||||
'phui-two-column-view-css' => 'c75bfc5b',
|
||||
'phui-workboard-view-css' => 'e9e56029',
|
||||
'phui-two-column-view-css' => '0763177e',
|
||||
'phui-workboard-color-css' => 'ac6fe6a7',
|
||||
'phui-workboard-view-css' => 'e6d89647',
|
||||
'phui-workcard-view-css' => '3646fb96',
|
||||
'phui-workpanel-view-css' => 'a78c0661',
|
||||
'phui-workpanel-view-css' => '92197373',
|
||||
'phuix-action-list-view' => 'b5c256b8',
|
||||
'phuix-action-view' => '8cf6d262',
|
||||
'phuix-autocomplete' => '9196fb06',
|
||||
|
@ -853,9 +855,9 @@ return array(
|
|||
'policy-css' => '957ea14c',
|
||||
'policy-edit-css' => '815c66f7',
|
||||
'policy-transaction-detail-css' => '82100a43',
|
||||
'ponder-view-css' => '7b0df4da',
|
||||
'ponder-view-css' => 'b40dc156',
|
||||
'project-card-view-css' => '9418c97d',
|
||||
'project-view-css' => '4693497c',
|
||||
'project-view-css' => '83bb6654',
|
||||
'releeph-core' => '9b3c5733',
|
||||
'releeph-preview-branch' => 'b7a6f4a5',
|
||||
'releeph-request-differential-create-dialog' => '8d8b92cd',
|
||||
|
@ -1117,12 +1119,6 @@ return array(
|
|||
'javelin-util',
|
||||
'javelin-uri',
|
||||
),
|
||||
'3ee3408b' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-behavior-device',
|
||||
'javelin-stratcom',
|
||||
'phabricator-tooltip',
|
||||
),
|
||||
'3f5d6dbf' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
|
@ -1138,6 +1134,12 @@ return array(
|
|||
'javelin-dom',
|
||||
'javelin-request',
|
||||
),
|
||||
'42fcb747' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-behavior-device',
|
||||
'javelin-stratcom',
|
||||
'phabricator-tooltip',
|
||||
),
|
||||
'44959b73' => array(
|
||||
'javelin-util',
|
||||
'javelin-uri',
|
||||
|
@ -1273,6 +1275,11 @@ return array(
|
|||
'javelin-request',
|
||||
'javelin-util',
|
||||
),
|
||||
'5813016a' => array(
|
||||
'javelin-install',
|
||||
'javelin-dom',
|
||||
'javelin-vector',
|
||||
),
|
||||
'59a7976a' => array(
|
||||
'javelin-install',
|
||||
'javelin-dom',
|
||||
|
@ -1573,6 +1580,9 @@ return array(
|
|||
'phuix-icon-view',
|
||||
'phabricator-prefab',
|
||||
),
|
||||
92197373 => array(
|
||||
'phui-workcard-view-css',
|
||||
),
|
||||
'93d0c9e3' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-stratcom',
|
||||
|
@ -1616,11 +1626,6 @@ return array(
|
|||
'phabricator-phtize',
|
||||
'changeset-view-manager',
|
||||
),
|
||||
'9e54692d' => array(
|
||||
'javelin-install',
|
||||
'javelin-dom',
|
||||
'javelin-vector',
|
||||
),
|
||||
'9f36c42d' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-stratcom',
|
||||
|
@ -1659,9 +1664,6 @@ return array(
|
|||
'javelin-install',
|
||||
'javelin-dom',
|
||||
),
|
||||
'a78c0661' => array(
|
||||
'phui-workcard-view-css',
|
||||
),
|
||||
'a80d0378' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-stratcom',
|
||||
|
|
2
resources/sql/autopatches/20160215.owners.policy.1.sql
Normal file
2
resources/sql/autopatches/20160215.owners.policy.1.sql
Normal file
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE {$NAMESPACE}_owners.owners_package
|
||||
ADD viewPolicy VARBINARY(64) NOT NULL;
|
2
resources/sql/autopatches/20160215.owners.policy.2.sql
Normal file
2
resources/sql/autopatches/20160215.owners.policy.2.sql
Normal file
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE {$NAMESPACE}_owners.owners_package
|
||||
ADD editPolicy VARBINARY(64) NOT NULL;
|
2
resources/sql/autopatches/20160215.owners.policy.3.sql
Normal file
2
resources/sql/autopatches/20160215.owners.policy.3.sql
Normal file
|
@ -0,0 +1,2 @@
|
|||
UPDATE {$NAMESPACE}_owners.owners_package
|
||||
SET viewPolicy = 'users' WHERE viewPolicy = '';
|
2
resources/sql/autopatches/20160215.owners.policy.4.sql
Normal file
2
resources/sql/autopatches/20160215.owners.policy.4.sql
Normal file
|
@ -0,0 +1,2 @@
|
|||
UPDATE {$NAMESPACE}_owners.owners_package
|
||||
SET editPolicy = 'users' WHERE editPolicy = '';
|
4
resources/sql/autopatches/20160218.callsigns.1.sql
Normal file
4
resources/sql/autopatches/20160218.callsigns.1.sql
Normal file
|
@ -0,0 +1,4 @@
|
|||
/* Make callsigns nullable, and thus optional. */
|
||||
|
||||
ALTER TABLE {$NAMESPACE}_repository.repository
|
||||
CHANGE callsign callsign VARCHAR(32) COLLATE {$COLLATE_SORT};
|
|
@ -32,14 +32,14 @@ $root = dirname(dirname(dirname(__FILE__)));
|
|||
require_once $root.'/scripts/__init_script__.php';
|
||||
|
||||
if ($argc < 2) {
|
||||
throw new Exception(pht('usage: commit-hook <callsign>'));
|
||||
throw new Exception(pht('usage: commit-hook <repository>'));
|
||||
}
|
||||
|
||||
$engine = new DiffusionCommitHookEngine();
|
||||
|
||||
$repository = id(new PhabricatorRepositoryQuery())
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->withCallsigns(array($argv[1]))
|
||||
->withIdentifiers(array($argv[1]))
|
||||
->needProjectPHIDs(true)
|
||||
->executeOne();
|
||||
|
||||
|
@ -62,8 +62,9 @@ if ($repository->isGit() || $repository->isHg()) {
|
|||
if (!strlen($username)) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Usage: %s should be defined!',
|
||||
DiffusionCommitHookEngine::ENV_USER));
|
||||
'No Direct Pushes: You are pushing directly to a repository hosted '.
|
||||
'by Phabricator. This will not work. See "No Direct Pushes" in the '.
|
||||
'documentation for more information.'));
|
||||
}
|
||||
|
||||
if ($repository->isHg()) {
|
||||
|
@ -77,7 +78,7 @@ if ($repository->isGit() || $repository->isHg()) {
|
|||
// specify the correct user; read this user out of the commit log.
|
||||
|
||||
if ($argc < 4) {
|
||||
throw new Exception(pht('usage: commit-hook <callsign> <repo> <txn>'));
|
||||
throw new Exception(pht('usage: commit-hook <repository> <repo> <txn>'));
|
||||
}
|
||||
|
||||
$svn_repo = $argv[2];
|
||||
|
|
|
@ -6,7 +6,7 @@ require_once $root.'/scripts/__init_script__.php';
|
|||
|
||||
$args = new PhutilArgumentParser($argv);
|
||||
$args->setSynopsis(<<<EOSYNOPSIS
|
||||
**clear_repository_symbols.php** [__options__] __callsign__
|
||||
**clear_repository_symbols.php** [__options__] __repository__
|
||||
|
||||
Clear repository symbols.
|
||||
EOSYNOPSIS
|
||||
|
@ -15,24 +15,26 @@ $args->parseStandardArguments();
|
|||
$args->parse(
|
||||
array(
|
||||
array(
|
||||
'name' => 'callsign',
|
||||
'name' => 'repository',
|
||||
'wildcard' => true,
|
||||
),
|
||||
));
|
||||
|
||||
$callsigns = $args->getArg('callsign');
|
||||
if (count($callsigns) !== 1) {
|
||||
$identifiers = $args->getArg('repository');
|
||||
if (count($identifiers) !== 1) {
|
||||
$args->printHelpAndExit();
|
||||
}
|
||||
|
||||
$callsign = head($callsigns);
|
||||
$identifier = head($identifiers);
|
||||
$repository = id(new PhabricatorRepositoryQuery())
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->withCallsigns($callsigns)
|
||||
->withIdentifiers($identifiers)
|
||||
->executeOne();
|
||||
|
||||
if (!$repository) {
|
||||
echo pht("Repository '%s' does not exist.", $callsign);
|
||||
echo tsprintf(
|
||||
"%s\n",
|
||||
pht('Repository "%s" does not exist.', $identifier));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ require_once $root.'/scripts/__init_script__.php';
|
|||
|
||||
$args = new PhutilArgumentParser($argv);
|
||||
$args->setSynopsis(<<<EOSYNOPSIS
|
||||
**import_repository_symbols.php** [__options__] __callsign__ < symbols
|
||||
**import_repository_symbols.php** [__options__] __repository__ < symbols
|
||||
|
||||
Import repository symbols (symbols are read from stdin).
|
||||
EOSYNOPSIS
|
||||
|
@ -35,24 +35,26 @@ $args->parse(
|
|||
'be part of a single transaction.'),
|
||||
),
|
||||
array(
|
||||
'name' => 'callsign',
|
||||
'name' => 'repository',
|
||||
'wildcard' => true,
|
||||
),
|
||||
));
|
||||
|
||||
$callsigns = $args->getArg('callsign');
|
||||
if (count($callsigns) !== 1) {
|
||||
$identifiers = $args->getArg('repository');
|
||||
if (count($identifiers) !== 1) {
|
||||
$args->printHelpAndExit();
|
||||
}
|
||||
|
||||
$callsign = head($callsigns);
|
||||
$identifier = head($identifiers);
|
||||
$repository = id(new PhabricatorRepositoryQuery())
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->withCallsigns($callsigns)
|
||||
->withIdentifiers($identifiers)
|
||||
->executeOne();
|
||||
|
||||
if (!$repository) {
|
||||
echo pht("Repository '%s' does not exist.", $callsign);
|
||||
echo tsprintf(
|
||||
"%s\n",
|
||||
pht('Repository "%s" does not exist.', $identifier));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
|
|
@ -689,7 +689,7 @@ phutil_register_library_map(array(
|
|||
'DiffusionPreCommitRefRepositoryHeraldField' => 'applications/diffusion/herald/DiffusionPreCommitRefRepositoryHeraldField.php',
|
||||
'DiffusionPreCommitRefRepositoryProjectsHeraldField' => 'applications/diffusion/herald/DiffusionPreCommitRefRepositoryProjectsHeraldField.php',
|
||||
'DiffusionPreCommitRefTypeHeraldField' => 'applications/diffusion/herald/DiffusionPreCommitRefTypeHeraldField.php',
|
||||
'DiffusionPullEventGarbageCollector' => 'applications/diffusion/DiffusionPullEventGarbageCollector.php',
|
||||
'DiffusionPullEventGarbageCollector' => 'applications/diffusion/garbagecollector/DiffusionPullEventGarbageCollector.php',
|
||||
'DiffusionPushCapability' => 'applications/diffusion/capability/DiffusionPushCapability.php',
|
||||
'DiffusionPushEventViewController' => 'applications/diffusion/controller/DiffusionPushEventViewController.php',
|
||||
'DiffusionPushLogController' => 'applications/diffusion/controller/DiffusionPushLogController.php',
|
||||
|
@ -2665,6 +2665,8 @@ phutil_register_library_map(array(
|
|||
'PhabricatorOwnersCustomFieldStorage' => 'applications/owners/storage/PhabricatorOwnersCustomFieldStorage.php',
|
||||
'PhabricatorOwnersCustomFieldStringIndex' => 'applications/owners/storage/PhabricatorOwnersCustomFieldStringIndex.php',
|
||||
'PhabricatorOwnersDAO' => 'applications/owners/storage/PhabricatorOwnersDAO.php',
|
||||
'PhabricatorOwnersDefaultEditCapability' => 'applications/owners/capability/PhabricatorOwnersDefaultEditCapability.php',
|
||||
'PhabricatorOwnersDefaultViewCapability' => 'applications/owners/capability/PhabricatorOwnersDefaultViewCapability.php',
|
||||
'PhabricatorOwnersDetailController' => 'applications/owners/controller/PhabricatorOwnersDetailController.php',
|
||||
'PhabricatorOwnersEditController' => 'applications/owners/controller/PhabricatorOwnersEditController.php',
|
||||
'PhabricatorOwnersListController' => 'applications/owners/controller/PhabricatorOwnersListController.php',
|
||||
|
@ -2867,9 +2869,11 @@ phutil_register_library_map(array(
|
|||
'PhabricatorProjectAddHeraldAction' => 'applications/project/herald/PhabricatorProjectAddHeraldAction.php',
|
||||
'PhabricatorProjectApplication' => 'applications/project/application/PhabricatorProjectApplication.php',
|
||||
'PhabricatorProjectArchiveController' => 'applications/project/controller/PhabricatorProjectArchiveController.php',
|
||||
'PhabricatorProjectBoardBackgroundController' => 'applications/project/controller/PhabricatorProjectBoardBackgroundController.php',
|
||||
'PhabricatorProjectBoardController' => 'applications/project/controller/PhabricatorProjectBoardController.php',
|
||||
'PhabricatorProjectBoardDisableController' => 'applications/project/controller/PhabricatorProjectBoardDisableController.php',
|
||||
'PhabricatorProjectBoardImportController' => 'applications/project/controller/PhabricatorProjectBoardImportController.php',
|
||||
'PhabricatorProjectBoardManageController' => 'applications/project/controller/PhabricatorProjectBoardManageController.php',
|
||||
'PhabricatorProjectBoardReorderController' => 'applications/project/controller/PhabricatorProjectBoardReorderController.php',
|
||||
'PhabricatorProjectBoardViewController' => 'applications/project/controller/PhabricatorProjectBoardViewController.php',
|
||||
'PhabricatorProjectCardView' => 'applications/project/view/PhabricatorProjectCardView.php',
|
||||
|
@ -2967,6 +2971,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorProjectViewController' => 'applications/project/controller/PhabricatorProjectViewController.php',
|
||||
'PhabricatorProjectWatchController' => 'applications/project/controller/PhabricatorProjectWatchController.php',
|
||||
'PhabricatorProjectWatcherListView' => 'applications/project/view/PhabricatorProjectWatcherListView.php',
|
||||
'PhabricatorProjectWorkboardBackgroundColor' => 'applications/project/constants/PhabricatorProjectWorkboardBackgroundColor.php',
|
||||
'PhabricatorProjectWorkboardProfilePanel' => 'applications/project/profilepanel/PhabricatorProjectWorkboardProfilePanel.php',
|
||||
'PhabricatorProjectsEditEngineExtension' => 'applications/project/engineextension/PhabricatorProjectsEditEngineExtension.php',
|
||||
'PhabricatorProjectsEditField' => 'applications/transactions/editfield/PhabricatorProjectsEditField.php',
|
||||
|
@ -5706,7 +5711,7 @@ phutil_register_library_map(array(
|
|||
'PHUIListView' => 'AphrontTagView',
|
||||
'PHUIListViewTestCase' => 'PhabricatorTestCase',
|
||||
'PHUIMainMenuView' => 'AphrontView',
|
||||
'PHUIObjectBoxView' => 'AphrontView',
|
||||
'PHUIObjectBoxView' => 'AphrontTagView',
|
||||
'PHUIObjectItemListExample' => 'PhabricatorUIExample',
|
||||
'PHUIObjectItemListView' => 'AphrontTagView',
|
||||
'PHUIObjectItemView' => 'AphrontTagView',
|
||||
|
@ -7036,6 +7041,8 @@ phutil_register_library_map(array(
|
|||
'PhabricatorOwnersCustomFieldStorage' => 'PhabricatorCustomFieldStorage',
|
||||
'PhabricatorOwnersCustomFieldStringIndex' => 'PhabricatorCustomFieldStringIndexStorage',
|
||||
'PhabricatorOwnersDAO' => 'PhabricatorLiskDAO',
|
||||
'PhabricatorOwnersDefaultEditCapability' => 'PhabricatorPolicyCapability',
|
||||
'PhabricatorOwnersDefaultViewCapability' => 'PhabricatorPolicyCapability',
|
||||
'PhabricatorOwnersDetailController' => 'PhabricatorOwnersController',
|
||||
'PhabricatorOwnersEditController' => 'PhabricatorOwnersController',
|
||||
'PhabricatorOwnersListController' => 'PhabricatorOwnersController',
|
||||
|
@ -7293,9 +7300,11 @@ phutil_register_library_map(array(
|
|||
'PhabricatorProjectAddHeraldAction' => 'PhabricatorProjectHeraldAction',
|
||||
'PhabricatorProjectApplication' => 'PhabricatorApplication',
|
||||
'PhabricatorProjectArchiveController' => 'PhabricatorProjectController',
|
||||
'PhabricatorProjectBoardBackgroundController' => 'PhabricatorProjectBoardController',
|
||||
'PhabricatorProjectBoardController' => 'PhabricatorProjectController',
|
||||
'PhabricatorProjectBoardDisableController' => 'PhabricatorProjectBoardController',
|
||||
'PhabricatorProjectBoardImportController' => 'PhabricatorProjectBoardController',
|
||||
'PhabricatorProjectBoardManageController' => 'PhabricatorProjectBoardController',
|
||||
'PhabricatorProjectBoardReorderController' => 'PhabricatorProjectBoardController',
|
||||
'PhabricatorProjectBoardViewController' => 'PhabricatorProjectBoardController',
|
||||
'PhabricatorProjectCardView' => 'AphrontTagView',
|
||||
|
@ -7305,6 +7314,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorApplicationTransactionInterface',
|
||||
'PhabricatorPolicyInterface',
|
||||
'PhabricatorDestructibleInterface',
|
||||
'PhabricatorExtendedPolicyInterface',
|
||||
),
|
||||
'PhabricatorProjectColumnDetailController' => 'PhabricatorProjectBoardController',
|
||||
'PhabricatorProjectColumnEditController' => 'PhabricatorProjectBoardController',
|
||||
|
@ -7406,6 +7416,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorProjectViewController' => 'PhabricatorProjectController',
|
||||
'PhabricatorProjectWatchController' => 'PhabricatorProjectController',
|
||||
'PhabricatorProjectWatcherListView' => 'PhabricatorProjectUserListView',
|
||||
'PhabricatorProjectWorkboardBackgroundColor' => 'Phobject',
|
||||
'PhabricatorProjectWorkboardProfilePanel' => 'PhabricatorProfilePanel',
|
||||
'PhabricatorProjectsEditEngineExtension' => 'PhabricatorEditEngineExtension',
|
||||
'PhabricatorProjectsEditField' => 'PhabricatorTokenizerEditField',
|
||||
|
|
|
@ -363,11 +363,7 @@ final class PhabricatorCalendarEventViewController
|
|||
->getIconLabel($event->getIcon()));
|
||||
|
||||
if (strlen($event->getDescription())) {
|
||||
$description = PhabricatorMarkupEngine::renderOneObject(
|
||||
id(new PhabricatorMarkupOneOff())->setContent($event->getDescription()),
|
||||
'default',
|
||||
$viewer);
|
||||
|
||||
$description = new PHUIRemarkupView($viewer, $event->getDescription());
|
||||
$properties->addSectionHeader(
|
||||
pht('Description'),
|
||||
PHUIPropertyListView::ICON_SUMMARY);
|
||||
|
|
|
@ -72,6 +72,12 @@ final class CelerityDefaultPostprocessor
|
|||
'hoverselectedblue' => '#e6e9ee',
|
||||
'borderinset' => 'inset 0 0 0 1px rgba(55,55,55,.15)',
|
||||
|
||||
// Alphas
|
||||
'alphawhite' => '255,255,255',
|
||||
'alphagrey' => '55,55,55',
|
||||
'alphablue' => '71,87,120',
|
||||
'alphablack' => '0,0,0',
|
||||
|
||||
// Base Greys
|
||||
'lightgreyborder' => '#C7CCD9',
|
||||
'greyborder' => '#A1A6B0',
|
||||
|
|
|
@ -37,7 +37,7 @@ final class PhabricatorConduitLogSearchEngine
|
|||
return array(
|
||||
id(new PhabricatorUsersSearchField())
|
||||
->setKey('callerPHIDs')
|
||||
->setLabel(pht('Methods'))
|
||||
->setLabel(pht('Callers'))
|
||||
->setAliases(array('caller', 'callers'))
|
||||
->setDescription(pht('Find calls by specific users.')),
|
||||
id(new PhabricatorSearchStringListField())
|
||||
|
|
|
@ -341,23 +341,14 @@ final class PhabricatorConfigWelcomeController
|
|||
$header = id(new PHUIHeaderView())
|
||||
->setHeader(pht('Welcome to Phabricator'));
|
||||
|
||||
$setup_header = PhabricatorMarkupEngine::renderOneObject(
|
||||
id(new PhabricatorMarkupOneOff())
|
||||
->setContent(pht('=Setup and Configuration')),
|
||||
'default',
|
||||
$viewer);
|
||||
$setup_header = new PHUIRemarkupView(
|
||||
$viewer, pht('=Setup and Configuration'));
|
||||
|
||||
$explore_header = PhabricatorMarkupEngine::renderOneObject(
|
||||
id(new PhabricatorMarkupOneOff())
|
||||
->setContent(pht('=Explore Phabricator')),
|
||||
'default',
|
||||
$viewer);
|
||||
$explore_header = new PHUIRemarkupView(
|
||||
$viewer, pht('=Explore Phabricator'));
|
||||
|
||||
$quick_header = PhabricatorMarkupEngine::renderOneObject(
|
||||
id(new PhabricatorMarkupOneOff())
|
||||
->setContent(pht('=Quick Start Guides')),
|
||||
'default',
|
||||
$viewer);
|
||||
$quick_header = new PHUIRemarkupView(
|
||||
$viewer, pht('=Quick Start Guide'));
|
||||
|
||||
return id(new PHUIDocumentView())
|
||||
->setHeader($header)
|
||||
|
@ -376,10 +367,7 @@ final class PhabricatorConfigWelcomeController
|
|||
$icon = id(new PHUIIconView())
|
||||
->setIcon($icon.' fa-2x');
|
||||
|
||||
$content = PhabricatorMarkupEngine::renderOneObject(
|
||||
id(new PhabricatorMarkupOneOff())->setContent($content),
|
||||
'default',
|
||||
$viewer);
|
||||
$content = new PHUIRemarkupView($viewer, $content);
|
||||
|
||||
$icon = phutil_tag(
|
||||
'div',
|
||||
|
|
|
@ -132,11 +132,7 @@ final class PhabricatorCountdownViewController
|
|||
|
||||
$description = $countdown->getDescription();
|
||||
if (strlen($description)) {
|
||||
$description = PhabricatorMarkupEngine::renderOneObject(
|
||||
id(new PhabricatorMarkupOneOff())->setContent($description),
|
||||
'default',
|
||||
$viewer);
|
||||
|
||||
$description = new PHUIRemarkupView($viewer, $description);
|
||||
$view->addSectionHeader(
|
||||
pht('Description'),
|
||||
PHUIPropertyListView::ICON_SUMMARY);
|
||||
|
|
|
@ -44,12 +44,7 @@ final class DifferentialRevertPlanField
|
|||
return null;
|
||||
}
|
||||
|
||||
return PhabricatorMarkupEngine::renderOneObject(
|
||||
id(new PhabricatorMarkupOneOff())
|
||||
->setPreserveLinebreaks(true)
|
||||
->setContent($this->getValue()),
|
||||
'default',
|
||||
$this->getViewer());
|
||||
return new PHUIRemarkupView($this->getViewer(), $this->getValue());
|
||||
}
|
||||
|
||||
public function shouldAppearInGlobalSearch() {
|
||||
|
|
|
@ -122,12 +122,7 @@ final class DifferentialSummaryField
|
|||
return null;
|
||||
}
|
||||
|
||||
return PhabricatorMarkupEngine::renderOneObject(
|
||||
id(new PhabricatorMarkupOneOff())
|
||||
->setPreserveLinebreaks(true)
|
||||
->setContent($this->getValue()),
|
||||
'default',
|
||||
$this->getViewer());
|
||||
return new PHUIRemarkupView($this->getViewer(), $this->getValue());
|
||||
}
|
||||
|
||||
public function getApplicationTransactionRemarkupBlocks(
|
||||
|
|
|
@ -136,12 +136,7 @@ final class DifferentialTestPlanField
|
|||
return null;
|
||||
}
|
||||
|
||||
return PhabricatorMarkupEngine::renderOneObject(
|
||||
id(new PhabricatorMarkupOneOff())
|
||||
->setPreserveLinebreaks(true)
|
||||
->setContent($this->getValue()),
|
||||
'default',
|
||||
$this->getViewer());
|
||||
return new PHUIRemarkupView($this->getViewer(), $this->getValue());
|
||||
}
|
||||
|
||||
public function getApplicationTransactionRemarkupBlocks(
|
||||
|
|
|
@ -64,7 +64,11 @@ final class PhabricatorDiffusionApplication extends PhabricatorApplication {
|
|||
'(?:query/(?P<queryKey>[^/]+)/)?' => 'DiffusionPushLogListController',
|
||||
'view/(?P<id>\d+)/' => 'DiffusionPushEventViewController',
|
||||
),
|
||||
'(?P<repositoryCallsign>[A-Z]+)/' => array(
|
||||
'(?:'.
|
||||
'(?P<repositoryCallsign>[A-Z]+)'.
|
||||
'|'.
|
||||
'(?P<repositoryID>[1-9]\d*)'.
|
||||
')/' => array(
|
||||
'' => 'DiffusionRepositoryController',
|
||||
|
||||
'repository/(?P<dblob>.*)' => 'DiffusionRepositoryController',
|
||||
|
@ -115,8 +119,9 @@ final class PhabricatorDiffusionApplication extends PhabricatorApplication {
|
|||
// catch-all for serving repositories over HTTP. We must accept
|
||||
// requests without the trailing "/" because SVN commands don't
|
||||
// necessarily include it.
|
||||
'(?P<repositoryCallsign>[A-Z]+)(?:/.*)?' =>
|
||||
'DiffusionRepositoryDefaultController',
|
||||
'(?:(?P<repositoryCallsign>[A-Z]+)|(?P<repositoryID>[1-9]\d*))'.
|
||||
'(?:/.*)?'
|
||||
=> 'DiffusionRepositoryDefaultController',
|
||||
|
||||
'inline/' => array(
|
||||
'edit/(?P<phid>[^/]+)/' => 'DiffusionInlineCommentController',
|
||||
|
|
|
@ -246,7 +246,16 @@ final class DiffusionBrowseQueryConduitAPIMethod
|
|||
DiffusionBrowseResultSet::REASON_IS_FILE);
|
||||
return $result;
|
||||
}
|
||||
|
||||
$parts = explode('/', $remainder);
|
||||
$name = reset($parts);
|
||||
|
||||
// If we've already seen this path component, we're looking at a file
|
||||
// inside a directory we already processed. Just move on.
|
||||
if (isset($results[$name])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (count($parts) == 1) {
|
||||
$type = DifferentialChangeType::FILE_NORMAL;
|
||||
} else {
|
||||
|
@ -254,7 +263,7 @@ final class DiffusionBrowseQueryConduitAPIMethod
|
|||
}
|
||||
|
||||
if ($count >= $offset) {
|
||||
$results[reset($parts)] = $type;
|
||||
$results[$name] = $type;
|
||||
}
|
||||
|
||||
$count++;
|
||||
|
|
|
@ -19,13 +19,19 @@ final class DiffusionBranchTableController extends DiffusionController {
|
|||
$pager = id(new PHUIPagerView())
|
||||
->readFromRequest($request);
|
||||
|
||||
// TODO: Add support for branches that contain commit
|
||||
$params = array(
|
||||
'offset' => $pager->getOffset(),
|
||||
'limit' => $pager->getPageSize() + 1,
|
||||
);
|
||||
|
||||
$contains = $drequest->getSymbolicCommit();
|
||||
if (strlen($contains)) {
|
||||
$params['contains'] = $contains;
|
||||
}
|
||||
|
||||
$branches = $this->callConduitWithDiffusionRequest(
|
||||
'diffusion.branchquery',
|
||||
array(
|
||||
'offset' => $pager->getOffset(),
|
||||
'limit' => $pager->getPageSize() + 1,
|
||||
));
|
||||
$params);
|
||||
$branches = $pager->sliceResults($branches);
|
||||
|
||||
$branches = DiffusionRepositoryRef::loadAllFromDictionaries($branches);
|
||||
|
|
|
@ -15,20 +15,18 @@ final class DiffusionCommitBranchesController extends DiffusionController {
|
|||
$drequest = $this->getDiffusionRequest();
|
||||
$repository = $drequest->getRepository();
|
||||
|
||||
switch ($repository->getVersionControlSystem()) {
|
||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
|
||||
$branches = array();
|
||||
break;
|
||||
default:
|
||||
$branches = $this->callConduitWithDiffusionRequest(
|
||||
'diffusion.branchquery',
|
||||
array(
|
||||
'contains' => $drequest->getCommit(),
|
||||
));
|
||||
break;
|
||||
}
|
||||
$branch_limit = 10;
|
||||
$branches = DiffusionRepositoryRef::loadAllFromDictionaries(
|
||||
$this->callConduitWithDiffusionRequest(
|
||||
'diffusion.branchquery',
|
||||
array(
|
||||
'contains' => $drequest->getCommit(),
|
||||
'limit' => $branch_limit + 1,
|
||||
)));
|
||||
|
||||
$has_more_branches = (count($branches) > $branch_limit);
|
||||
$branches = array_slice($branches, 0, $branch_limit);
|
||||
|
||||
$branches = DiffusionRepositoryRef::loadAllFromDictionaries($branches);
|
||||
$branch_links = array();
|
||||
foreach ($branches as $branch) {
|
||||
$branch_links[] = phutil_tag(
|
||||
|
@ -43,6 +41,18 @@ final class DiffusionCommitBranchesController extends DiffusionController {
|
|||
$branch->getShortName());
|
||||
}
|
||||
|
||||
if ($has_more_branches) {
|
||||
$branch_links[] = phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => $drequest->generateURI(
|
||||
array(
|
||||
'action' => 'branches',
|
||||
)),
|
||||
),
|
||||
pht("More Branches\xE2\x80\xA6"));
|
||||
}
|
||||
|
||||
return id(new AphrontAjaxResponse())
|
||||
->setContent($branch_links ? implode(', ', $branch_links) : pht('None'));
|
||||
}
|
||||
|
|
|
@ -16,20 +16,14 @@ final class DiffusionCommitTagsController extends DiffusionController {
|
|||
$repository = $drequest->getRepository();
|
||||
|
||||
$tag_limit = 10;
|
||||
switch ($repository->getVersionControlSystem()) {
|
||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
|
||||
$tags = array();
|
||||
break;
|
||||
default:
|
||||
$tags = DiffusionRepositoryTag::newFromConduit(
|
||||
$this->callConduitWithDiffusionRequest(
|
||||
'diffusion.tagsquery',
|
||||
array(
|
||||
'commit' => $drequest->getCommit(),
|
||||
'limit' => $tag_limit + 1,
|
||||
)));
|
||||
break;
|
||||
}
|
||||
$tags = DiffusionRepositoryTag::newFromConduit(
|
||||
$this->callConduitWithDiffusionRequest(
|
||||
'diffusion.tagsquery',
|
||||
array(
|
||||
'commit' => $drequest->getCommit(),
|
||||
'limit' => $tag_limit + 1,
|
||||
)));
|
||||
|
||||
$has_more_tags = (count($tags) > $tag_limit);
|
||||
$tags = array_slice($tags, 0, $tag_limit);
|
||||
|
||||
|
|
|
@ -64,6 +64,20 @@ abstract class DiffusionController extends PhabricatorController {
|
|||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
// If the client is making a request like "/diffusion/1/...", but the
|
||||
// repository has a different canonical path like "/diffusion/XYZ/...",
|
||||
// redirect them to the canonical path.
|
||||
|
||||
$request_path = $request->getPath();
|
||||
$repository = $drequest->getRepository();
|
||||
|
||||
$canonical_path = $repository->getCanonicalPath($request_path);
|
||||
if ($canonical_path !== null) {
|
||||
if ($canonical_path != $request_path) {
|
||||
return id(new AphrontRedirectResponse())->setURI($canonical_path);
|
||||
}
|
||||
}
|
||||
|
||||
$this->diffusionRequest = $drequest;
|
||||
|
||||
return null;
|
||||
|
|
|
@ -290,10 +290,7 @@ final class DiffusionRepositoryController extends DiffusionController {
|
|||
|
||||
$description = $repository->getDetail('description');
|
||||
if (strlen($description)) {
|
||||
$description = PhabricatorMarkupEngine::renderOneObject(
|
||||
$repository,
|
||||
'description',
|
||||
$user);
|
||||
$description = new PHUIRemarkupView($user, $description);
|
||||
$view->addSectionHeader(
|
||||
pht('Description'), PHUIPropertyListView::ICON_SUMMARY);
|
||||
$view->addTextContent($description);
|
||||
|
|
|
@ -134,7 +134,6 @@ final class DiffusionRepositoryCreateController
|
|||
$type_name = PhabricatorRepositoryTransaction::TYPE_NAME;
|
||||
$type_vcs = PhabricatorRepositoryTransaction::TYPE_VCS;
|
||||
$type_activate = PhabricatorRepositoryTransaction::TYPE_ACTIVATE;
|
||||
$type_local_path = PhabricatorRepositoryTransaction::TYPE_LOCAL_PATH;
|
||||
$type_remote_uri = PhabricatorRepositoryTransaction::TYPE_REMOTE_URI;
|
||||
$type_hosting = PhabricatorRepositoryTransaction::TYPE_HOSTING;
|
||||
$type_http = PhabricatorRepositoryTransaction::TYPE_PROTOCOL_HTTP;
|
||||
|
@ -150,14 +149,6 @@ final class DiffusionRepositoryCreateController
|
|||
|
||||
// If we're creating a new repository, set all this core stuff.
|
||||
if ($is_create) {
|
||||
$callsign = $form->getPage('name')
|
||||
->getControl('callsign')->getValue();
|
||||
|
||||
// We must set this to a unique value to save the repository
|
||||
// initially, and it's immutable, so we don't bother using
|
||||
// transactions to apply this change.
|
||||
$repository->setCallsign($callsign);
|
||||
|
||||
$xactions[] = id(clone $template)
|
||||
->setTransactionType($type_name)
|
||||
->setNewValue(
|
||||
|
@ -179,16 +170,6 @@ final class DiffusionRepositoryCreateController
|
|||
->setTransactionType($type_service)
|
||||
->setNewValue($service->getPHID());
|
||||
}
|
||||
|
||||
$default_local_path = PhabricatorEnv::getEnvConfig(
|
||||
'repository.default-local-path');
|
||||
|
||||
$default_local_path = rtrim($default_local_path, '/');
|
||||
$default_local_path = $default_local_path.'/'.$callsign.'/';
|
||||
|
||||
$xactions[] = id(clone $template)
|
||||
->setTransactionType($type_local_path)
|
||||
->setNewValue($default_local_path);
|
||||
}
|
||||
|
||||
if ($is_init) {
|
||||
|
@ -354,7 +335,7 @@ final class DiffusionRepositoryCreateController
|
|||
}
|
||||
|
||||
|
||||
/* -( Page: Name and Callsign )-------------------------------------------- */
|
||||
/* -( Page: Name )--------------------------------------------------------- */
|
||||
|
||||
|
||||
private function buildNamePage() {
|
||||
|
@ -370,23 +351,7 @@ final class DiffusionRepositoryCreateController
|
|||
->addControl(
|
||||
id(new AphrontFormTextControl())
|
||||
->setName('name')
|
||||
->setLabel(pht('Name'))
|
||||
->setCaption(pht('Human-readable repository name.')))
|
||||
->addRemarkupInstructions(
|
||||
pht(
|
||||
'**Choose a "Callsign" for the repository.** This is a short, '.
|
||||
'unique string which identifies commits elsewhere in Phabricator. '.
|
||||
'For example, you might use `M` for your mobile app repository '.
|
||||
'and `B` for your backend repository.'.
|
||||
"\n\n".
|
||||
'**Callsigns must be UPPERCASE**, and can not be edited after the '.
|
||||
'repository is created. Generally, you should choose short '.
|
||||
'callsigns.'))
|
||||
->addControl(
|
||||
id(new AphrontFormTextControl())
|
||||
->setName('callsign')
|
||||
->setLabel(pht('Callsign'))
|
||||
->setCaption(pht('Short UPPERCASE identifier.')));
|
||||
->setLabel(pht('Name')));
|
||||
}
|
||||
|
||||
public function validateNamePage(PHUIFormPageView $page) {
|
||||
|
@ -398,38 +363,7 @@ final class DiffusionRepositoryCreateController
|
|||
pht('You must choose a name for this repository.'));
|
||||
}
|
||||
|
||||
$c_call = $page->getControl('callsign');
|
||||
$v_call = $c_call->getValue();
|
||||
if (!strlen($v_call)) {
|
||||
$c_call->setError(pht('Required'));
|
||||
$page->addPageError(
|
||||
pht('You must choose a callsign for this repository.'));
|
||||
} else if (!preg_match('/^[A-Z]+\z/', $v_call)) {
|
||||
$c_call->setError(pht('Invalid'));
|
||||
$page->addPageError(
|
||||
pht('The callsign must contain only UPPERCASE letters.'));
|
||||
} else {
|
||||
$exists = false;
|
||||
try {
|
||||
$repo = id(new PhabricatorRepositoryQuery())
|
||||
->setViewer($this->getRequest()->getUser())
|
||||
->withCallsigns(array($v_call))
|
||||
->executeOne();
|
||||
$exists = (bool)$repo;
|
||||
} catch (PhabricatorPolicyException $ex) {
|
||||
$exists = true;
|
||||
}
|
||||
if ($exists) {
|
||||
$c_call->setError(pht('Not Unique'));
|
||||
$page->addPageError(
|
||||
pht(
|
||||
'Another repository already uses that callsign. You must choose '.
|
||||
'a unique callsign.'));
|
||||
}
|
||||
}
|
||||
|
||||
return $c_name->isValid() &&
|
||||
$c_call->isValid();
|
||||
return $c_name->isValid();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -18,11 +18,13 @@ final class DiffusionRepositoryEditBasicController
|
|||
$v_name = $repository->getName();
|
||||
$v_desc = $repository->getDetail('description');
|
||||
$v_slug = $repository->getRepositorySlug();
|
||||
$v_callsign = $repository->getCallsign();
|
||||
$v_projects = PhabricatorEdgeQuery::loadDestinationPHIDs(
|
||||
$repository->getPHID(),
|
||||
PhabricatorProjectObjectHasProjectEdgeType::EDGECONST);
|
||||
$e_name = true;
|
||||
$e_slug = null;
|
||||
$e_callsign = null;
|
||||
$errors = array();
|
||||
|
||||
$validation_exception = null;
|
||||
|
@ -31,6 +33,7 @@ final class DiffusionRepositoryEditBasicController
|
|||
$v_desc = $request->getStr('description');
|
||||
$v_projects = $request->getArr('projectPHIDs');
|
||||
$v_slug = $request->getStr('slug');
|
||||
$v_callsign = $request->getStr('callsign');
|
||||
|
||||
if (!strlen($v_name)) {
|
||||
$e_name = pht('Required');
|
||||
|
@ -47,6 +50,7 @@ final class DiffusionRepositoryEditBasicController
|
|||
$type_desc = PhabricatorRepositoryTransaction::TYPE_DESCRIPTION;
|
||||
$type_edge = PhabricatorTransactions::TYPE_EDGE;
|
||||
$type_slug = PhabricatorRepositoryTransaction::TYPE_SLUG;
|
||||
$type_callsign = PhabricatorRepositoryTransaction::TYPE_CALLSIGN;
|
||||
|
||||
$xactions[] = id(clone $template)
|
||||
->setTransactionType($type_name)
|
||||
|
@ -60,6 +64,10 @@ final class DiffusionRepositoryEditBasicController
|
|||
->setTransactionType($type_slug)
|
||||
->setNewValue($v_slug);
|
||||
|
||||
$xactions[] = id(clone $template)
|
||||
->setTransactionType($type_callsign)
|
||||
->setNewValue($v_callsign);
|
||||
|
||||
$xactions[] = id(clone $template)
|
||||
->setTransactionType($type_edge)
|
||||
->setMetadataValue(
|
||||
|
@ -78,11 +86,16 @@ final class DiffusionRepositoryEditBasicController
|
|||
try {
|
||||
$editor->applyTransactions($repository, $xactions);
|
||||
|
||||
// The preferred edit URI may have changed if the callsign or slug
|
||||
// were adjusted, so grab a fresh copy.
|
||||
$edit_uri = $this->getRepositoryControllerURI($repository, 'edit/');
|
||||
|
||||
return id(new AphrontRedirectResponse())->setURI($edit_uri);
|
||||
} catch (PhabricatorApplicationTransactionValidationException $ex) {
|
||||
$validation_exception = $ex;
|
||||
|
||||
$e_slug = $ex->getShortMessage($type_slug);
|
||||
$e_callsign = $ex->getShortMessage($type_callsign);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -106,6 +119,12 @@ final class DiffusionRepositoryEditBasicController
|
|||
->setLabel(pht('Short Name'))
|
||||
->setValue($v_slug)
|
||||
->setError($e_slug))
|
||||
->appendChild(
|
||||
id(new AphrontFormTextControl())
|
||||
->setName('callsign')
|
||||
->setLabel(pht('Callsign'))
|
||||
->setValue($v_callsign)
|
||||
->setError($e_callsign))
|
||||
->appendChild(
|
||||
id(new PhabricatorRemarkupControl())
|
||||
->setUser($viewer)
|
||||
|
|
|
@ -284,7 +284,12 @@ final class DiffusionRepositoryEditMainController
|
|||
$repository->getVersionControlSystem());
|
||||
|
||||
$view->addProperty(pht('Type'), $type);
|
||||
$view->addProperty(pht('Callsign'), $repository->getCallsign());
|
||||
|
||||
$callsign = $repository->getCallsign();
|
||||
if (!strlen($callsign)) {
|
||||
$callsign = phutil_tag('em', array(), pht('No Callsign'));
|
||||
}
|
||||
$view->addProperty(pht('Callsign'), $callsign);
|
||||
|
||||
$short_name = $repository->getRepositorySlug();
|
||||
if ($short_name === null) {
|
||||
|
@ -309,10 +314,7 @@ final class DiffusionRepositoryEditMainController
|
|||
if (!strlen($description)) {
|
||||
$description = phutil_tag('em', array(), pht('No description provided.'));
|
||||
} else {
|
||||
$description = PhabricatorMarkupEngine::renderOneObject(
|
||||
$repository,
|
||||
'description',
|
||||
$viewer);
|
||||
$description = new PHUIRemarkupView($viewer, $description);
|
||||
}
|
||||
$view->addTextContent($description);
|
||||
|
||||
|
|
|
@ -262,17 +262,23 @@ final class DiffusionServeController extends DiffusionController {
|
|||
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
|
||||
$result = new PhabricatorVCSResponse(
|
||||
500,
|
||||
pht('This is not a Git repository.'));
|
||||
pht(
|
||||
'This repository ("%s") is not a Git repository.',
|
||||
$repository->getDisplayName()));
|
||||
break;
|
||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
|
||||
$result = new PhabricatorVCSResponse(
|
||||
500,
|
||||
pht('This is not a Mercurial repository.'));
|
||||
pht(
|
||||
'This repository ("%s") is not a Mercurial repository.',
|
||||
$repository->getDisplayName()));
|
||||
break;
|
||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
|
||||
$result = new PhabricatorVCSResponse(
|
||||
500,
|
||||
pht('This is not a Subversion repository.'));
|
||||
pht(
|
||||
'This repository ("%s") is not a Subversion repository.',
|
||||
$repository->getDisplayName()));
|
||||
break;
|
||||
default:
|
||||
$result = new PhabricatorVCSResponse(
|
||||
|
@ -480,7 +486,9 @@ final class DiffusionServeController extends DiffusionController {
|
|||
private function getRequestDirectoryPath(PhabricatorRepository $repository) {
|
||||
$request = $this->getRequest();
|
||||
$request_path = $request->getRequestURI()->getPath();
|
||||
$base_path = preg_replace('@^/diffusion/[A-Z]+@', '', $request_path);
|
||||
|
||||
$info = PhabricatorRepository::parseRepositoryServicePath($request_path);
|
||||
$base_path = $info['path'];
|
||||
|
||||
// For Git repositories, strip an optional directory component if it
|
||||
// isn't the name of a known Git resource. This allows users to clone
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
*/
|
||||
final class DiffusionCommitHookEngine extends Phobject {
|
||||
|
||||
const ENV_REPOSITORY = 'PHABRICATOR_REPOSITORY';
|
||||
const ENV_USER = 'PHABRICATOR_USER';
|
||||
const ENV_REMOTE_ADDRESS = 'PHABRICATOR_REMOTE_ADDRESS';
|
||||
const ENV_REMOTE_PROTOCOL = 'PHABRICATOR_REMOTE_PROTOCOL';
|
||||
|
@ -610,7 +611,7 @@ final class DiffusionCommitHookEngine extends Phobject {
|
|||
$console = PhutilConsole::getConsole();
|
||||
|
||||
$env = array(
|
||||
'PHABRICATOR_REPOSITORY' => $this->getRepository()->getCallsign(),
|
||||
self::ENV_REPOSITORY => $this->getRepository()->getPHID(),
|
||||
self::ENV_USER => $this->getViewer()->getUsername(),
|
||||
self::ENV_REMOTE_PROTOCOL => $this->getRemoteProtocol(),
|
||||
self::ENV_REMOTE_ADDRESS => $this->getRemoteAddress(),
|
||||
|
|
|
@ -243,10 +243,6 @@ abstract class DiffusionRequest extends Phobject {
|
|||
return $this->repository;
|
||||
}
|
||||
|
||||
public function getCallsign() {
|
||||
return $this->getRepository()->getCallsign();
|
||||
}
|
||||
|
||||
public function setPath($path) {
|
||||
$this->path = $path;
|
||||
return $this;
|
||||
|
|
|
@ -6,6 +6,7 @@ abstract class DiffusionSSHWorkflow extends PhabricatorSSHWorkflow {
|
|||
private $repository;
|
||||
private $hasWriteAccess;
|
||||
private $proxyURI;
|
||||
private $baseRequestPath;
|
||||
|
||||
public function getRepository() {
|
||||
if (!$this->repository) {
|
||||
|
@ -45,6 +46,10 @@ abstract class DiffusionSSHWorkflow extends PhabricatorSSHWorkflow {
|
|||
abstract protected function identifyRepository();
|
||||
abstract protected function executeRepositoryOperations();
|
||||
|
||||
protected function getBaseRequestPath() {
|
||||
return $this->baseRequestPath;
|
||||
}
|
||||
|
||||
protected function writeError($message) {
|
||||
$this->getErrorChannel()->write($message);
|
||||
return $this;
|
||||
|
@ -149,25 +154,29 @@ abstract class DiffusionSSHWorkflow extends PhabricatorSSHWorkflow {
|
|||
protected function loadRepositoryWithPath($path) {
|
||||
$viewer = $this->getUser();
|
||||
|
||||
$regex = '@^/?diffusion/(?P<callsign>[A-Z]+)(?:/|\z)@';
|
||||
$matches = null;
|
||||
if (!preg_match($regex, $path, $matches)) {
|
||||
$info = PhabricatorRepository::parseRepositoryServicePath($path);
|
||||
if ($info === null) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Unrecognized repository path "%s". Expected a path like "%s".',
|
||||
'Unrecognized repository path "%s". Expected a path like "%s" '.
|
||||
'or "%s".',
|
||||
$path,
|
||||
'/diffusion/X/'));
|
||||
'/diffusion/X/',
|
||||
'/diffusion/123/'));
|
||||
}
|
||||
|
||||
$callsign = $matches[1];
|
||||
$identifier = $info['identifier'];
|
||||
$base = $info['base'];
|
||||
|
||||
$this->baseRequestPath = $base;
|
||||
|
||||
$repository = id(new PhabricatorRepositoryQuery())
|
||||
->setViewer($viewer)
|
||||
->withCallsigns(array($callsign))
|
||||
->withIdentifiers(array($identifier))
|
||||
->executeOne();
|
||||
|
||||
if (!$repository) {
|
||||
throw new Exception(
|
||||
pht('No repository "%s" exists!', $callsign));
|
||||
pht('No repository "%s" exists!', $identifier));
|
||||
}
|
||||
|
||||
switch ($repository->getServeOverSSH()) {
|
||||
|
@ -179,7 +188,9 @@ abstract class DiffusionSSHWorkflow extends PhabricatorSSHWorkflow {
|
|||
case PhabricatorRepository::SERVE_OFF:
|
||||
default:
|
||||
throw new Exception(
|
||||
pht('This repository is not available over SSH.'));
|
||||
pht(
|
||||
'This repository ("%s") is not available over SSH.',
|
||||
$repository->getDisplayName()));
|
||||
}
|
||||
|
||||
return $repository;
|
||||
|
|
|
@ -377,14 +377,12 @@ final class DiffusionSubversionServeSSHWorkflow
|
|||
$repository = $this->getRepository();
|
||||
|
||||
$path = $this->getPathFromSubversionURI($uri_string);
|
||||
$path = preg_replace(
|
||||
'(^/diffusion/[A-Z]+)',
|
||||
rtrim($repository->getLocalPath(), '/'),
|
||||
$path);
|
||||
$external_base = $this->getBaseRequestPath();
|
||||
|
||||
if (preg_match('(^/diffusion/[A-Z]+/\z)', $path)) {
|
||||
$path = rtrim($path, '/');
|
||||
}
|
||||
// Replace "/diffusion/X" in the request with the repository local path,
|
||||
// so "/diffusion/X/master/" becomes "/path/to/repository/X/master/".
|
||||
$local_path = rtrim($repository->getLocalPath(), '/');
|
||||
$path = $local_path.substr($path, strlen($external_base));
|
||||
|
||||
// NOTE: We are intentionally NOT removing username information from the
|
||||
// URI. Subversion retains it over the course of the request and considers
|
||||
|
@ -398,7 +396,7 @@ final class DiffusionSubversionServeSSHWorkflow
|
|||
if ($this->externalBaseURI === null) {
|
||||
$pre = (string)id(clone $uri)->setPath('');
|
||||
|
||||
$external_path = '/diffusion/'.$repository->getCallsign();
|
||||
$external_path = $external_base;
|
||||
$external_path = $this->normalizeSVNPath($external_path);
|
||||
$this->externalBaseURI = $pre.$external_path;
|
||||
|
||||
|
|
|
@ -109,11 +109,14 @@ final class DiffusionReadmeView extends DiffusionView {
|
|||
$header = id(new PHUIHeaderView())
|
||||
->setHeader($readme_name);
|
||||
|
||||
return id(new PHUIDocumentView())
|
||||
$document = id(new PHUIDocumentViewPro())
|
||||
->setFluid(true)
|
||||
->appendChild($readme_content)
|
||||
->addClass('diffusion-readme-view')
|
||||
->setHeader($header);
|
||||
->appendChild($readme_content);
|
||||
|
||||
return id(new PHUIObjectBoxView())
|
||||
->setHeader($header)
|
||||
->appendChild($document)
|
||||
->addClass('diffusion-readme-view');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -29,20 +29,12 @@ final class DivinerBookController extends DivinerController {
|
|||
$book->getShortTitle(),
|
||||
'/book/'.$book->getName().'/');
|
||||
|
||||
$action_button = id(new PHUIButtonView())
|
||||
->setTag('a')
|
||||
->setText(pht('Actions'))
|
||||
->setHref('#')
|
||||
->setIcon('fa-bars')
|
||||
->addClass('phui-mobile-menu')
|
||||
->setDropdownMenu($actions);
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader($book->getTitle())
|
||||
->setUser($viewer)
|
||||
->setPolicyObject($book)
|
||||
->setEpoch($book->getDateModified())
|
||||
->addActionLink($action_button);
|
||||
->setActionList($actions);
|
||||
|
||||
// TODO: This could probably look better.
|
||||
if ($book->getRepositoryPHID()) {
|
||||
|
@ -94,11 +86,7 @@ final class DivinerBookController extends DivinerController {
|
|||
$preface = $book->getPreface();
|
||||
$preface_view = null;
|
||||
if (strlen($preface)) {
|
||||
$preface_view =
|
||||
PhabricatorMarkupEngine::renderOneObject(
|
||||
id(new PhabricatorMarkupOneOff())->setContent($preface),
|
||||
'default',
|
||||
$viewer);
|
||||
$preface_view = new PHUIRemarkupView($viewer, $preface);
|
||||
}
|
||||
|
||||
$document->appendChild($preface_view);
|
||||
|
|
|
@ -61,11 +61,7 @@ final class DivinerMainController extends DivinerController {
|
|||
" %s\n\n",
|
||||
'phabricator/ $ ./bin/diviner generate');
|
||||
|
||||
$text = PhabricatorMarkupEngine::renderOneObject(
|
||||
id(new PhabricatorMarkupOneOff())->setContent($text),
|
||||
'default',
|
||||
$viewer);
|
||||
|
||||
$text = new PHUIRemarkupView($viewer, $text);
|
||||
$document->appendChild($text);
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ final class DivinerGenerateWorkflow extends DivinerWorkflow {
|
|||
),
|
||||
array(
|
||||
'name' => 'repository',
|
||||
'param' => 'callsign',
|
||||
'param' => 'identifier',
|
||||
'help' => pht('Repository that the documentation belongs to.'),
|
||||
),
|
||||
));
|
||||
|
@ -192,19 +192,19 @@ final class DivinerGenerateWorkflow extends DivinerWorkflow {
|
|||
}
|
||||
$publisher = newv($publisher_class, array());
|
||||
|
||||
$callsign = $args->getArg('repository');
|
||||
$identifier = $args->getArg('repository');
|
||||
$repository = null;
|
||||
if ($callsign) {
|
||||
if (strlen($identifier)) {
|
||||
$repository = id(new PhabricatorRepositoryQuery())
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->withCallsigns(array($callsign))
|
||||
->withIdentifiers(array($identifier))
|
||||
->executeOne();
|
||||
|
||||
if (!$repository) {
|
||||
throw new PhutilArgumentUsageException(
|
||||
pht(
|
||||
"Repository '%s' does not exist.",
|
||||
$callsign));
|
||||
'Repository "%s" does not exist.',
|
||||
$identifier));
|
||||
}
|
||||
|
||||
$publisher->setRepositoryPHID($repository->getPHID());
|
||||
|
|
|
@ -111,10 +111,7 @@ final class PhabricatorAsanaConfigOptions
|
|||
"The Asana Workspaces your linked account has access to are:\n\n%s",
|
||||
$out);
|
||||
|
||||
return PhabricatorMarkupEngine::renderOneObject(
|
||||
id(new PhabricatorMarkupOneOff())->setContent($out),
|
||||
'default',
|
||||
$viewer);
|
||||
return new PHUIRemarkupView($viewer, $out);
|
||||
}
|
||||
|
||||
private function renderContextualProjectDescription(
|
||||
|
@ -155,10 +152,7 @@ final class PhabricatorAsanaConfigOptions
|
|||
|
||||
$out = implode("\n", $out);
|
||||
|
||||
return PhabricatorMarkupEngine::renderOneObject(
|
||||
id(new PhabricatorMarkupOneOff())->setContent($out),
|
||||
'default',
|
||||
$viewer);
|
||||
return new PHUIRemarkupView($viewer, $out);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -98,11 +98,7 @@ final class FundInitiativeViewController
|
|||
|
||||
$description = $initiative->getDescription();
|
||||
if (strlen($description)) {
|
||||
$description = PhabricatorMarkupEngine::renderOneObject(
|
||||
id(new PhabricatorMarkupOneOff())->setContent($description),
|
||||
'default',
|
||||
$viewer);
|
||||
|
||||
$description = new PHUIRemarkupView($viewer, $description);
|
||||
$view->addSectionHeader(
|
||||
pht('Description'), PHUIPropertyListView::ICON_SUMMARY);
|
||||
$view->addTextContent($description);
|
||||
|
@ -110,11 +106,7 @@ final class FundInitiativeViewController
|
|||
|
||||
$risks = $initiative->getRisks();
|
||||
if (strlen($risks)) {
|
||||
$risks = PhabricatorMarkupEngine::renderOneObject(
|
||||
id(new PhabricatorMarkupOneOff())->setContent($risks),
|
||||
'default',
|
||||
$viewer);
|
||||
|
||||
$risks = new PHUIRemarkupView($viewer, $risks);
|
||||
$view->addSectionHeader(
|
||||
pht('Risks/Challenges'), 'fa-ambulance');
|
||||
$view->addTextContent($risks);
|
||||
|
|
|
@ -181,16 +181,10 @@ final class HarbormasterBuildViewController
|
|||
if ($step) {
|
||||
$description = $step->getDescription();
|
||||
if ($description) {
|
||||
$rendered = PhabricatorMarkupEngine::renderOneObject(
|
||||
id(new PhabricatorMarkupOneOff())
|
||||
->setContent($description)
|
||||
->setPreserveLinebreaks(true),
|
||||
'default',
|
||||
$viewer);
|
||||
|
||||
$description = new PHUIRemarkupView($viewer, $description);
|
||||
$properties->addSectionHeader(
|
||||
pht('Description'), PHUIPropertyListView::ICON_SUMMARY);
|
||||
$properties->addTextContent($rendered);
|
||||
$properties->addTextContent($description);
|
||||
}
|
||||
} else {
|
||||
$target_box->setFormErrors(
|
||||
|
|
|
@ -258,11 +258,7 @@ final class LegalpadDocumentSignController extends LegalpadController {
|
|||
|
||||
$preamble_box = null;
|
||||
if (strlen($document->getPreamble())) {
|
||||
$preamble_text = PhabricatorMarkupEngine::renderOneObject(
|
||||
id(new PhabricatorMarkupOneOff())->setContent(
|
||||
$document->getPreamble()),
|
||||
'default',
|
||||
$viewer);
|
||||
$preamble_text = new PHUIRemarkupView($viewer, $document->getPreamble());
|
||||
|
||||
// NOTE: We're avoiding `setObject()` here so we don't pick up extra UI
|
||||
// elements like "Subscribers". This information is available on the
|
||||
|
|
|
@ -42,13 +42,6 @@ final class PhabricatorMacroApplication extends PhabricatorApplication {
|
|||
);
|
||||
}
|
||||
|
||||
public function getRemarkupRules() {
|
||||
return array(
|
||||
new PhabricatorIconRemarkupRule(),
|
||||
new PhabricatorEmojiRemarkupRule(),
|
||||
);
|
||||
}
|
||||
|
||||
protected function getCustomCapabilities() {
|
||||
return array(
|
||||
PhabricatorMacroManageCapability::CAPABILITY => array(
|
||||
|
|
|
@ -289,8 +289,14 @@ final class ManiphestTransactionEditor
|
|||
array($select_phids))
|
||||
->execute();
|
||||
|
||||
$object_phids = mpull($board_tasks, 'getPHID');
|
||||
$object_phids[] = $object_phid;
|
||||
$board_tasks = mpull($board_tasks, null, 'getPHID');
|
||||
$board_tasks[$object_phid] = $object;
|
||||
|
||||
// Make sure tasks are sorted by ID, so we lay out new positions in
|
||||
// a consistent way.
|
||||
$board_tasks = msort($board_tasks, 'getID');
|
||||
|
||||
$object_phids = array_keys($board_tasks);
|
||||
|
||||
$engine = id(new PhabricatorBoardLayoutEngine())
|
||||
->setViewer($omnipotent_viewer)
|
||||
|
|
|
@ -104,14 +104,11 @@ final class PhabricatorApplicationDetailViewController
|
|||
}
|
||||
|
||||
$overview = $application->getOverview();
|
||||
if ($overview) {
|
||||
if (strlen($overview)) {
|
||||
$overview = new PHUIRemarkupView($viewer, $overview);
|
||||
$properties->addSectionHeader(
|
||||
pht('Overview'), PHUIPropertyListView::ICON_SUMMARY);
|
||||
$properties->addTextContent(
|
||||
PhabricatorMarkupEngine::renderOneObject(
|
||||
id(new PhabricatorMarkupOneOff())->setContent($overview),
|
||||
'default',
|
||||
$viewer));
|
||||
$properties->addTextContent($overview);
|
||||
}
|
||||
|
||||
$descriptions = PhabricatorPolicyQuery::renderPolicyDescriptions(
|
||||
|
|
|
@ -117,10 +117,7 @@ final class PhabricatorApplicationEmailCommandsController
|
|||
$crumbs->addTextCrumb($title);
|
||||
$crumbs->setBorder(true);
|
||||
|
||||
$content_box = PhabricatorMarkupEngine::renderOneObject(
|
||||
id(new PhabricatorMarkupOneOff())->setContent($content),
|
||||
'default',
|
||||
$viewer);
|
||||
$content_box = new PHUIRemarkupView($viewer, $content);
|
||||
|
||||
$info_view = null;
|
||||
if (!PhabricatorEnv::getEnvConfig('metamta.reply-handler-domain')) {
|
||||
|
|
|
@ -120,11 +120,7 @@ final class NuancePhabricatorFormSourceDefinition
|
|||
PHUIPropertyListView $view) {
|
||||
|
||||
$complaint = $item->getNuanceProperty('complaint');
|
||||
$complaint = PhabricatorMarkupEngine::renderOneObject(
|
||||
id(new PhabricatorMarkupOneOff())->setContent($complaint),
|
||||
'default',
|
||||
$viewer);
|
||||
|
||||
$complaint = new PHUIRemarkupView($viewer, $complaint);
|
||||
$view->addSectionHeader(
|
||||
pht('Complaint'), 'fa-exclamation-circle');
|
||||
$view->addTextContent($complaint);
|
||||
|
|
|
@ -54,4 +54,19 @@ final class PhabricatorOwnersApplication extends PhabricatorApplication {
|
|||
);
|
||||
}
|
||||
|
||||
protected function getCustomCapabilities() {
|
||||
return array(
|
||||
PhabricatorOwnersDefaultViewCapability::CAPABILITY => array(
|
||||
'caption' => pht('Default view policy for newly created packages.'),
|
||||
'template' => PhabricatorOwnersPackagePHIDType::TYPECONST,
|
||||
'capability' => PhabricatorPolicyCapability::CAN_VIEW,
|
||||
),
|
||||
PhabricatorOwnersDefaultEditCapability::CAPABILITY => array(
|
||||
'caption' => pht('Default edit policy for newly created packages.'),
|
||||
'template' => PhabricatorOwnersPackagePHIDType::TYPECONST,
|
||||
'capability' => PhabricatorPolicyCapability::CAN_EDIT,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorOwnersDefaultEditCapability
|
||||
extends PhabricatorPolicyCapability {
|
||||
|
||||
const CAPABILITY = 'owners.default.edit';
|
||||
|
||||
public function getCapabilityName() {
|
||||
return pht('Default Edit Policy');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorOwnersDefaultViewCapability
|
||||
extends PhabricatorPolicyCapability {
|
||||
|
||||
const CAPABILITY = 'owners.default.view';
|
||||
|
||||
public function getCapabilityName() {
|
||||
return pht('Default View Policy');
|
||||
}
|
||||
|
||||
public function shouldAllowPublicPolicySetting() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -189,13 +189,10 @@ final class PhabricatorOwnersDetailController
|
|||
|
||||
$description = $package->getDescription();
|
||||
if (strlen($description)) {
|
||||
$description = new PHUIRemarkupView($viewer, $description);
|
||||
$view->addSectionHeader(
|
||||
pht('Description'), PHUIPropertyListView::ICON_SUMMARY);
|
||||
$view->addTextContent(
|
||||
$output = PhabricatorMarkupEngine::renderOneObject(
|
||||
id(new PhabricatorMarkupOneOff())->setContent($description),
|
||||
'default',
|
||||
$viewer));
|
||||
$view->addTextContent($description);
|
||||
}
|
||||
|
||||
$view->invokeWillRenderEvent();
|
||||
|
@ -211,8 +208,10 @@ final class PhabricatorOwnersDetailController
|
|||
private function buildPackageActionView(PhabricatorOwnersPackage $package) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
// TODO: Implement this capability.
|
||||
$can_edit = true;
|
||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||
$viewer,
|
||||
$package,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
|
||||
$id = $package->getID();
|
||||
$edit_uri = $this->getApplicationURI("/edit/{$id}/");
|
||||
|
|
|
@ -12,8 +12,7 @@ final class PhabricatorOwnersPathsController
|
|||
->requireCapabilities(
|
||||
array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
// TODO: Support this capability.
|
||||
// PhabricatorPolicyCapability::CAN_EDIT,
|
||||
PhabricatorPolicyCapability::CAN_EDIT,
|
||||
))
|
||||
->needPaths(true)
|
||||
->executeOne();
|
||||
|
|
|
@ -21,6 +21,9 @@ final class PhabricatorOwnersPackageTransactionEditor
|
|||
$types[] = PhabricatorOwnersPackageTransaction::TYPE_PATHS;
|
||||
$types[] = PhabricatorOwnersPackageTransaction::TYPE_STATUS;
|
||||
|
||||
$types[] = PhabricatorTransactions::TYPE_VIEW_POLICY;
|
||||
$types[] = PhabricatorTransactions::TYPE_EDIT_POLICY;
|
||||
|
||||
return $types;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,8 @@ final class PhabricatorOwnersPackage
|
|||
protected $primaryOwnerPHID;
|
||||
protected $mailKey;
|
||||
protected $status;
|
||||
protected $viewPolicy;
|
||||
protected $editPolicy;
|
||||
|
||||
private $paths = self::ATTACHABLE;
|
||||
private $owners = self::ATTACHABLE;
|
||||
|
@ -27,8 +29,20 @@ final class PhabricatorOwnersPackage
|
|||
const STATUS_ARCHIVED = 'archived';
|
||||
|
||||
public static function initializeNewPackage(PhabricatorUser $actor) {
|
||||
$app = id(new PhabricatorApplicationQuery())
|
||||
->setViewer($actor)
|
||||
->withClasses(array('PhabricatorOwnersApplication'))
|
||||
->executeOne();
|
||||
|
||||
$view_policy = $app->getPolicy(
|
||||
PhabricatorOwnersDefaultViewCapability::CAPABILITY);
|
||||
$edit_policy = $app->getPolicy(
|
||||
PhabricatorOwnersDefaultEditCapability::CAPABILITY);
|
||||
|
||||
return id(new PhabricatorOwnersPackage())
|
||||
->setAuditingEnabled(0)
|
||||
->setViewPolicy($view_policy)
|
||||
->setEditPolicy($edit_policy)
|
||||
->attachPaths(array())
|
||||
->setStatus(self::STATUS_ACTIVE)
|
||||
->attachOwners(array())
|
||||
|
@ -287,8 +301,12 @@ final class PhabricatorOwnersPackage
|
|||
}
|
||||
|
||||
public function getPolicy($capability) {
|
||||
// TODO: Implement proper policies.
|
||||
return PhabricatorPolicies::POLICY_USER;
|
||||
switch ($capability) {
|
||||
case PhabricatorPolicyCapability::CAN_VIEW:
|
||||
return $this->getViewPolicy();
|
||||
case PhabricatorPolicyCapability::CAN_EDIT:
|
||||
return $this->getEditPolicy();
|
||||
}
|
||||
}
|
||||
|
||||
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
|
||||
|
|
|
@ -56,9 +56,11 @@ final class PhabricatorPeopleProfileViewController
|
|||
|
||||
$projects = $this->buildProjectsView($user);
|
||||
$badges = $this->buildBadgesView($user);
|
||||
require_celerity_resource('project-view-css');
|
||||
|
||||
$columns = id(new PHUITwoColumnView())
|
||||
->addClass('project-view-badges')
|
||||
$home = id(new PHUITwoColumnView())
|
||||
->setHeader($header)
|
||||
->addClass('project-view-home')
|
||||
->setMainColumn(
|
||||
array(
|
||||
$properties,
|
||||
|
@ -76,17 +78,6 @@ final class PhabricatorPeopleProfileViewController
|
|||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->setBorder(true);
|
||||
|
||||
require_celerity_resource('project-view-css');
|
||||
$home = phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'project-view-home',
|
||||
),
|
||||
array(
|
||||
$header,
|
||||
$columns,
|
||||
));
|
||||
|
||||
return $this->newPage()
|
||||
->setTitle($user->getUsername())
|
||||
->setNavigation($nav)
|
||||
|
@ -115,7 +106,7 @@ final class PhabricatorPeopleProfileViewController
|
|||
}
|
||||
|
||||
$view = id(new PHUIBoxView())
|
||||
->setColor(PHUIBoxView::GREY)
|
||||
->setBorder(true)
|
||||
->appendChild($view)
|
||||
->addClass('project-view-properties');
|
||||
|
||||
|
@ -174,7 +165,7 @@ final class PhabricatorPeopleProfileViewController
|
|||
$box = id(new PHUIObjectBoxView())
|
||||
->setHeader($header)
|
||||
->appendChild($list)
|
||||
->setBackground(PHUIBoxView::GREY);
|
||||
->setBackground(PHUIObjectBoxView::GREY);
|
||||
|
||||
return $box;
|
||||
}
|
||||
|
@ -217,8 +208,9 @@ final class PhabricatorPeopleProfileViewController
|
|||
|
||||
$box = id(new PHUIObjectBoxView())
|
||||
->setHeaderText(pht('Badges'))
|
||||
->addClass('project-view-badges')
|
||||
->appendChild($flex)
|
||||
->setBackground(PHUIBoxView::GREY);
|
||||
->setBackground(PHUIObjectBoxView::GREY);
|
||||
|
||||
return $box;
|
||||
}
|
||||
|
|
|
@ -118,10 +118,7 @@ final class PhameBlogManageController extends PhameBlogController {
|
|||
$properties->invokeWillRenderEvent();
|
||||
|
||||
if (strlen($blog->getDescription())) {
|
||||
$description = PhabricatorMarkupEngine::renderOneObject(
|
||||
id(new PhabricatorMarkupOneOff())->setContent($blog->getDescription()),
|
||||
'default',
|
||||
$viewer);
|
||||
$description = new PHUIRemarkupView($viewer, $description);
|
||||
$properties->addSectionHeader(
|
||||
pht('Description'),
|
||||
PHUIPropertyListView::ICON_SUMMARY);
|
||||
|
|
|
@ -44,16 +44,7 @@ final class PhameBlogViewController extends PhameLiveController {
|
|||
$header->setStatus($header_icon, $header_color, $header_name);
|
||||
|
||||
$actions = $this->renderActions($blog);
|
||||
$action_button = id(new PHUIButtonView())
|
||||
->setTag('a')
|
||||
->setText(pht('Actions'))
|
||||
->setHref('#')
|
||||
->setIcon('fa-bars')
|
||||
->addClass('phui-mobile-menu')
|
||||
->setDropdownMenu($actions);
|
||||
|
||||
$header->addActionLink($action_button);
|
||||
|
||||
$header->setActionList($actions);
|
||||
$header->setPolicyObject($blog);
|
||||
}
|
||||
|
||||
|
|
|
@ -24,17 +24,8 @@ final class PhamePostViewController
|
|||
|
||||
if (!$is_external) {
|
||||
$actions = $this->renderActions($post);
|
||||
|
||||
$action_button = id(new PHUIButtonView())
|
||||
->setTag('a')
|
||||
->setText(pht('Actions'))
|
||||
->setHref('#')
|
||||
->setIcon('fa-bars')
|
||||
->addClass('phui-mobile-menu')
|
||||
->setDropdownMenu($actions);
|
||||
|
||||
$header->setPolicyObject($post);
|
||||
$header->addActionLink($action_button);
|
||||
$header->setActionList($actions);
|
||||
}
|
||||
|
||||
$document = id(new PHUIDocumentViewPro())
|
||||
|
|
|
@ -52,6 +52,13 @@ final class PHUIHandleTagListView extends AphrontTagView {
|
|||
protected function getTagContent() {
|
||||
$handles = $this->handles;
|
||||
|
||||
// Remove any archived projects from the list.
|
||||
foreach ($handles as $key => $handle) {
|
||||
if ($handle->getStatus() == PhabricatorObjectHandle::STATUS_CLOSED) {
|
||||
unset($handles[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
// If the list is empty, we may render a "No Projects" tag.
|
||||
if (!$handles) {
|
||||
if (strlen($this->noDataString)) {
|
||||
|
|
|
@ -86,16 +86,13 @@ final class PholioInlineController extends PholioController {
|
|||
),
|
||||
$author_handle->renderLink());
|
||||
|
||||
$inline_content = new PHUIRemarkupView($viewer, $inline->getContent());
|
||||
$comment_body = phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'pholio-inline-comment-body',
|
||||
),
|
||||
PhabricatorMarkupEngine::renderOneObject(
|
||||
id(new PhabricatorMarkupOneOff())
|
||||
->setContent($inline->getContent()),
|
||||
'default',
|
||||
$viewer));
|
||||
$inline_content);
|
||||
|
||||
return $this->newDialog()
|
||||
->setTitle(pht('Inline Comment'))
|
||||
|
|
|
@ -48,12 +48,7 @@ abstract class PhortuneCartController
|
|||
return null;
|
||||
}
|
||||
|
||||
$output = PhabricatorMarkupEngine::renderOneObject(
|
||||
id(new PhabricatorMarkupOneOff())
|
||||
->setPreserveLinebreaks(true)
|
||||
->setContent($description),
|
||||
'default',
|
||||
$this->getViewer());
|
||||
$output = new PHUIRemarkupView($this->getUser(), $description);
|
||||
|
||||
$box = id(new PHUIBoxView())
|
||||
->addMargin(PHUI::MARGIN_LARGE)
|
||||
|
|
|
@ -136,11 +136,7 @@ final class PhortuneMerchantViewController
|
|||
|
||||
$description = $merchant->getDescription();
|
||||
if (strlen($description)) {
|
||||
$description = PhabricatorMarkupEngine::renderOneObject(
|
||||
id(new PhabricatorMarkupOneOff())->setContent($description),
|
||||
'default',
|
||||
$viewer);
|
||||
|
||||
$description = new PHUIRemarkupView($viewer, $description);
|
||||
$view->addSectionHeader(
|
||||
pht('Description'), PHUIPropertyListView::ICON_SUMMARY);
|
||||
$view->addTextContent($description);
|
||||
|
|
|
@ -203,19 +203,11 @@ final class PhrictionDocumentController
|
|||
$crumbs->addCrumb($view);
|
||||
}
|
||||
|
||||
$action_button = id(new PHUIButtonView())
|
||||
->setTag('a')
|
||||
->setText(pht('Actions'))
|
||||
->setHref('#')
|
||||
->setIcon('fa-bars')
|
||||
->addClass('phui-mobile-menu')
|
||||
->setDropdownMenu($actions);
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setUser($viewer)
|
||||
->setPolicyObject($document)
|
||||
->setHeader($page_title)
|
||||
->addActionLink($action_button);
|
||||
->setActionList($actions);
|
||||
|
||||
if ($content) {
|
||||
$header->setEpoch($content->getDateCreated());
|
||||
|
|
|
@ -134,16 +134,12 @@ final class PhabricatorPhurlURLViewController
|
|||
|
||||
$properties->invokeWillRenderEvent();
|
||||
|
||||
if (strlen($url->getDescription())) {
|
||||
$description = PhabricatorMarkupEngine::renderOneObject(
|
||||
id(new PhabricatorMarkupOneOff())->setContent($url->getDescription()),
|
||||
'default',
|
||||
$viewer);
|
||||
|
||||
$description = $url->getDescription();
|
||||
if (strlen($description)) {
|
||||
$description = new PHUIRemarkupView($viewer, $description);
|
||||
$properties->addSectionHeader(
|
||||
pht('Description'),
|
||||
PHUIPropertyListView::ICON_SUMMARY);
|
||||
|
||||
$properties->addTextContent($description);
|
||||
}
|
||||
|
||||
|
|
|
@ -101,6 +101,9 @@ final class PhabricatorPolicyEditEngineExtension
|
|||
if ($capability == PhabricatorPolicyCapability::CAN_VIEW) {
|
||||
$type_space = PhabricatorTransactions::TYPE_SPACE;
|
||||
if (isset($types[$type_space])) {
|
||||
$space_phid = PhabricatorSpacesNamespaceQuery::getObjectSpacePHID(
|
||||
$object);
|
||||
|
||||
$space_field = id(new PhabricatorSpaceEditField())
|
||||
->setKey('spacePHID')
|
||||
->setLabel(pht('Space'))
|
||||
|
@ -114,7 +117,7 @@ final class PhabricatorPolicyEditEngineExtension
|
|||
->setConduitDescription(
|
||||
pht('Shift the object between spaces.'))
|
||||
->setConduitTypeDescription(pht('New space PHID.'))
|
||||
->setValue($object->getSpacePHID());
|
||||
->setValue($space_phid);
|
||||
$fields[] = $space_field;
|
||||
|
||||
$space_field->setPolicyField($policy_field);
|
||||
|
|
|
@ -44,7 +44,6 @@ final class PonderQuestionViewController extends PonderController {
|
|||
|
||||
$actions = $this->buildActionListView($question);
|
||||
$properties = $this->buildPropertyListView($question, $actions);
|
||||
$sidebar = $this->buildSidebar($question);
|
||||
|
||||
$content_id = celerity_generate_unique_node_id();
|
||||
$timeline = $this->buildTransactionTimeline(
|
||||
|
@ -81,20 +80,6 @@ final class PonderQuestionViewController extends PonderController {
|
|||
->addPropertyList($properties)
|
||||
->appendChild($footer);
|
||||
|
||||
if ($viewer->getPHID() == $question->getAuthorPHID()) {
|
||||
$status = $question->getStatus();
|
||||
$answers_list = $question->getAnswers();
|
||||
if ($answers_list && ($status == PonderQuestionStatus::STATUS_OPEN)) {
|
||||
$info_view = id(new PHUIInfoView())
|
||||
->setSeverity(PHUIInfoView::SEVERITY_WARNING)
|
||||
->appendChild(
|
||||
pht(
|
||||
'If this question has been resolved, please consider closing
|
||||
the question and marking the answer as helpful.'));
|
||||
$object_box->setInfoView($info_view);
|
||||
}
|
||||
}
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs($this->buildSideNavView());
|
||||
$crumbs->addTextCrumb('Q'.$id, '/Q'.$id);
|
||||
|
||||
|
@ -107,21 +92,14 @@ final class PonderQuestionViewController extends PonderController {
|
|||
->appendChild($answer);
|
||||
}
|
||||
|
||||
$ponder_view = id(new PHUITwoColumnView())
|
||||
->setMainColumn(array(
|
||||
$object_box,
|
||||
$comment_view,
|
||||
$answer_wiki,
|
||||
$answers,
|
||||
$answer_add_panel,
|
||||
))
|
||||
->setSideColumn($sidebar)
|
||||
->addClass('ponder-question-view');
|
||||
|
||||
return $this->buildApplicationPage(
|
||||
array(
|
||||
$crumbs,
|
||||
$ponder_view,
|
||||
$object_box,
|
||||
$comment_view,
|
||||
$answer_wiki,
|
||||
$answers,
|
||||
$answer_add_panel,
|
||||
),
|
||||
array(
|
||||
'title' => 'Q'.$question->getID().' '.$question->getTitle(),
|
||||
|
@ -261,48 +239,4 @@ final class PonderQuestionViewController extends PonderController {
|
|||
return $view;
|
||||
}
|
||||
|
||||
private function buildSidebar(PonderQuestion $question) {
|
||||
$viewer = $this->getViewer();
|
||||
$status = $question->getStatus();
|
||||
$id = $question->getID();
|
||||
|
||||
$questions = id(new PonderQuestionQuery())
|
||||
->setViewer($viewer)
|
||||
->withStatuses(array($status))
|
||||
->withEdgeLogicPHIDs(
|
||||
PhabricatorProjectObjectHasProjectEdgeType::EDGECONST,
|
||||
PhabricatorQueryConstraint::OPERATOR_OR,
|
||||
$question->getProjectPHIDs())
|
||||
->setLimit(10)
|
||||
->execute();
|
||||
|
||||
$list = id(new PHUIObjectItemListView())
|
||||
->setUser($viewer)
|
||||
->setNoDataString(pht('No similar questions found.'));
|
||||
|
||||
foreach ($questions as $question) {
|
||||
if ($id == $question->getID()) {
|
||||
continue;
|
||||
}
|
||||
$item = new PHUIObjectItemView();
|
||||
$item->setObjectName('Q'.$question->getID());
|
||||
$item->setHeader($question->getTitle());
|
||||
$item->setHref('/Q'.$question->getID());
|
||||
$item->setObject($question);
|
||||
|
||||
$item->addAttribute(
|
||||
pht(
|
||||
'%s Answer(s)',
|
||||
new PhutilNumber($question->getAnswerCount())));
|
||||
|
||||
$list->addItem($item);
|
||||
}
|
||||
|
||||
$box = id(new PHUIObjectBoxView())
|
||||
->setHeaderText(pht('Similar Questions'))
|
||||
->setObjectList($list);
|
||||
|
||||
return $box;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1013,6 +1013,51 @@ final class PhabricatorProjectCoreTestCase extends PhabricatorTestCase {
|
|||
$this->assertColumns($expect, $user, $board, $task);
|
||||
}
|
||||
|
||||
public function testColumnExtendedPolicies() {
|
||||
$user = $this->createUser();
|
||||
$user->save();
|
||||
|
||||
$board = $this->createProject($user);
|
||||
$column = $this->addColumn($user, $board, 0);
|
||||
|
||||
// At first, the user should be able to view and edit the column.
|
||||
$column = $this->refreshColumn($user, $column);
|
||||
$this->assertTrue((bool)$column);
|
||||
|
||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||
$user,
|
||||
$column,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
$this->assertTrue($can_edit);
|
||||
|
||||
// Now, set the project edit policy to "Members of Project". This should
|
||||
// disable editing.
|
||||
$members_policy = id(new PhabricatorProjectMembersPolicyRule())
|
||||
->getObjectPolicyFullKey();
|
||||
$board->setEditPolicy($members_policy)->save();
|
||||
|
||||
$column = $this->refreshColumn($user, $column);
|
||||
$this->assertTrue((bool)$column);
|
||||
|
||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||
$user,
|
||||
$column,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
$this->assertFalse($can_edit);
|
||||
|
||||
// Now, join the project. This should make the column editable again.
|
||||
$this->joinProject($board, $user);
|
||||
|
||||
$column = $this->refreshColumn($user, $column);
|
||||
$this->assertTrue((bool)$column);
|
||||
|
||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||
$user,
|
||||
$column,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
$this->assertTrue($can_edit);
|
||||
}
|
||||
|
||||
private function moveToColumn(
|
||||
PhabricatorUser $viewer,
|
||||
PhabricatorProject $board,
|
||||
|
@ -1251,6 +1296,22 @@ final class PhabricatorProjectCoreTestCase extends PhabricatorTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
private function refreshColumn(
|
||||
PhabricatorUser $viewer,
|
||||
PhabricatorProjectColumn $column) {
|
||||
|
||||
$results = id(new PhabricatorProjectColumnQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($column->getID()))
|
||||
->execute();
|
||||
|
||||
if ($results) {
|
||||
return head($results);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private function createProject(
|
||||
PhabricatorUser $user,
|
||||
PhabricatorProject $parent = null,
|
||||
|
|
|
@ -84,6 +84,10 @@ final class PhabricatorProjectApplication extends PhabricatorApplication {
|
|||
=> 'PhabricatorProjectBoardReorderController',
|
||||
'disable/'
|
||||
=> 'PhabricatorProjectBoardDisableController',
|
||||
'manage/'
|
||||
=> 'PhabricatorProjectBoardManageController',
|
||||
'background/'
|
||||
=> 'PhabricatorProjectBoardBackgroundController',
|
||||
),
|
||||
'update/(?P<id>[1-9]\d*)/(?P<action>[^/]+)/'
|
||||
=> 'PhabricatorProjectUpdateController',
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorProjectWorkboardBackgroundColor extends Phobject {
|
||||
|
||||
public static function getOptions() {
|
||||
$options = array(
|
||||
array(
|
||||
'key' => '',
|
||||
'name' => pht('Use Parent Background (Default)'),
|
||||
'special' => 'parent',
|
||||
'icon' => 'fa-chevron-circle-up',
|
||||
'group' => 'basic',
|
||||
),
|
||||
array(
|
||||
'key' => 'none',
|
||||
'name' => pht('No Background'),
|
||||
'special' => 'none',
|
||||
'icon' => 'fa-ban',
|
||||
'group' => 'basic',
|
||||
),
|
||||
array(
|
||||
'key' => 'red',
|
||||
'name' => pht('Red'),
|
||||
),
|
||||
array(
|
||||
'key' => 'orange',
|
||||
'name' => pht('Orange'),
|
||||
),
|
||||
array(
|
||||
'key' => 'yellow',
|
||||
'name' => pht('Yellow'),
|
||||
),
|
||||
array(
|
||||
'key' => 'green',
|
||||
'name' => pht('Green'),
|
||||
),
|
||||
array(
|
||||
'key' => 'blue',
|
||||
'name' => pht('Blue'),
|
||||
),
|
||||
array(
|
||||
'key' => 'indigo',
|
||||
'name' => pht('Indigo'),
|
||||
),
|
||||
array(
|
||||
'key' => 'violet',
|
||||
'name' => pht('Violet'),
|
||||
),
|
||||
array(
|
||||
'key' => 'sky',
|
||||
'name' => pht('Sky'),
|
||||
),
|
||||
array(
|
||||
'key' => 'pink',
|
||||
'name' => pht('Pink'),
|
||||
),
|
||||
array(
|
||||
'key' => 'fire',
|
||||
'name' => pht('Fire'),
|
||||
),
|
||||
array(
|
||||
'key' => 'grey',
|
||||
'name' => pht('Grey'),
|
||||
),
|
||||
array(
|
||||
'key' => 'gradient-red',
|
||||
'name' => pht('Ripe Peach'),
|
||||
),
|
||||
array(
|
||||
'key' => 'gradient-orange',
|
||||
'name' => pht('Ripe Orange'),
|
||||
),
|
||||
array(
|
||||
'key' => 'gradient-yellow',
|
||||
'name' => pht('Ripe Mango'),
|
||||
),
|
||||
array(
|
||||
'key' => 'gradient-green',
|
||||
'name' => pht('Shallows'),
|
||||
),
|
||||
array(
|
||||
'key' => 'gradient-blue',
|
||||
'name' => pht('Reef'),
|
||||
),
|
||||
array(
|
||||
'key' => 'gradient-bluegrey',
|
||||
'name' => pht('Depths'),
|
||||
),
|
||||
array(
|
||||
'key' => 'gradient-indigo',
|
||||
'name' => pht('This One Is Purple'),
|
||||
),
|
||||
array(
|
||||
'key' => 'gradient-violet',
|
||||
'name' => pht('Unripe Plum'),
|
||||
),
|
||||
array(
|
||||
'key' => 'gradient-sky',
|
||||
'name' => pht('Blue Sky'),
|
||||
),
|
||||
array(
|
||||
'key' => 'gradient-pink',
|
||||
'name' => pht('Intensity'),
|
||||
),
|
||||
array(
|
||||
'key' => 'gradient-grey',
|
||||
'name' => pht('Into The Expanse'),
|
||||
),
|
||||
);
|
||||
|
||||
foreach ($options as $key => $option) {
|
||||
if (empty($option['group'])) {
|
||||
if (preg_match('/^gradient/', $option['key'])) {
|
||||
$option['group'] = 'gradient';
|
||||
} else {
|
||||
$option['group'] = 'solid';
|
||||
}
|
||||
}
|
||||
$options[$key] = $option;
|
||||
}
|
||||
|
||||
return ipull($options, null, 'key');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,168 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorProjectBoardBackgroundController
|
||||
extends PhabricatorProjectBoardController {
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $request->getUser();
|
||||
$board_id = $request->getURIData('projectID');
|
||||
|
||||
$board = id(new PhabricatorProjectQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($board_id))
|
||||
->needImages(true)
|
||||
->requireCapabilities(
|
||||
array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
PhabricatorPolicyCapability::CAN_EDIT,
|
||||
))
|
||||
->executeOne();
|
||||
if (!$board) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
if (!$board->getHasWorkboard()) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$this->setProject($board);
|
||||
$id = $board->getID();
|
||||
|
||||
$manage_uri = $this->getApplicationURI("board/{$id}/manage/");
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
$background_key = $request->getStr('backgroundKey');
|
||||
|
||||
$xactions = array();
|
||||
|
||||
$xactions[] = id(new PhabricatorProjectTransaction())
|
||||
->setTransactionType(PhabricatorProjectTransaction::TYPE_BACKGROUND)
|
||||
->setNewValue($background_key);
|
||||
|
||||
id(new PhabricatorProjectTransactionEditor())
|
||||
->setActor($viewer)
|
||||
->setContentSourceFromRequest($request)
|
||||
->setContinueOnNoEffect(true)
|
||||
->setContinueOnMissingFields(true)
|
||||
->applyTransactions($board, $xactions);
|
||||
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI($manage_uri);
|
||||
}
|
||||
|
||||
$nav = $this->getProfileMenu();
|
||||
|
||||
$crumbs = id($this->buildApplicationCrumbs())
|
||||
->addTextCrumb(pht('Workboard'), "/project/board/{$board_id}/")
|
||||
->addTextCrumb(pht('Manage'), $manage_uri)
|
||||
->addTextCrumb(pht('Background Color'));
|
||||
|
||||
$form = id(new AphrontFormView())
|
||||
->setUser($viewer);
|
||||
|
||||
$group_info = array(
|
||||
'basic' => array(
|
||||
'label' => pht('Basics'),
|
||||
),
|
||||
'solid' => array(
|
||||
'label' => pht('Solid Colors'),
|
||||
),
|
||||
'gradient' => array(
|
||||
'label' => pht('Gradients'),
|
||||
),
|
||||
);
|
||||
|
||||
$groups = array();
|
||||
$options = PhabricatorProjectWorkboardBackgroundColor::getOptions();
|
||||
$option_groups = igroup($options, 'group');
|
||||
|
||||
require_celerity_resource('people-profile-css');
|
||||
require_celerity_resource('phui-workboard-color-css');
|
||||
Javelin::initBehavior('phabricator-tooltips', array());
|
||||
|
||||
foreach ($group_info as $group_key => $spec) {
|
||||
$buttons = array();
|
||||
|
||||
$available_options = idx($option_groups, $group_key, array());
|
||||
foreach ($available_options as $option) {
|
||||
$buttons[] = $this->renderOptionButton($option);
|
||||
}
|
||||
|
||||
$form->appendControl(
|
||||
id(new AphrontFormMarkupControl())
|
||||
->setLabel($spec['label'])
|
||||
->setValue($buttons));
|
||||
}
|
||||
|
||||
// NOTE: Each button is its own form, so we can't wrap them in a normal
|
||||
// form.
|
||||
$layout_view = $form->buildLayoutView();
|
||||
|
||||
$form_box = id(new PHUIObjectBoxView())
|
||||
->setHeaderText(pht('Edit Background Color'))
|
||||
->appendChild($layout_view);
|
||||
|
||||
return $this->newPage()
|
||||
->setTitle(
|
||||
array(
|
||||
pht('Edit Background Color'),
|
||||
$board->getDisplayName(),
|
||||
))
|
||||
->setCrumbs($crumbs)
|
||||
->setNavigation($nav)
|
||||
->appendChild($form_box);
|
||||
}
|
||||
|
||||
private function renderOptionButton(array $option) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$icon = idx($option, 'icon');
|
||||
if ($icon) {
|
||||
$preview_class = null;
|
||||
$preview_content = id(new PHUIIconView())
|
||||
->setIcon($icon, 'lightbluetext');
|
||||
} else {
|
||||
$preview_class = 'phui-workboard-'.$option['key'];
|
||||
$preview_content = null;
|
||||
}
|
||||
|
||||
$preview = phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'phui-workboard-color-preview '.$preview_class,
|
||||
),
|
||||
$preview_content);
|
||||
|
||||
$button = javelin_tag(
|
||||
'button',
|
||||
array(
|
||||
'class' => 'grey profile-image-button',
|
||||
'sigil' => 'has-tooltip',
|
||||
'meta' => array(
|
||||
'tip' => $option['name'],
|
||||
'size' => 300,
|
||||
),
|
||||
),
|
||||
$preview);
|
||||
|
||||
$input = phutil_tag(
|
||||
'input',
|
||||
array(
|
||||
'type' => 'hidden',
|
||||
'name' => 'backgroundKey',
|
||||
'value' => $option['key'],
|
||||
));
|
||||
|
||||
return phabricator_form(
|
||||
$viewer,
|
||||
array(
|
||||
'class' => 'profile-image-form',
|
||||
'method' => 'POST',
|
||||
),
|
||||
array(
|
||||
$button,
|
||||
$input,
|
||||
));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,174 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorProjectBoardManageController
|
||||
extends PhabricatorProjectBoardController {
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $request->getViewer();
|
||||
$board_id = $request->getURIData('projectID');
|
||||
|
||||
$board = id(new PhabricatorProjectQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($board_id))
|
||||
->needImages(true)
|
||||
->executeOne();
|
||||
if (!$board) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
$this->setProject($board);
|
||||
|
||||
// Perform layout of no tasks to load and populate the columns in the
|
||||
// correct order.
|
||||
$layout_engine = id(new PhabricatorBoardLayoutEngine())
|
||||
->setViewer($viewer)
|
||||
->setBoardPHIDs(array($board->getPHID()))
|
||||
->setObjectPHIDs(array())
|
||||
->setFetchAllBoards(true)
|
||||
->executeLayout();
|
||||
|
||||
$columns = $layout_engine->getColumns($board->getPHID());
|
||||
|
||||
$board_id = $board->getID();
|
||||
|
||||
$header = $this->buildHeaderView($board);
|
||||
$actions = $this->buildActionView($board);
|
||||
$properties = $this->buildPropertyView($board);
|
||||
|
||||
$properties->setActionList($actions);
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->addTextCrumb(pht('Workboard'), "/project/board/{$board_id}/");
|
||||
$crumbs->addTextCrumb(pht('Manage'));
|
||||
|
||||
$box = id(new PHUIObjectBoxView())
|
||||
->setHeader($header)
|
||||
->addPropertyList($properties);
|
||||
|
||||
$nav = $this->getProfileMenu();
|
||||
|
||||
$title = array(
|
||||
pht('Manage Workboard'),
|
||||
$board->getDisplayName(),
|
||||
);
|
||||
|
||||
$columns_list = $this->buildColumnsList($board, $columns);
|
||||
|
||||
return $this->newPage()
|
||||
->setTitle($title)
|
||||
->setNavigation($nav)
|
||||
->setCrumbs($crumbs)
|
||||
->appendChild(
|
||||
array(
|
||||
$box,
|
||||
$columns_list,
|
||||
));
|
||||
}
|
||||
|
||||
private function buildHeaderView(PhabricatorProject $board) {
|
||||
$viewer = $this->getRequest()->getUser();
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setUser($viewer)
|
||||
->setHeader(pht('Workboard: %s', $board->getDisplayName()));
|
||||
|
||||
return $header;
|
||||
}
|
||||
|
||||
private function buildActionView(PhabricatorProject $board) {
|
||||
$viewer = $this->getRequest()->getUser();
|
||||
$id = $board->getID();
|
||||
|
||||
$actions = id(new PhabricatorActionListView())
|
||||
->setUser($viewer);
|
||||
|
||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||
$viewer,
|
||||
$board,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
|
||||
$reorder_uri = $this->getApplicationURI("board/{$id}/reorder/");
|
||||
|
||||
$actions->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setIcon('fa-exchange')
|
||||
->setName(pht('Reorder Columns'))
|
||||
->setHref($reorder_uri)
|
||||
->setDisabled(!$can_edit)
|
||||
->setWorkflow(true));
|
||||
|
||||
$background_uri = $this->getApplicationURI("board/{$id}/background/");
|
||||
|
||||
$actions->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setIcon('fa-paint-brush')
|
||||
->setName(pht('Change Background Color'))
|
||||
->setHref($background_uri)
|
||||
->setDisabled(!$can_edit)
|
||||
->setWorkflow(!$can_edit));
|
||||
|
||||
$disable_uri = $this->getApplicationURI("board/{$id}/disable/");
|
||||
|
||||
$actions->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setIcon('fa-ban')
|
||||
->setName(pht('Disable Board'))
|
||||
->setHref($disable_uri)
|
||||
->setDisabled(!$can_edit)
|
||||
->setWorkflow(true));
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
private function buildPropertyView(
|
||||
PhabricatorProject $board) {
|
||||
$viewer = $this->getRequest()->getUser();
|
||||
|
||||
$properties = id(new PHUIPropertyListView())
|
||||
->setUser($viewer)
|
||||
->setObject($board);
|
||||
|
||||
$background = $board->getDisplayWorkboardBackgroundColor();
|
||||
if ($background !== null) {
|
||||
$map = PhabricatorProjectWorkboardBackgroundColor::getOptions();
|
||||
$map = ipull($map, 'name');
|
||||
|
||||
$name = idx($map, $background, $background);
|
||||
$properties->addProperty(pht('Background Color'), $name);
|
||||
}
|
||||
|
||||
return $properties;
|
||||
}
|
||||
|
||||
private function buildColumnsList(
|
||||
PhabricatorProject $board,
|
||||
array $columns) {
|
||||
assert_instances_of($columns, 'PhabricatorProjectColumn');
|
||||
|
||||
$board_id = $board->getID();
|
||||
|
||||
$view = id(new PHUIObjectItemListView())
|
||||
->setNoDataString(pht('This board has no columns.'));
|
||||
|
||||
foreach ($columns as $column) {
|
||||
$column_id = $column->getID();
|
||||
|
||||
$detail_uri = "/project/board/{$board_id}/column/{$column_id}/";
|
||||
|
||||
$item = id(new PHUIObjectItemView())
|
||||
->setHeader($column->getDisplayName())
|
||||
->setHref($detail_uri);
|
||||
|
||||
if ($column->isHidden()) {
|
||||
$item->setDisabled(true);
|
||||
}
|
||||
|
||||
$view->addItem($item);
|
||||
}
|
||||
|
||||
return id(new PHUIObjectBoxView())
|
||||
->setHeaderText(pht('Columns'))
|
||||
->setObjectList($view);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -23,13 +23,13 @@ final class PhabricatorProjectBoardReorderController
|
|||
$this->setProject($project);
|
||||
$project_id = $project->getID();
|
||||
|
||||
$board_uri = $this->getApplicationURI("board/{$project_id}/");
|
||||
$manage_uri = $this->getApplicationURI("board/{$project_id}/manage/");
|
||||
$reorder_uri = $this->getApplicationURI("board/{$project_id}/reorder/");
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
// User clicked "Done", make sure the page reloads to show the new
|
||||
// column order.
|
||||
return id(new AphrontRedirectResponse())->setURI($board_uri);
|
||||
return id(new AphrontRedirectResponse())->setURI($manage_uri);
|
||||
}
|
||||
|
||||
$columns = id(new PhabricatorProjectColumnQuery())
|
||||
|
|
|
@ -124,10 +124,14 @@ final class PhabricatorProjectBoardViewController
|
|||
|
||||
$board_phid = $project->getPHID();
|
||||
|
||||
// Regardless of display order, pass tasks to the layout engine in ID order
|
||||
// so layout is consistent.
|
||||
$board_tasks = msort($tasks, 'getID');
|
||||
|
||||
$layout_engine = id(new PhabricatorBoardLayoutEngine())
|
||||
->setViewer($viewer)
|
||||
->setBoardPHIDs(array($board_phid))
|
||||
->setObjectPHIDs(array_keys($tasks))
|
||||
->setObjectPHIDs(array_keys($board_tasks))
|
||||
->setFetchAllBoards(true)
|
||||
->executeLayout();
|
||||
|
||||
|
@ -427,7 +431,7 @@ final class PhabricatorProjectBoardViewController
|
|||
$crumbs->addAction($manage_menu);
|
||||
$crumbs->addAction($fullscreen);
|
||||
|
||||
return $this->newPage()
|
||||
$page = $this->newPage()
|
||||
->setTitle(
|
||||
array(
|
||||
$project->getDisplayName(),
|
||||
|
@ -445,6 +449,17 @@ final class PhabricatorProjectBoardViewController
|
|||
array(
|
||||
$board_box,
|
||||
));
|
||||
|
||||
$background = $project->getDisplayWorkboardBackgroundColor();
|
||||
if ($background !== null) {
|
||||
require_celerity_resource('phui-workboard-color-css');
|
||||
$background_color_class = "phui-workboard-{$background}";
|
||||
|
||||
$page->addClass('phui-workboard-color');
|
||||
$page->addClass($background_color_class);
|
||||
}
|
||||
|
||||
return $page;
|
||||
}
|
||||
|
||||
private function readRequestState() {
|
||||
|
@ -671,9 +686,8 @@ final class PhabricatorProjectBoardViewController
|
|||
|
||||
$id = $project->getID();
|
||||
|
||||
$disable_uri = $this->getApplicationURI("board/{$id}/disable/");
|
||||
$manage_uri = $this->getApplicationURI("board/{$id}/manage/");
|
||||
$add_uri = $this->getApplicationURI("board/{$id}/edit/");
|
||||
$reorder_uri = $this->getApplicationURI("board/{$id}/reorder/");
|
||||
|
||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||
$viewer,
|
||||
|
@ -687,14 +701,12 @@ final class PhabricatorProjectBoardViewController
|
|||
->setName(pht('Add Column'))
|
||||
->setHref($add_uri)
|
||||
->setDisabled(!$can_edit)
|
||||
->setWorkflow(!$can_edit);
|
||||
->setWorkflow(true);
|
||||
|
||||
$manage_items[] = id(new PhabricatorActionView())
|
||||
->setIcon('fa-exchange')
|
||||
->setName(pht('Reorder Columns'))
|
||||
->setHref($reorder_uri)
|
||||
->setDisabled(!$can_edit)
|
||||
->setWorkflow(true);
|
||||
->setIcon('fa-pencil')
|
||||
->setName(pht('Manage Board'))
|
||||
->setHref($manage_uri);
|
||||
|
||||
if ($show_hidden) {
|
||||
$hidden_uri = $this->getURIWithState()
|
||||
|
@ -726,13 +738,6 @@ final class PhabricatorProjectBoardViewController
|
|||
->setHref($batch_edit_uri)
|
||||
->setDisabled(!$can_batch_edit);
|
||||
|
||||
$manage_items[] = id(new PhabricatorActionView())
|
||||
->setIcon('fa-ban')
|
||||
->setName(pht('Disable Workboard'))
|
||||
->setHref($disable_uri)
|
||||
->setWorkflow(true)
|
||||
->setDisabled(!$can_edit);
|
||||
|
||||
$manage_menu = id(new PhabricatorActionListView())
|
||||
->setUser($viewer);
|
||||
foreach ($manage_items as $item) {
|
||||
|
@ -817,14 +822,6 @@ final class PhabricatorProjectBoardViewController
|
|||
->setHref($batch_edit_uri)
|
||||
->setDisabled(!$can_batch_edit);
|
||||
|
||||
$detail_uri = $this->getApplicationURI(
|
||||
'board/'.$this->id.'/column/'.$column->getID().'/');
|
||||
|
||||
$column_items[] = id(new PhabricatorActionView())
|
||||
->setIcon('fa-columns')
|
||||
->setName(pht('Column Details'))
|
||||
->setHref($detail_uri);
|
||||
|
||||
$can_hide = ($can_edit && !$column->isDefaultColumn());
|
||||
$hide_uri = 'board/'.$this->id.'/hide/'.$column->getID().'/';
|
||||
$hide_uri = $this->getApplicationURI($hide_uri);
|
||||
|
|
|
@ -73,8 +73,7 @@ final class PhabricatorProjectColumnDetailController
|
|||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setUser($viewer)
|
||||
->setHeader($column->getDisplayName())
|
||||
->setPolicyObject($column);
|
||||
->setHeader($column->getDisplayName());
|
||||
|
||||
if ($column->isHidden()) {
|
||||
$header->setStatus('fa-ban', 'dark', pht('Hidden'));
|
||||
|
|
|
@ -136,21 +136,13 @@ final class PhabricatorProjectColumnEditController
|
|||
$submit = pht('Save Column');
|
||||
}
|
||||
|
||||
$form->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->setValue($submit)
|
||||
->addCancelButton($view_uri));
|
||||
|
||||
$form_box = id(new PHUIObjectBoxView())
|
||||
->setHeaderText($title)
|
||||
->setValidationException($validation_exception)
|
||||
->setForm($form);
|
||||
|
||||
$nav = $this->getProfileMenu();
|
||||
|
||||
return $this->newPage()
|
||||
return $this->newDialog()
|
||||
->setWidth(AphrontDialogView::WIDTH_FORM)
|
||||
->setTitle($title)
|
||||
->setNavigation($nav)
|
||||
->appendChild($form_box);
|
||||
->appendForm($form)
|
||||
->setValidationException($validation_exception)
|
||||
->addCancelButton($view_uri)
|
||||
->addSubmitButton($submit);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,11 @@ final class PhabricatorProjectEditController
|
|||
|
||||
$id = $request->getURIData('id');
|
||||
if (!$id) {
|
||||
// This capability is checked again later, but checking it here
|
||||
// explicitly gives us a better error message.
|
||||
$this->requireApplicationCapability(
|
||||
ProjectCreateProjectsCapability::CAPABILITY);
|
||||
|
||||
$parent_id = head($request->getArr('parent'));
|
||||
if (!$parent_id) {
|
||||
$parent_id = $request->getStr('parent');
|
||||
|
|
|
@ -59,14 +59,14 @@ final class PhabricatorProjectProfileController
|
|||
->setUser($viewer)
|
||||
->setProject($project)
|
||||
->setLimit(5)
|
||||
->setBackground(PHUIBoxView::GREY)
|
||||
->setBackground(PHUIObjectBoxView::GREY)
|
||||
->setUserPHIDs($project->getMemberPHIDs());
|
||||
|
||||
$watcher_list = id(new PhabricatorProjectWatcherListView())
|
||||
->setUser($viewer)
|
||||
->setProject($project)
|
||||
->setLimit(5)
|
||||
->setBackground(PHUIBoxView::GREY)
|
||||
->setBackground(PHUIObjectBoxView::GREY)
|
||||
->setUserPHIDs($project->getWatcherPHIDs());
|
||||
|
||||
$nav = $this->getProfileMenu();
|
||||
|
@ -83,8 +83,11 @@ final class PhabricatorProjectProfileController
|
|||
|
||||
$feed = $this->renderStories($stories);
|
||||
$feed = phutil_tag_div('project-view-feed', $feed);
|
||||
require_celerity_resource('project-view-css');
|
||||
|
||||
$columns = id(new PHUITwoColumnView())
|
||||
$home = id(new PHUITwoColumnView())
|
||||
->setHeader($header)
|
||||
->addClass('project-view-home')
|
||||
->setMainColumn(
|
||||
array(
|
||||
$properties,
|
||||
|
@ -101,17 +104,6 @@ final class PhabricatorProjectProfileController
|
|||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->setBorder(true);
|
||||
|
||||
require_celerity_resource('project-view-css');
|
||||
$home = phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'project-view-home',
|
||||
),
|
||||
array(
|
||||
$header,
|
||||
$columns,
|
||||
));
|
||||
|
||||
return $this->newPage()
|
||||
->setNavigation($nav)
|
||||
->setCrumbs($crumbs)
|
||||
|
@ -142,7 +134,7 @@ final class PhabricatorProjectProfileController
|
|||
}
|
||||
|
||||
$view = id(new PHUIBoxView())
|
||||
->setColor(PHUIBoxView::GREY)
|
||||
->setBorder(true)
|
||||
->appendChild($view)
|
||||
->addClass('project-view-properties');
|
||||
|
||||
|
@ -162,19 +154,32 @@ final class PhabricatorProjectProfileController
|
|||
|
||||
private function renderWatchAction(PhabricatorProject $project) {
|
||||
$viewer = $this->getViewer();
|
||||
$viewer_phid = $viewer->getPHID();
|
||||
$id = $project->getID();
|
||||
|
||||
$is_watcher = ($viewer_phid && $project->isUserWatcher($viewer_phid));
|
||||
if (!$viewer->isLoggedIn()) {
|
||||
$is_watcher = false;
|
||||
$is_ancestor = false;
|
||||
} else {
|
||||
$viewer_phid = $viewer->getPHID();
|
||||
$is_watcher = $project->isUserWatcher($viewer_phid);
|
||||
$is_ancestor = $project->isUserAncestorWatcher($viewer_phid);
|
||||
}
|
||||
|
||||
if (!$is_watcher) {
|
||||
if ($is_ancestor && !$is_watcher) {
|
||||
$watch_icon = 'fa-eye';
|
||||
$watch_text = pht('Watching Ancestor');
|
||||
$watch_href = "/project/watch/{$id}/?via=profile";
|
||||
$watch_disabled = true;
|
||||
} else if (!$is_watcher) {
|
||||
$watch_icon = 'fa-eye';
|
||||
$watch_text = pht('Watch Project');
|
||||
$watch_href = "/project/watch/{$id}/?via=profile";
|
||||
$watch_disabled = false;
|
||||
} else {
|
||||
$watch_icon = 'fa-eye-slash';
|
||||
$watch_text = pht('Unwatch Project');
|
||||
$watch_href = "/project/unwatch/{$id}/?via=profile";
|
||||
$watch_disabled = false;
|
||||
}
|
||||
|
||||
$watch_icon = id(new PHUIIconView())
|
||||
|
@ -185,7 +190,8 @@ final class PhabricatorProjectProfileController
|
|||
->setWorkflow(true)
|
||||
->setIcon($watch_icon)
|
||||
->setText($watch_text)
|
||||
->setHref($watch_href);
|
||||
->setHref($watch_href)
|
||||
->setDisabled($watch_disabled);
|
||||
}
|
||||
|
||||
private function buildMilestoneList(PhabricatorProject $project) {
|
||||
|
@ -205,7 +211,7 @@ final class PhabricatorProjectProfileController
|
|||
array(
|
||||
PhabricatorProjectStatus::STATUS_ACTIVE,
|
||||
))
|
||||
->setOrder('newest')
|
||||
->setOrderVector(array('milestoneNumber', 'id'))
|
||||
->execute();
|
||||
if (!$milestones) {
|
||||
return null;
|
||||
|
@ -230,7 +236,7 @@ final class PhabricatorProjectProfileController
|
|||
|
||||
return id(new PHUIObjectBoxView())
|
||||
->setHeader($header)
|
||||
->setBackground(PHUIBoxView::GREY)
|
||||
->setBackground(PHUIObjectBoxView::GREY)
|
||||
->setObjectList($milestone_list);
|
||||
}
|
||||
|
||||
|
@ -278,7 +284,7 @@ final class PhabricatorProjectProfileController
|
|||
|
||||
return id(new PHUIObjectBoxView())
|
||||
->setHeader($header)
|
||||
->setBackground(PHUIBoxView::GREY)
|
||||
->setBackground(PHUIObjectBoxView::GREY)
|
||||
->setObjectList($subproject_list);
|
||||
}
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ final class PhabricatorProjectSubprojectsController
|
|||
->withParentProjectPHIDs(array($project->getPHID()))
|
||||
->needImages(true)
|
||||
->withIsMilestone(true)
|
||||
->setOrder('newest')
|
||||
->setOrderVector(array('milestoneNumber', 'id'))
|
||||
->execute();
|
||||
} else {
|
||||
$milestones = array();
|
||||
|
@ -181,6 +181,9 @@ final class PhabricatorProjectSubprojectsController
|
|||
$viewer = $this->getViewer();
|
||||
$id = $project->getID();
|
||||
|
||||
$can_create = $this->hasApplicationCapability(
|
||||
ProjectCreateProjectsCapability::CAPABILITY);
|
||||
|
||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||
$viewer,
|
||||
$project,
|
||||
|
@ -198,7 +201,7 @@ final class PhabricatorProjectSubprojectsController
|
|||
$milestone_text = pht('Create Milestone');
|
||||
}
|
||||
|
||||
$can_milestone = ($can_edit && $allows_milestones);
|
||||
$can_milestone = ($can_create && $can_edit && $allows_milestones);
|
||||
$milestone_href = "/project/edit/?milestone={$id}";
|
||||
|
||||
$view->addAction(
|
||||
|
@ -209,7 +212,7 @@ final class PhabricatorProjectSubprojectsController
|
|||
->setDisabled(!$can_milestone)
|
||||
->setWorkflow(!$can_milestone));
|
||||
|
||||
$can_subproject = ($can_edit && $allows_subprojects);
|
||||
$can_subproject = ($can_create && $can_edit && $allows_subprojects);
|
||||
|
||||
// If we're offering to create the first subproject, we're going to warn
|
||||
// the user about the effects before moving forward.
|
||||
|
|
|
@ -25,6 +25,23 @@ final class PhabricatorProjectWatchController
|
|||
$done_uri = "/project/members/{$id}/";
|
||||
}
|
||||
|
||||
$is_watcher = $project->isUserWatcher($viewer->getPHID());
|
||||
$is_ancestor = $project->isUserAncestorWatcher($viewer->getPHID());
|
||||
if ($is_ancestor && !$is_watcher) {
|
||||
$ancestor_phid = $project->getWatchedAncestorPHID($viewer->getPHID());
|
||||
$handles = $viewer->loadHandles(array($ancestor_phid));
|
||||
$ancestor_handle = $handles[$ancestor_phid];
|
||||
|
||||
return $this->newDialog()
|
||||
->setTitle(pht('Watching Ancestor'))
|
||||
->appendParagraph(
|
||||
pht(
|
||||
'You are already watching %s, an ancestor of this project, and '.
|
||||
'are thus watching all of its subprojects.',
|
||||
$ancestor_handle->renderTag()->render()))
|
||||
->addCancelbutton($done_uri);
|
||||
}
|
||||
|
||||
if ($request->isDialogFormPost()) {
|
||||
$edge_action = null;
|
||||
switch ($action) {
|
||||
|
@ -61,10 +78,14 @@ final class PhabricatorProjectWatchController
|
|||
switch ($action) {
|
||||
case 'watch':
|
||||
$title = pht('Watch Project?');
|
||||
$body = pht(
|
||||
$body = array();
|
||||
$body[] = pht(
|
||||
'Watching a project will let you monitor it closely. You will '.
|
||||
'receive email and notifications about changes to every object '.
|
||||
'associated with projects you watch.');
|
||||
'tagged with projects you watch.');
|
||||
$body[] = pht(
|
||||
'Watching a project also watches all subprojects and milestones of '.
|
||||
'that project.');
|
||||
$submit = pht('Watch Project');
|
||||
break;
|
||||
case 'unwatch':
|
||||
|
@ -78,12 +99,17 @@ final class PhabricatorProjectWatchController
|
|||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
return $this->newDialog()
|
||||
$dialog = $this->newDialog()
|
||||
->setTitle($title)
|
||||
->addHiddenInput('via', $via)
|
||||
->appendParagraph($body)
|
||||
->addCancelButton($done_uri)
|
||||
->addSubmitButton($submit);
|
||||
|
||||
foreach ((array)$body as $paragraph) {
|
||||
$dialog->appendParagraph($paragraph);
|
||||
}
|
||||
|
||||
return $dialog;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ final class PhabricatorProjectTransactionEditor
|
|||
$types[] = PhabricatorProjectTransaction::TYPE_HASWORKBOARD;
|
||||
$types[] = PhabricatorProjectTransaction::TYPE_DEFAULT_SORT;
|
||||
$types[] = PhabricatorProjectTransaction::TYPE_DEFAULT_FILTER;
|
||||
$types[] = PhabricatorProjectTransaction::TYPE_BACKGROUND;
|
||||
|
||||
return $types;
|
||||
}
|
||||
|
@ -77,6 +78,8 @@ final class PhabricatorProjectTransactionEditor
|
|||
return $object->getDefaultWorkboardSort();
|
||||
case PhabricatorProjectTransaction::TYPE_DEFAULT_FILTER:
|
||||
return $object->getDefaultWorkboardFilter();
|
||||
case PhabricatorProjectTransaction::TYPE_BACKGROUND:
|
||||
return $object->getWorkboardBackgroundColor();
|
||||
}
|
||||
|
||||
return parent::getCustomTransactionOldValue($object, $xaction);
|
||||
|
@ -100,6 +103,12 @@ final class PhabricatorProjectTransactionEditor
|
|||
return $xaction->getNewValue();
|
||||
case PhabricatorProjectTransaction::TYPE_HASWORKBOARD:
|
||||
return (int)$xaction->getNewValue();
|
||||
case PhabricatorProjectTransaction::TYPE_BACKGROUND:
|
||||
$value = $xaction->getNewValue();
|
||||
if (!strlen($value)) {
|
||||
return null;
|
||||
}
|
||||
return $value;
|
||||
case PhabricatorProjectTransaction::TYPE_SLUGS:
|
||||
return $this->normalizeSlugs($xaction->getNewValue());
|
||||
}
|
||||
|
@ -153,6 +162,9 @@ final class PhabricatorProjectTransactionEditor
|
|||
case PhabricatorProjectTransaction::TYPE_DEFAULT_FILTER:
|
||||
$object->setDefaultWorkboardFilter($xaction->getNewValue());
|
||||
return;
|
||||
case PhabricatorProjectTransaction::TYPE_BACKGROUND:
|
||||
$object->setWorkboardBackgroundColor($xaction->getNewValue());
|
||||
return;
|
||||
}
|
||||
|
||||
return parent::applyCustomInternalTransaction($object, $xaction);
|
||||
|
@ -198,6 +210,7 @@ final class PhabricatorProjectTransactionEditor
|
|||
case PhabricatorProjectTransaction::TYPE_HASWORKBOARD:
|
||||
case PhabricatorProjectTransaction::TYPE_DEFAULT_SORT:
|
||||
case PhabricatorProjectTransaction::TYPE_DEFAULT_FILTER:
|
||||
case PhabricatorProjectTransaction::TYPE_BACKGROUND:
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -506,6 +506,7 @@ final class PhabricatorBoardLayoutEngine extends Phobject {
|
|||
}
|
||||
}
|
||||
|
||||
$view_sequence = 1;
|
||||
foreach ($object_phids as $object_phid) {
|
||||
$positions = idx($position_groups, $object_phid, array());
|
||||
|
||||
|
@ -554,7 +555,8 @@ final class PhabricatorBoardLayoutEngine extends Phobject {
|
|||
->setBoardPHID($board_phid)
|
||||
->setColumnPHID($proxy_hit)
|
||||
->setObjectPHID($object_phid)
|
||||
->setSequence(0);
|
||||
->setSequence(0)
|
||||
->setViewSequence($view_sequence++);
|
||||
|
||||
$this->addQueue[] = $new_position;
|
||||
|
||||
|
@ -578,7 +580,8 @@ final class PhabricatorBoardLayoutEngine extends Phobject {
|
|||
->setBoardPHID($board_phid)
|
||||
->setColumnPHID($default_phid)
|
||||
->setObjectPHID($object_phid)
|
||||
->setSequence(0);
|
||||
->setSequence(0)
|
||||
->setViewSequence($view_sequence++);
|
||||
|
||||
$this->addQueue[] = $new_position;
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ final class PhabricatorProjectQuery
|
|||
private $ids;
|
||||
private $phids;
|
||||
private $memberPHIDs;
|
||||
private $watcherPHIDs;
|
||||
private $slugs;
|
||||
private $slugNormals;
|
||||
private $slugMap;
|
||||
|
@ -62,6 +63,11 @@ final class PhabricatorProjectQuery
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function withWatcherPHIDs(array $watcher_phids) {
|
||||
$this->watcherPHIDs = $watcher_phids;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withSlugs(array $slugs) {
|
||||
$this->slugs = $slugs;
|
||||
return $this;
|
||||
|
@ -170,6 +176,11 @@ final class PhabricatorProjectQuery
|
|||
'type' => 'string',
|
||||
'unique' => true,
|
||||
),
|
||||
'milestoneNumber' => array(
|
||||
'table' => $this->getPrimaryTableAlias(),
|
||||
'column' => 'milestoneNumber',
|
||||
'type' => 'int',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -242,7 +253,7 @@ final class PhabricatorProjectQuery
|
|||
|
||||
$all_graph = $this->getAllReachableAncestors($projects);
|
||||
|
||||
if ($this->needAncestorMembers) {
|
||||
if ($this->needAncestorMembers || $this->needWatchers) {
|
||||
$src_projects = $all_graph;
|
||||
} else {
|
||||
$src_projects = $projects;
|
||||
|
@ -250,11 +261,13 @@ final class PhabricatorProjectQuery
|
|||
|
||||
$all_sources = array();
|
||||
foreach ($src_projects as $project) {
|
||||
// For milestones, we need parent members.
|
||||
if ($project->isMilestone()) {
|
||||
$phid = $project->getParentProjectPHID();
|
||||
} else {
|
||||
$phid = $project->getPHID();
|
||||
$parent_phid = $project->getParentProjectPHID();
|
||||
$all_sources[$parent_phid] = $parent_phid;
|
||||
}
|
||||
|
||||
$phid = $project->getPHID();
|
||||
$all_sources[$phid] = $phid;
|
||||
}
|
||||
|
||||
|
@ -313,7 +326,7 @@ final class PhabricatorProjectQuery
|
|||
|
||||
if ($this->needWatchers) {
|
||||
$watcher_phids = $edge_query->getDestinationPHIDs(
|
||||
$source_phids,
|
||||
array($project_phid),
|
||||
array($watcher_type));
|
||||
$project->attachWatcherPHIDs($watcher_phids);
|
||||
$project->setIsUserWatcher(
|
||||
|
@ -429,6 +442,13 @@ final class PhabricatorProjectQuery
|
|||
$this->memberPHIDs);
|
||||
}
|
||||
|
||||
if ($this->watcherPHIDs !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'w.dst IN (%Ls)',
|
||||
$this->watcherPHIDs);
|
||||
}
|
||||
|
||||
if ($this->slugs !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
|
@ -542,7 +562,7 @@ final class PhabricatorProjectQuery
|
|||
}
|
||||
|
||||
protected function shouldGroupQueryResultRows() {
|
||||
if ($this->memberPHIDs || $this->nameTokens) {
|
||||
if ($this->memberPHIDs || $this->watcherPHIDs || $this->nameTokens) {
|
||||
return true;
|
||||
}
|
||||
return parent::shouldGroupQueryResultRows();
|
||||
|
@ -559,6 +579,14 @@ final class PhabricatorProjectQuery
|
|||
PhabricatorProjectMaterializedMemberEdgeType::EDGECONST);
|
||||
}
|
||||
|
||||
if ($this->watcherPHIDs !== null) {
|
||||
$joins[] = qsprintf(
|
||||
$conn,
|
||||
'JOIN %T w ON w.src = p.phid AND w.type = %d',
|
||||
PhabricatorEdgeConfig::TABLE_NAME_EDGE,
|
||||
PhabricatorObjectHasWatcherEdgeType::EDGECONST);
|
||||
}
|
||||
|
||||
if ($this->slugs !== null) {
|
||||
$joins[] = qsprintf(
|
||||
$conn,
|
||||
|
|
|
@ -26,6 +26,10 @@ final class PhabricatorProjectSearchEngine
|
|||
->setLabel(pht('Members'))
|
||||
->setKey('memberPHIDs')
|
||||
->setAliases(array('member', 'members')),
|
||||
id(new PhabricatorUsersSearchField())
|
||||
->setLabel(pht('Watchers'))
|
||||
->setKey('watcherPHIDs')
|
||||
->setAliases(array('watcher', 'watchers')),
|
||||
id(new PhabricatorSearchSelectField())
|
||||
->setLabel(pht('Status'))
|
||||
->setKey('status')
|
||||
|
@ -54,6 +58,10 @@ final class PhabricatorProjectSearchEngine
|
|||
$query->withMemberPHIDs($map['memberPHIDs']);
|
||||
}
|
||||
|
||||
if ($map['watcherPHIDs']) {
|
||||
$query->withWatcherPHIDs($map['watcherPHIDs']);
|
||||
}
|
||||
|
||||
if ($map['status']) {
|
||||
$status = idx($this->getStatusValues(), $map['status']);
|
||||
if ($status) {
|
||||
|
|
|
@ -287,6 +287,32 @@ final class PhabricatorProject extends PhabricatorProjectDAO
|
|||
return $this->assertAttachedKey($this->sparseWatchers, $user_phid);
|
||||
}
|
||||
|
||||
public function isUserAncestorWatcher($user_phid) {
|
||||
$is_watcher = $this->isUserWatcher($user_phid);
|
||||
|
||||
if (!$is_watcher) {
|
||||
$parent = $this->getParentProject();
|
||||
if ($parent) {
|
||||
return $parent->isUserWatcher($user_phid);
|
||||
}
|
||||
}
|
||||
|
||||
return $is_watcher;
|
||||
}
|
||||
|
||||
public function getWatchedAncestorPHID($user_phid) {
|
||||
if ($this->isUserWatcher($user_phid)) {
|
||||
return $this->getPHID();
|
||||
}
|
||||
|
||||
$parent = $this->getParentProject();
|
||||
if ($parent) {
|
||||
return $parent->getWatchedAncestorPHID($user_phid);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function setIsUserWatcher($user_phid, $is_watcher) {
|
||||
if ($this->sparseWatchers === self::ATTACHABLE) {
|
||||
$this->sparseWatchers = array();
|
||||
|
@ -304,6 +330,21 @@ final class PhabricatorProject extends PhabricatorProjectDAO
|
|||
return $this->assertAttached($this->watcherPHIDs);
|
||||
}
|
||||
|
||||
public function getAllAncestorWatcherPHIDs() {
|
||||
$parent = $this->getParentProject();
|
||||
if ($parent) {
|
||||
$watchers = $parent->getAllAncestorWatcherPHIDs();
|
||||
} else {
|
||||
$watchers = array();
|
||||
}
|
||||
|
||||
foreach ($this->getWatcherPHIDs() as $phid) {
|
||||
$watchers[$phid] = $phid;
|
||||
}
|
||||
|
||||
return $watchers;
|
||||
}
|
||||
|
||||
public function attachSlugs(array $slugs) {
|
||||
$this->slugs = $slugs;
|
||||
return $this;
|
||||
|
@ -579,6 +620,31 @@ final class PhabricatorProject extends PhabricatorProjectDAO
|
|||
return $this->setProperty('workboard.filter.default', $filter);
|
||||
}
|
||||
|
||||
public function getWorkboardBackgroundColor() {
|
||||
return $this->getProperty('workboard.background');
|
||||
}
|
||||
|
||||
public function setWorkboardBackgroundColor($color) {
|
||||
return $this->setProperty('workboard.background', $color);
|
||||
}
|
||||
|
||||
public function getDisplayWorkboardBackgroundColor() {
|
||||
$color = $this->getWorkboardBackgroundColor();
|
||||
|
||||
if ($color === null) {
|
||||
$parent = $this->getParentProject();
|
||||
if ($parent) {
|
||||
return $parent->getDisplayWorkboardBackgroundColor();
|
||||
}
|
||||
}
|
||||
|
||||
if ($color === 'none') {
|
||||
$color = null;
|
||||
}
|
||||
|
||||
return $color;
|
||||
}
|
||||
|
||||
|
||||
/* -( PhabricatorCustomFieldInterface )------------------------------------ */
|
||||
|
||||
|
|
|
@ -5,7 +5,8 @@ final class PhabricatorProjectColumn
|
|||
implements
|
||||
PhabricatorApplicationTransactionInterface,
|
||||
PhabricatorPolicyInterface,
|
||||
PhabricatorDestructibleInterface {
|
||||
PhabricatorDestructibleInterface,
|
||||
PhabricatorExtendedPolicyInterface {
|
||||
|
||||
const STATUS_ACTIVE = 0;
|
||||
const STATUS_HIDDEN = 1;
|
||||
|
@ -169,14 +170,16 @@ final class PhabricatorProjectColumn
|
|||
// Normal columns and subproject columns go first, in a user-controlled
|
||||
// order.
|
||||
|
||||
// All the milestone columns go last, in their sequential order.
|
||||
// All the milestone columns go last, in reverse order (newest on the
|
||||
// left) so that you don't have to scroll across older milestones to get
|
||||
// to the newest ones.
|
||||
|
||||
if (!$proxy || !$proxy->isMilestone()) {
|
||||
$group = 'A';
|
||||
$sequence = $this->getSequence();
|
||||
} else {
|
||||
$group = 'B';
|
||||
$sequence = $proxy->getMilestoneNumber();
|
||||
$sequence = (10000000 - $proxy->getMilestoneNumber());
|
||||
}
|
||||
|
||||
return sprintf('%s%012d', $group, $sequence);
|
||||
|
@ -217,7 +220,14 @@ final class PhabricatorProjectColumn
|
|||
}
|
||||
|
||||
public function getPolicy($capability) {
|
||||
return $this->getProject()->getPolicy($capability);
|
||||
// NOTE: Column policies are enforced as an extended policy which makes
|
||||
// them the same as the project's policies.
|
||||
switch ($capability) {
|
||||
case PhabricatorPolicyCapability::CAN_VIEW:
|
||||
return PhabricatorPolicies::getMostOpenPolicy();
|
||||
case PhabricatorPolicyCapability::CAN_EDIT:
|
||||
return PhabricatorPolicies::POLICY_USER;
|
||||
}
|
||||
}
|
||||
|
||||
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
|
||||
|
@ -231,6 +241,16 @@ final class PhabricatorProjectColumn
|
|||
}
|
||||
|
||||
|
||||
/* -( PhabricatorExtendedPolicyInterface )--------------------------------- */
|
||||
|
||||
|
||||
public function getExtendedPolicy($capability, PhabricatorUser $viewer) {
|
||||
return array(
|
||||
array($this->getProject(), $capability),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/* -( PhabricatorDestructibleInterface )----------------------------------- */
|
||||
|
||||
public function destroyObjectPermanently(
|
||||
|
|
|
@ -9,6 +9,7 @@ final class PhabricatorProjectColumnPosition extends PhabricatorProjectDAO
|
|||
protected $sequence;
|
||||
|
||||
private $column = self::ATTACHABLE;
|
||||
private $viewSequence = 0;
|
||||
|
||||
protected function getConfiguration() {
|
||||
return array(
|
||||
|
@ -40,18 +41,30 @@ final class PhabricatorProjectColumnPosition extends PhabricatorProjectDAO
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function getOrderingKey() {
|
||||
if (!$this->getID() && !$this->getSequence()) {
|
||||
return 0;
|
||||
}
|
||||
public function setViewSequence($view_sequence) {
|
||||
$this->viewSequence = $view_sequence;
|
||||
return $this;
|
||||
}
|
||||
|
||||
// Low sequence numbers go above high sequence numbers.
|
||||
// High position IDs go above low position IDs.
|
||||
// Broadly, this makes newly added stuff float to the top.
|
||||
public function getOrderingKey() {
|
||||
// We're ordering both real positions and "virtual" positions which we have
|
||||
// created but not saved yet.
|
||||
|
||||
// Low sequence numbers go above high sequence numbers. Virtual positions
|
||||
// will have sequence number 0.
|
||||
|
||||
// High virtual sequence numbers go above low virtual sequence numbers.
|
||||
// The layout engine gets objects in ID order, and this puts them in
|
||||
// reverse ID order.
|
||||
|
||||
// High IDs go above low IDs.
|
||||
|
||||
// Broadly, this collectively makes newly added stuff float to the top.
|
||||
|
||||
return sprintf(
|
||||
'~%012d%012d',
|
||||
'~%012d%012d%012d',
|
||||
$this->getSequence(),
|
||||
((1 << 31) - $this->viewSequence),
|
||||
((1 << 31) - $this->getID()));
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ final class PhabricatorProjectTransaction
|
|||
const TYPE_HASWORKBOARD = 'project:hasworkboard';
|
||||
const TYPE_DEFAULT_SORT = 'project:sort';
|
||||
const TYPE_DEFAULT_FILTER = 'project:filter';
|
||||
const TYPE_BACKGROUND = 'project:background';
|
||||
|
||||
// NOTE: This is deprecated, members are just a normal edge now.
|
||||
const TYPE_MEMBERS = 'project:members';
|
||||
|
@ -73,6 +74,7 @@ final class PhabricatorProjectTransaction
|
|||
case self::TYPE_HASWORKBOARD:
|
||||
case self::TYPE_DEFAULT_SORT:
|
||||
case self::TYPE_DEFAULT_FILTER:
|
||||
case self::TYPE_BACKGROUND:
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -84,6 +86,7 @@ final class PhabricatorProjectTransaction
|
|||
case self::TYPE_HASWORKBOARD:
|
||||
case self::TYPE_DEFAULT_SORT:
|
||||
case self::TYPE_DEFAULT_FILTER:
|
||||
case self::TYPE_BACKGROUND:
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -291,6 +294,11 @@ final class PhabricatorProjectTransaction
|
|||
return pht(
|
||||
'%s changed the default filter for the project workboard.',
|
||||
$author_handle);
|
||||
|
||||
case self::TYPE_BACKGROUND:
|
||||
return pht(
|
||||
'%s changed the background color of the project workboard.',
|
||||
$author_handle);
|
||||
}
|
||||
|
||||
return parent::getTitle();
|
||||
|
|
|
@ -45,6 +45,7 @@ final class PhabricatorRepositoryEditor
|
|||
$types[] = PhabricatorRepositoryTransaction::TYPE_SYMBOLS_SOURCES;
|
||||
$types[] = PhabricatorRepositoryTransaction::TYPE_STAGING_URI;
|
||||
$types[] = PhabricatorRepositoryTransaction::TYPE_AUTOMATION_BLUEPRINTS;
|
||||
$types[] = PhabricatorRepositoryTransaction::TYPE_CALLSIGN;
|
||||
|
||||
$types[] = PhabricatorTransactions::TYPE_EDGE;
|
||||
$types[] = PhabricatorTransactions::TYPE_VIEW_POLICY;
|
||||
|
@ -110,6 +111,8 @@ final class PhabricatorRepositoryEditor
|
|||
return $object->getDetail('staging-uri');
|
||||
case PhabricatorRepositoryTransaction::TYPE_AUTOMATION_BLUEPRINTS:
|
||||
return $object->getDetail('automation.blueprintPHIDs', array());
|
||||
case PhabricatorRepositoryTransaction::TYPE_CALLSIGN:
|
||||
return $object->getCallsign();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -148,6 +151,7 @@ final class PhabricatorRepositoryEditor
|
|||
case PhabricatorRepositoryTransaction::TYPE_AUTOMATION_BLUEPRINTS:
|
||||
return $xaction->getNewValue();
|
||||
case PhabricatorRepositoryTransaction::TYPE_SLUG:
|
||||
case PhabricatorRepositoryTransaction::TYPE_CALLSIGN:
|
||||
$name = $xaction->getNewValue();
|
||||
if (strlen($name)) {
|
||||
return $name;
|
||||
|
@ -240,6 +244,9 @@ final class PhabricatorRepositoryEditor
|
|||
'automation.blueprintPHIDs',
|
||||
$xaction->getNewValue());
|
||||
return;
|
||||
case PhabricatorRepositoryTransaction::TYPE_CALLSIGN:
|
||||
$object->setCallsign($xaction->getNewValue());
|
||||
return;
|
||||
case PhabricatorRepositoryTransaction::TYPE_ENCODING:
|
||||
// Make sure the encoding is valid by converting to UTF-8. This tests
|
||||
// that the user has mbstring installed, and also that they didn't type
|
||||
|
@ -468,7 +475,7 @@ final class PhabricatorRepositoryEditor
|
|||
}
|
||||
|
||||
try {
|
||||
PhabricatorRepository::asssertValidRepositorySlug($new);
|
||||
PhabricatorRepository::assertValidRepositorySlug($new);
|
||||
} catch (Exception $ex) {
|
||||
$errors[] = new PhabricatorApplicationTransactionValidationError(
|
||||
$type,
|
||||
|
@ -495,6 +502,47 @@ final class PhabricatorRepositoryEditor
|
|||
}
|
||||
break;
|
||||
|
||||
case PhabricatorRepositoryTransaction::TYPE_CALLSIGN:
|
||||
foreach ($xactions as $xaction) {
|
||||
$old = $xaction->getOldValue();
|
||||
$new = $xaction->getNewValue();
|
||||
|
||||
if (!strlen($new)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($new === $old) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
PhabricatorRepository::assertValidCallsign($new);
|
||||
} catch (Exception $ex) {
|
||||
$errors[] = new PhabricatorApplicationTransactionValidationError(
|
||||
$type,
|
||||
pht('Invalid'),
|
||||
$ex->getMessage(),
|
||||
$xaction);
|
||||
continue;
|
||||
}
|
||||
|
||||
$other = id(new PhabricatorRepositoryQuery())
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->withCallsigns(array($new))
|
||||
->executeOne();
|
||||
if ($other && ($other->getID() !== $object->getID())) {
|
||||
$errors[] = new PhabricatorApplicationTransactionValidationError(
|
||||
$type,
|
||||
pht('Duplicate'),
|
||||
pht(
|
||||
'The selected callsign ("%s") is already in use by another '.
|
||||
'repository. Choose a unique callsign.',
|
||||
$new),
|
||||
$xaction);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return $errors;
|
||||
|
@ -522,4 +570,27 @@ final class PhabricatorRepositoryEditor
|
|||
return true;
|
||||
}
|
||||
|
||||
protected function applyFinalEffects(
|
||||
PhabricatorLiskDAO $object,
|
||||
array $xactions) {
|
||||
|
||||
// If the repository does not have a local path yet, assign it one based
|
||||
// on its ID. We can't do this earlier because we won't have an ID yet.
|
||||
$local_path = $object->getDetail('local-path');
|
||||
if (!strlen($local_path)) {
|
||||
$local_key = 'repository.default-local-path';
|
||||
|
||||
$local_root = PhabricatorEnv::getEnvConfig($local_key);
|
||||
$local_root = rtrim($local_root, '/');
|
||||
|
||||
$id = $object->getID();
|
||||
$local_path = "{$local_root}/{$id}/";
|
||||
|
||||
$object->setDetail('local-path', $local_path);
|
||||
$object->save();
|
||||
}
|
||||
|
||||
return $xactions;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -192,7 +192,7 @@ final class PhabricatorRepositoryPullEngine
|
|||
}
|
||||
|
||||
private function getHookContextIdentifier(PhabricatorRepository $repository) {
|
||||
$identifier = $repository->getCallsign();
|
||||
$identifier = $repository->getPHID();
|
||||
|
||||
$instance = PhabricatorEnv::getEnvConfig('cluster.instance');
|
||||
if (strlen($instance)) {
|
||||
|
|
|
@ -93,7 +93,7 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
|
|||
),
|
||||
self::CONFIG_COLUMN_SCHEMA => array(
|
||||
'name' => 'sort255',
|
||||
'callsign' => 'sort32',
|
||||
'callsign' => 'sort32?',
|
||||
'repositorySlug' => 'sort64?',
|
||||
'versionControlSystem' => 'text32',
|
||||
'uuid' => 'text64?',
|
||||
|
@ -149,13 +149,21 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
|
|||
}
|
||||
|
||||
public function getMonogram() {
|
||||
return 'r'.$this->getCallsign();
|
||||
$callsign = $this->getCallsign();
|
||||
if (strlen($callsign)) {
|
||||
return "r{$callsign}";
|
||||
}
|
||||
|
||||
$id = $this->getID();
|
||||
return "R{$id}";
|
||||
}
|
||||
|
||||
public function getDisplayName() {
|
||||
// TODO: This is intended to produce a human-readable name that is not
|
||||
// necessarily a global, unique identifier. Eventually, it may just return
|
||||
// a string like "skynet" instead of "rSKYNET".
|
||||
$slug = $this->getRepositorySlug();
|
||||
if (strlen($slug)) {
|
||||
return $slug;
|
||||
}
|
||||
|
||||
return $this->getMonogram();
|
||||
}
|
||||
|
||||
|
@ -317,14 +325,14 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
|
|||
|
||||
public static function isValidRepositorySlug($slug) {
|
||||
try {
|
||||
self::asssertValidRepositorySlug($slug);
|
||||
self::assertValidRepositorySlug($slug);
|
||||
return true;
|
||||
} catch (Exception $ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static function asssertValidRepositorySlug($slug) {
|
||||
public static function assertValidRepositorySlug($slug) {
|
||||
if (!strlen($slug)) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
|
@ -391,6 +399,30 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
|
|||
}
|
||||
}
|
||||
|
||||
public static function assertValidCallsign($callsign) {
|
||||
if (!strlen($callsign)) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'A repository callsign must be at least one character long.'));
|
||||
}
|
||||
|
||||
if (strlen($callsign) > 32) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'The callsign "%s" is not a valid repository callsign. Callsigns '.
|
||||
'must be no more than 32 bytes long.',
|
||||
$callsign));
|
||||
}
|
||||
|
||||
if (!preg_match('/^[A-Z]+\z/', $callsign)) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'The callsign "%s" is not a valid repository callsign. Callsigns '.
|
||||
'may only contain UPPERCASE letters.',
|
||||
$callsign));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* -( Remote Command Execution )------------------------------------------- */
|
||||
|
||||
|
@ -675,7 +707,13 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
|
|||
}
|
||||
|
||||
public function getURI() {
|
||||
return '/diffusion/'.$this->getCallsign().'/';
|
||||
$callsign = $this->getCallsign();
|
||||
if (strlen($callsign)) {
|
||||
return "/diffusion/{$callsign}/";
|
||||
}
|
||||
|
||||
$id = $this->getID();
|
||||
return "/diffusion/{$id}/";
|
||||
}
|
||||
|
||||
public function getPathURI($path) {
|
||||
|
@ -684,7 +722,96 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
|
|||
|
||||
public function getCommitURI($identifier) {
|
||||
$callsign = $this->getCallsign();
|
||||
return "/r{$callsign}{$identifier}";
|
||||
if (strlen($callsign)) {
|
||||
return "/r{$callsign}{$identifier}";
|
||||
}
|
||||
|
||||
$id = $this->getID();
|
||||
return "/R{$id}:{$identifier}";
|
||||
}
|
||||
|
||||
public static function parseRepositoryServicePath($request_path) {
|
||||
// NOTE: In Mercurial over SSH, the path will begin without a leading "/",
|
||||
// so we're matching it optionally.
|
||||
|
||||
$patterns = array(
|
||||
'(^'.
|
||||
'(?P<base>/?diffusion/(?P<identifier>[A-Z]+|[0-9]\d*))'.
|
||||
'(?P<path>(?:/.*)?)'.
|
||||
'\z)',
|
||||
);
|
||||
|
||||
$identifier = null;
|
||||
foreach ($patterns as $pattern) {
|
||||
$matches = null;
|
||||
if (!preg_match($pattern, $request_path, $matches)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$identifier = $matches['identifier'];
|
||||
$base = $matches['base'];
|
||||
$path = $matches['path'];
|
||||
break;
|
||||
}
|
||||
|
||||
if ($identifier === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return array(
|
||||
'identifier' => $identifier,
|
||||
'base' => $base,
|
||||
'path' => $path,
|
||||
);
|
||||
}
|
||||
|
||||
public function getCanonicalPath($request_path) {
|
||||
$standard_pattern =
|
||||
'(^'.
|
||||
'(?P<prefix>/diffusion/)'.
|
||||
'(?P<identifier>[^/]+)'.
|
||||
'(?P<suffix>(?:/.*)?)'.
|
||||
'\z)';
|
||||
|
||||
$matches = null;
|
||||
if (preg_match($standard_pattern, $request_path, $matches)) {
|
||||
$prefix = $matches['prefix'];
|
||||
|
||||
$callsign = $this->getCallsign();
|
||||
if ($callsign) {
|
||||
$identifier = $callsign;
|
||||
} else {
|
||||
$identifier = $this->getID();
|
||||
}
|
||||
|
||||
$suffix = $matches['suffix'];
|
||||
if (!strlen($suffix)) {
|
||||
$suffix = '/';
|
||||
}
|
||||
|
||||
return $prefix.$identifier.$suffix;
|
||||
}
|
||||
|
||||
$commit_pattern =
|
||||
'(^'.
|
||||
'(?P<prefix>/)'.
|
||||
'(?P<monogram>'.
|
||||
'(?:'.
|
||||
'r(?P<repositoryCallsign>[A-Z]+)'.
|
||||
'|'.
|
||||
'R(?P<repositoryID>[1-9]\d*):'.
|
||||
')'.
|
||||
'(?P<commit>[a-f0-9]+)'.
|
||||
')'.
|
||||
'\z)';
|
||||
|
||||
$matches = null;
|
||||
if (preg_match($commit_pattern, $request_path, $matches)) {
|
||||
$commit = $matches['commit'];
|
||||
return $this->getCommitURI($commit);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function generateURI(array $params) {
|
||||
|
@ -955,7 +1082,13 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
|
|||
}
|
||||
|
||||
if ($need_scope) {
|
||||
$scope = 'r'.$this->getCallsign();
|
||||
$callsign = $this->getCallsign();
|
||||
if ($callsign) {
|
||||
$scope = "r{$callsign}";
|
||||
} else {
|
||||
$id = $this->getID();
|
||||
$scope = "R{$id}:";
|
||||
}
|
||||
$name = $scope.$name;
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ final class PhabricatorRepositoryTransaction
|
|||
const TYPE_SYMBOLS_LANGUAGE = 'repo:symbol-language';
|
||||
const TYPE_STAGING_URI = 'repo:staging-uri';
|
||||
const TYPE_AUTOMATION_BLUEPRINTS = 'repo:automation-blueprints';
|
||||
const TYPE_CALLSIGN = 'repo:callsign';
|
||||
|
||||
// TODO: Clean up these legacy transaction types.
|
||||
const TYPE_SSH_LOGIN = 'repo:ssh-login';
|
||||
|
@ -466,6 +467,26 @@ final class PhabricatorRepositoryTransaction
|
|||
new PhutilNumber(count($rem)),
|
||||
$this->renderHandleList($rem));
|
||||
}
|
||||
|
||||
case self::TYPE_CALLSIGN:
|
||||
if ($old === null) {
|
||||
return pht(
|
||||
'%s set the callsign for this repository to "%s".',
|
||||
$this->renderHandleLink($author_phid),
|
||||
$new);
|
||||
} else if ($new === null) {
|
||||
return pht(
|
||||
'%s removed the callsign ("%s") for this repository.',
|
||||
$this->renderHandleLink($author_phid),
|
||||
$old);
|
||||
} else {
|
||||
return pht(
|
||||
'%s changed the callsign for this repository from "%s" to "%s".',
|
||||
$this->renderHandleLink($author_phid),
|
||||
$old,
|
||||
$new);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return parent::getTitle();
|
||||
|
|
|
@ -9,6 +9,47 @@ final class PhabricatorRepositoryURITestCase
|
|||
);
|
||||
}
|
||||
|
||||
public function testRepositoryURICanonicalization() {
|
||||
$repo = id(new PhabricatorRepository())
|
||||
->makeEphemeral()
|
||||
->setID(123);
|
||||
|
||||
$tests = array(
|
||||
'/diffusion/123' => '/diffusion/123/',
|
||||
'/diffusion/123/' => '/diffusion/123/',
|
||||
'/diffusion/123/browse/master/' => '/diffusion/123/browse/master/',
|
||||
'/kangaroo/' => null,
|
||||
);
|
||||
|
||||
foreach ($tests as $input => $expect) {
|
||||
$this->assertEqual(
|
||||
$expect,
|
||||
$repo->getCanonicalPath($input),
|
||||
pht('Canonical Path (ID, No Callsign): %s', $input));
|
||||
}
|
||||
|
||||
$repo->setCallsign('XYZ');
|
||||
|
||||
$tests = array(
|
||||
'/diffusion/123' => '/diffusion/XYZ/',
|
||||
'/diffusion/123/' => '/diffusion/XYZ/',
|
||||
'/diffusion/123/browse/master/' => '/diffusion/XYZ/browse/master/',
|
||||
'/diffusion/XYZ' => '/diffusion/XYZ/',
|
||||
'/diffusion/XYZ/' => '/diffusion/XYZ/',
|
||||
'/diffusion/XYZ/browse/master/' => '/diffusion/XYZ/browse/master/',
|
||||
'/diffusion/ABC/' => '/diffusion/XYZ/',
|
||||
'/kangaroo/' => null,
|
||||
'/R1:abcdef' => '/rXYZabcdef',
|
||||
);
|
||||
|
||||
foreach ($tests as $input => $expect) {
|
||||
$this->assertEqual(
|
||||
$expect,
|
||||
$repo->getCanonicalPath($input),
|
||||
pht('Canonical Path (ID, Callsign): %s', $input));
|
||||
}
|
||||
}
|
||||
|
||||
public function testURIGeneration() {
|
||||
$svn = PhabricatorRepositoryType::REPOSITORY_TYPE_SVN;
|
||||
$git = PhabricatorRepositoryType::REPOSITORY_TYPE_GIT;
|
||||
|
|
|
@ -122,13 +122,13 @@ final class PhabricatorSlowvotePollController
|
|||
|
||||
$view->invokeWillRenderEvent();
|
||||
|
||||
if (strlen($poll->getDescription())) {
|
||||
$view->addTextContent(
|
||||
$output = PhabricatorMarkupEngine::renderOneObject(
|
||||
id(new PhabricatorMarkupOneOff())->setContent(
|
||||
$poll->getDescription()),
|
||||
'default',
|
||||
$viewer));
|
||||
$description = $poll->getDescription();
|
||||
if (strlen($description)) {
|
||||
$description = new PHUIRemarkupView($viewer, $description);
|
||||
$view->addSectionHeader(
|
||||
pht('Description'),
|
||||
PHUIPropertyListView::ICON_SUMMARY);
|
||||
$view->addTextContent($description);
|
||||
}
|
||||
|
||||
return $view;
|
||||
|
|
|
@ -97,7 +97,20 @@ final class PhabricatorSlowvoteTransaction
|
|||
return parent::getTitle();
|
||||
}
|
||||
|
||||
public function getTitleForFeed() {
|
||||
public function getRemarkupBlocks() {
|
||||
$blocks = parent::getRemarkupBlocks();
|
||||
|
||||
$type = $this->getTransactionType();
|
||||
switch ($type) {
|
||||
case self::TYPE_DESCRIPTION:
|
||||
$blocks[] = $this->getNewValue();
|
||||
break;
|
||||
}
|
||||
|
||||
return $blocks;
|
||||
}
|
||||
|
||||
public function getTitleForFeed() {
|
||||
$author_phid = $this->getAuthorPHID();
|
||||
$object_phid = $this->getObjectPHID();
|
||||
|
||||
|
|
|
@ -74,13 +74,9 @@ final class SlowvoteEmbedView extends AphrontView {
|
|||
$header = id(new PHUIHeaderView())
|
||||
->setHeader($link_to_slowvote);
|
||||
|
||||
$description = null;
|
||||
if ($poll->getDescription()) {
|
||||
$description = PhabricatorMarkupEngine::renderOneObject(
|
||||
id(new PhabricatorMarkupOneOff())->setContent(
|
||||
$poll->getDescription()),
|
||||
'default',
|
||||
$this->getUser());
|
||||
$description = $poll->getDescription();
|
||||
if (strlen($description)) {
|
||||
$description = new PHUIRemarkupView($this->getUser(), $description);
|
||||
$description = phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
|
|
|
@ -83,15 +83,10 @@ final class PhabricatorSpacesViewController
|
|||
|
||||
$description = $space->getDescription();
|
||||
if (strlen($description)) {
|
||||
$description = PhabricatorMarkupEngine::renderOneObject(
|
||||
id(new PhabricatorMarkupOneOff())->setContent($description),
|
||||
'default',
|
||||
$viewer);
|
||||
|
||||
$description = new PHUIRemarkupView($viewer, $description);
|
||||
$list->addSectionHeader(
|
||||
pht('Description'),
|
||||
PHUIPropertyListView::ICON_SUMMARY);
|
||||
|
||||
$list->addTextContent($description);
|
||||
}
|
||||
|
||||
|
|
|
@ -28,24 +28,10 @@ final class PhabricatorSubscriptionsEditController
|
|||
->withPHIDs(array($phid))
|
||||
->executeOne();
|
||||
|
||||
if (phid_get_type($phid) == PhabricatorProjectProjectPHIDType::TYPECONST) {
|
||||
// TODO: This is a big hack, but a weak argument for adding some kind
|
||||
// of "load for role" feature to ObjectQuery, and also not a really great
|
||||
// argument for adding some kind of "load extra stuff" feature to
|
||||
// SubscriberInterface. Do this for now and wait for the best way forward
|
||||
// to become more clear?
|
||||
|
||||
$object = id(new PhabricatorProjectQuery())
|
||||
->setViewer($viewer)
|
||||
->withPHIDs(array($phid))
|
||||
->needWatchers(true)
|
||||
->executeOne();
|
||||
} else {
|
||||
$object = id(new PhabricatorObjectQuery())
|
||||
->setViewer($viewer)
|
||||
->withPHIDs(array($phid))
|
||||
->executeOne();
|
||||
}
|
||||
$object = id(new PhabricatorObjectQuery())
|
||||
->setViewer($viewer)
|
||||
->withPHIDs(array($phid))
|
||||
->executeOne();
|
||||
|
||||
if (!($object instanceof PhabricatorSubscribableInterface)) {
|
||||
return $this->buildErrorResponse(
|
||||
|
|
|
@ -50,10 +50,7 @@ final class PhabricatorApplicationTransactionCommentRawController
|
|||
$details_text = pht(
|
||||
'For full details, run `/bin/mail show-outbound --id %d`',
|
||||
$source_id);
|
||||
$addendum = PhabricatorMarkupEngine::renderOneObject(
|
||||
id(new PhabricatorMarkupOneOff())->setContent($details_text),
|
||||
'default',
|
||||
$viewer);
|
||||
$addendum = new PHUIRemarkupView($viewer, $details_text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,6 +70,8 @@ abstract class PhabricatorEditEngineController
|
|||
->executeOne();
|
||||
if ($config) {
|
||||
$engine = $config->getEngine();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!$engine->isEngineConfigurable()) {
|
||||
|
|
|
@ -2607,14 +2607,19 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
PhabricatorProjectObjectHasProjectEdgeType::EDGECONST);
|
||||
|
||||
if ($project_phids) {
|
||||
$watcher_type = PhabricatorObjectHasWatcherEdgeType::EDGECONST;
|
||||
$projects = id(new PhabricatorProjectQuery())
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->withPHIDs($project_phids)
|
||||
->needWatchers(true)
|
||||
->execute();
|
||||
|
||||
$query = id(new PhabricatorEdgeQuery())
|
||||
->withSourcePHIDs($project_phids)
|
||||
->withEdgeTypes(array($watcher_type));
|
||||
$query->execute();
|
||||
$watcher_phids = array();
|
||||
foreach ($projects as $project) {
|
||||
foreach ($project->getAllAncestorWatcherPHIDs() as $phid) {
|
||||
$watcher_phids[$phid] = $phid;
|
||||
}
|
||||
}
|
||||
|
||||
$watcher_phids = $query->getDestinationPHIDs();
|
||||
if ($watcher_phids) {
|
||||
// We need to do a visibility check for all the watchers, as
|
||||
// watching a project is not a guarantee that you can see objects
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue