Page MenuHomestyx hydra

No OneTemporary

This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/resources/celerity/map.php b/resources/celerity/map.php
index c4e3ae3bf6..3209d1c6ed 100644
--- a/resources/celerity/map.php
+++ b/resources/celerity/map.php
@@ -1,2347 +1,2347 @@
<?php
/**
* This file is automatically generated. Use 'bin/celerity map' to rebuild it.
*
* @generated
*/
return array(
'names' => array(
- 'core.pkg.css' => '225e8ac7',
+ 'core.pkg.css' => 'a93de192',
'core.pkg.js' => '7d8faf57',
'darkconsole.pkg.js' => 'e7393ebb',
'differential.pkg.css' => '7ba78475',
'differential.pkg.js' => 'd0cd0df6',
- 'diffusion.pkg.css' => 'f45955ed',
+ 'diffusion.pkg.css' => 'dc8e0cc2',
'diffusion.pkg.js' => '3a9a8bfa',
'maniphest.pkg.css' => '4845691a',
'maniphest.pkg.js' => '949a7498',
'rsrc/css/aphront/aphront-bars.css' => '231ac33c',
'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' => '7f684b62',
'rsrc/css/aphront/panel-view.css' => '8427b78d',
'rsrc/css/aphront/phabricator-nav-view.css' => 'ac79a758',
'rsrc/css/aphront/table-view.css' => '036b6cdc',
'rsrc/css/aphront/tokenizer.css' => '056da01b',
'rsrc/css/aphront/tooltip.css' => '1a07aea8',
'rsrc/css/aphront/typeahead-browse.css' => 'd8581d2c',
'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',
'rsrc/css/application/base/notification-menu.css' => 'f31c0bde',
'rsrc/css/application/base/phabricator-application-launch-view.css' => '95351601',
'rsrc/css/application/base/phui-theme.css' => '027ba77e',
'rsrc/css/application/base/standard-page-view.css' => 'e709f6d0',
'rsrc/css/application/chatlog/chatlog.css' => 'd295b020',
'rsrc/css/application/conduit/conduit-api.css' => '7bc725c4',
'rsrc/css/application/config/config-options.css' => '0ede4c9b',
'rsrc/css/application/config/config-template.css' => '8e6c6fcd',
'rsrc/css/application/config/config-welcome.css' => '6abd79be',
'rsrc/css/application/config/setup-issue.css' => 'db7e9c40',
'rsrc/css/application/config/unhandled-exception.css' => '4c96257a',
'rsrc/css/application/conpherence/durable-column.css' => '86396117',
'rsrc/css/application/conpherence/menu.css' => 'f99fee4c',
'rsrc/css/application/conpherence/message-pane.css' => '5897d3ac',
'rsrc/css/application/conpherence/notification.css' => '6cdcc253',
'rsrc/css/application/conpherence/transaction.css' => '85d0974c',
'rsrc/css/application/conpherence/update.css' => 'faf6be09',
'rsrc/css/application/conpherence/widget-pane.css' => '775eaaba',
'rsrc/css/application/contentsource/content-source-view.css' => '4b8b05d4',
'rsrc/css/application/countdown/timer.css' => '96696f21',
'rsrc/css/application/daemon/bulk-job.css' => 'df9c1d4a',
'rsrc/css/application/dashboard/dashboard.css' => 'eb458607',
'rsrc/css/application/diff/inline-comment-summary.css' => '51efda3a',
'rsrc/css/application/differential/add-comment.css' => 'c47f8c40',
'rsrc/css/application/differential/changeset-view.css' => '3e3b0b76',
'rsrc/css/application/differential/core.css' => '5b7b8ff4',
'rsrc/css/application/differential/phui-inline-comment.css' => '5953c28e',
'rsrc/css/application/differential/revision-comment.css' => '14b8565a',
'rsrc/css/application/differential/revision-history.css' => '0e8eb855',
'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-icons.css' => '3311444d',
'rsrc/css/application/diffusion/diffusion-readme.css' => '356a4f3c',
- 'rsrc/css/application/diffusion/diffusion-source.css' => '075ba788',
+ 'rsrc/css/application/diffusion/diffusion-source.css' => '68b30fd3',
'rsrc/css/application/feed/feed.css' => 'ecd4ec57',
'rsrc/css/application/files/global-drag-and-drop.css' => '5c1b47c2',
'rsrc/css/application/flag/flag.css' => '5337623f',
'rsrc/css/application/harbormaster/harbormaster.css' => '834879db',
'rsrc/css/application/herald/herald-test.css' => 'a52e323e',
'rsrc/css/application/herald/herald.css' => 'dc31f6e9',
'rsrc/css/application/maniphest/batch-editor.css' => 'b0f0b6d5',
'rsrc/css/application/maniphest/report.css' => '9b9580b7',
'rsrc/css/application/maniphest/task-edit.css' => 'fda62a9b',
'rsrc/css/application/maniphest/task-summary.css' => '11cc5344',
'rsrc/css/application/objectselector/object-selector.css' => '85ee8ce6',
'rsrc/css/application/owners/owners-path-editor.css' => '2f00933b',
'rsrc/css/application/paste/paste.css' => '1898e534',
'rsrc/css/application/people/people-profile.css' => '2473d929',
'rsrc/css/application/phame/phame.css' => '737792d6',
'rsrc/css/application/pholio/pholio-edit.css' => '3ad9d1ee',
'rsrc/css/application/pholio/pholio-inline-comments.css' => '8e545e49',
'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',
'rsrc/css/application/phriction/phriction-document-css.css' => 'd1861e06',
'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' => 'fbd45f96',
'rsrc/css/application/project/project-card-view.css' => '9418c97d',
'rsrc/css/application/project/project-view.css' => '9ce99f21',
'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',
'rsrc/css/application/releeph/releeph-request-typeahead.css' => '667a48ae',
'rsrc/css/application/search/search-results.css' => '7dea472c',
'rsrc/css/application/slowvote/slowvote.css' => 'a94b7230',
'rsrc/css/application/tokens/tokens.css' => '3d0f239e',
'rsrc/css/application/uiexample/example.css' => '528b19de',
'rsrc/css/core/core.css' => 'd0801452',
'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',
'rsrc/css/font/font-aleo.css' => '8bdb2835',
'rsrc/css/font/font-awesome.css' => 'c43323c5',
'rsrc/css/font/font-lato.css' => 'c7ccd872',
'rsrc/css/font/phui-font-icon-base.css' => '6449bce8',
'rsrc/css/layout/phabricator-filetree-view.css' => 'fccf9f82',
'rsrc/css/layout/phabricator-side-menu-view.css' => '3a3d9f41',
'rsrc/css/layout/phabricator-source-code-view.css' => 'cbeef983',
'rsrc/css/phui/calendar/phui-calendar-day.css' => 'd1cf6f93',
'rsrc/css/phui/calendar/phui-calendar-list.css' => 'c1c7f338',
'rsrc/css/phui/calendar/phui-calendar-month.css' => '476be7e0',
'rsrc/css/phui/calendar/phui-calendar.css' => 'ccabe893',
'rsrc/css/phui/phui-action-list.css' => 'c5eba19d',
'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' => '96a10c5d',
+ 'rsrc/css/phui/phui-box.css' => 'b2d49bae',
'rsrc/css/phui/phui-button.css' => 'a64a8de6',
'rsrc/css/phui/phui-chart.css' => '6bf6f78e',
'rsrc/css/phui/phui-crumbs-view.css' => '79d536e5',
'rsrc/css/phui/phui-curtain-view.css' => '7148ae25',
'rsrc/css/phui/phui-document-pro.css' => '92d5b648',
'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' => 'aac1d51d',
- 'rsrc/css/phui/phui-head-thing.css' => '31638812',
- 'rsrc/css/phui/phui-header-view.css' => '26cffd3d',
+ 'rsrc/css/phui/phui-head-thing.css' => 'fd311e5f',
+ 'rsrc/css/phui/phui-header-view.css' => '230254d3',
'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' => 'a8498f9c',
'rsrc/css/phui/phui-info-panel.css' => '27ea50a1',
- 'rsrc/css/phui/phui-info-view.css' => '6d7c3509',
+ 'rsrc/css/phui/phui-info-view.css' => '28efab79',
'rsrc/css/phui/phui-list.css' => '9da2aa00',
'rsrc/css/phui/phui-object-box.css' => '6b487c57',
'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' => '7e92a89a',
- 'rsrc/css/phui/phui-property-list-view.css' => 'b12e801c',
+ 'rsrc/css/phui/phui-property-list-view.css' => '1d42ee7c',
'rsrc/css/phui/phui-remarkup-preview.css' => '1a8f2591',
'rsrc/css/phui/phui-segment-bar-view.css' => '46342871',
'rsrc/css/phui/phui-spacing.css' => '042804d6',
'rsrc/css/phui/phui-status.css' => '37309046',
'rsrc/css/phui/phui-tag-view.css' => '6bbd83e2',
'rsrc/css/phui/phui-timeline-view.css' => 'a0173eba',
- 'rsrc/css/phui/phui-two-column-view.css' => '61dd6d38',
+ 'rsrc/css/phui/phui-two-column-view.css' => 'c110d0c3',
'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' => '92197373',
'rsrc/css/sprite-login.css' => '60e8560e',
'rsrc/css/sprite-menu.css' => '9dd65b92',
'rsrc/css/sprite-tokens.css' => '4f399012',
'rsrc/externals/d3/d3.min.js' => 'a11a5ff2',
'rsrc/externals/font/aleo/aleo-bold.eot' => 'd3d3bed7',
'rsrc/externals/font/aleo/aleo-bold.svg' => '45899c8e',
'rsrc/externals/font/aleo/aleo-bold.ttf' => '4b08bef0',
'rsrc/externals/font/aleo/aleo-bold.woff' => '93b513a1',
'rsrc/externals/font/aleo/aleo-bold.woff2' => '75fbf322',
'rsrc/externals/font/aleo/aleo-regular.eot' => 'a4e29e2f',
'rsrc/externals/font/aleo/aleo-regular.svg' => '42a86f7a',
'rsrc/externals/font/aleo/aleo-regular.ttf' => '751e7479',
'rsrc/externals/font/aleo/aleo-regular.woff' => 'c3744be9',
'rsrc/externals/font/aleo/aleo-regular.woff2' => '851aa0ee',
'rsrc/externals/font/fontawesome/fontawesome-webfont.eot' => '346fbcc5',
'rsrc/externals/font/fontawesome/fontawesome-webfont.ttf' => '510fccb2',
'rsrc/externals/font/fontawesome/fontawesome-webfont.woff' => '0334f580',
'rsrc/externals/font/fontawesome/fontawesome-webfont.woff2' => '45dca585',
'rsrc/externals/font/lato/lato-bold.eot' => '99fbcf8c',
'rsrc/externals/font/lato/lato-bold.svg' => '2aa83045',
'rsrc/externals/font/lato/lato-bold.ttf' => '0a7141f7',
'rsrc/externals/font/lato/lato-bold.woff' => 'f5db2061',
'rsrc/externals/font/lato/lato-bold.woff2' => '37a94ecd',
'rsrc/externals/font/lato/lato-bolditalic.eot' => 'b93389d0',
'rsrc/externals/font/lato/lato-bolditalic.svg' => '5442e1ef',
'rsrc/externals/font/lato/lato-bolditalic.ttf' => 'dad31252',
'rsrc/externals/font/lato/lato-bolditalic.woff' => 'e53bcf47',
'rsrc/externals/font/lato/lato-bolditalic.woff2' => 'd035007f',
'rsrc/externals/font/lato/lato-italic.eot' => '6a903f5d',
'rsrc/externals/font/lato/lato-italic.svg' => '0dc7cf2f',
'rsrc/externals/font/lato/lato-italic.ttf' => '629f64f0',
'rsrc/externals/font/lato/lato-italic.woff' => '678dc4bb',
'rsrc/externals/font/lato/lato-italic.woff2' => '7c8dd650',
'rsrc/externals/font/lato/lato-regular.eot' => '848dfb1e',
'rsrc/externals/font/lato/lato-regular.svg' => 'cbd5fd6b',
'rsrc/externals/font/lato/lato-regular.ttf' => 'e270165b',
'rsrc/externals/font/lato/lato-regular.woff' => '13d39fe2',
'rsrc/externals/font/lato/lato-regular.woff2' => '57a9f742',
'rsrc/externals/javelin/core/Event.js' => '2ee659ce',
'rsrc/externals/javelin/core/Stratcom.js' => '6ad39b6f',
'rsrc/externals/javelin/core/__tests__/event-stop-and-kill.js' => '717554e4',
'rsrc/externals/javelin/core/__tests__/install.js' => 'c432ee85',
'rsrc/externals/javelin/core/__tests__/stratcom.js' => '88bf7313',
'rsrc/externals/javelin/core/__tests__/util.js' => 'e251703d',
'rsrc/externals/javelin/core/init.js' => '3010e992',
'rsrc/externals/javelin/core/init_node.js' => 'c234aded',
'rsrc/externals/javelin/core/install.js' => '05270951',
'rsrc/externals/javelin/core/util.js' => '93cc50d6',
'rsrc/externals/javelin/docs/Base.js' => '74676256',
'rsrc/externals/javelin/docs/onload.js' => 'e819c479',
'rsrc/externals/javelin/ext/fx/Color.js' => '7e41274a',
'rsrc/externals/javelin/ext/fx/FX.js' => '54b612ba',
'rsrc/externals/javelin/ext/reactor/core/DynVal.js' => 'f6555212',
'rsrc/externals/javelin/ext/reactor/core/Reactor.js' => '2b8de964',
'rsrc/externals/javelin/ext/reactor/core/ReactorNode.js' => '1ad0a787',
'rsrc/externals/javelin/ext/reactor/core/ReactorNodeCalmer.js' => '76f4ebed',
'rsrc/externals/javelin/ext/reactor/dom/RDOM.js' => 'c90a04fc',
'rsrc/externals/javelin/ext/view/HTMLView.js' => 'fe287620',
'rsrc/externals/javelin/ext/view/View.js' => '0f764c35',
'rsrc/externals/javelin/ext/view/ViewInterpreter.js' => 'f829edb3',
'rsrc/externals/javelin/ext/view/ViewPlaceholder.js' => '47830651',
'rsrc/externals/javelin/ext/view/ViewRenderer.js' => '6c2b09a2',
'rsrc/externals/javelin/ext/view/ViewVisitor.js' => 'efe49472',
'rsrc/externals/javelin/ext/view/__tests__/HTMLView.js' => 'f92d7bcb',
'rsrc/externals/javelin/ext/view/__tests__/View.js' => '6450b38b',
'rsrc/externals/javelin/ext/view/__tests__/ViewInterpreter.js' => '7a94d6a5',
'rsrc/externals/javelin/ext/view/__tests__/ViewRenderer.js' => '6ea96ac9',
'rsrc/externals/javelin/lib/Cookie.js' => '62dfea03',
'rsrc/externals/javelin/lib/DOM.js' => '805b806a',
'rsrc/externals/javelin/lib/History.js' => 'd4505101',
'rsrc/externals/javelin/lib/JSON.js' => '69adf288',
'rsrc/externals/javelin/lib/Leader.js' => '331b1611',
'rsrc/externals/javelin/lib/Mask.js' => '8a41885b',
'rsrc/externals/javelin/lib/Quicksand.js' => '6b8ef10b',
'rsrc/externals/javelin/lib/Request.js' => '94b750d2',
'rsrc/externals/javelin/lib/Resource.js' => '44959b73',
'rsrc/externals/javelin/lib/Routable.js' => 'b3e7d692',
'rsrc/externals/javelin/lib/Router.js' => '29274e2b',
'rsrc/externals/javelin/lib/Scrollbar.js' => '087e919c',
'rsrc/externals/javelin/lib/Sound.js' => '949c0fe5',
'rsrc/externals/javelin/lib/URI.js' => 'c989ade3',
'rsrc/externals/javelin/lib/Vector.js' => '2caa8fb8',
'rsrc/externals/javelin/lib/WebSocket.js' => 'e292eaf4',
'rsrc/externals/javelin/lib/Workflow.js' => '5b2e3e2b',
'rsrc/externals/javelin/lib/__tests__/Cookie.js' => '5ed109e8',
'rsrc/externals/javelin/lib/__tests__/DOM.js' => 'c984504b',
'rsrc/externals/javelin/lib/__tests__/JSON.js' => '837a7d68',
'rsrc/externals/javelin/lib/__tests__/URI.js' => '1e45fda9',
'rsrc/externals/javelin/lib/__tests__/behavior.js' => '1ea62783',
'rsrc/externals/javelin/lib/behavior.js' => '61cbc29a',
'rsrc/externals/javelin/lib/control/tokenizer/Tokenizer.js' => '8d3bc1b2',
'rsrc/externals/javelin/lib/control/typeahead/Typeahead.js' => '70baed2f',
'rsrc/externals/javelin/lib/control/typeahead/normalizer/TypeaheadNormalizer.js' => 'e6e25838',
'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadCompositeSource.js' => '503e17fd',
'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadOnDemandSource.js' => '013ffff9',
'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadPreloadedSource.js' => '54f314a0',
'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadSource.js' => '1bc11c4a',
'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadStaticSource.js' => '6c0e62fa',
'rsrc/favicons/apple-touch-icon-120x120.png' => '43742962',
'rsrc/favicons/apple-touch-icon-152x152.png' => '669eaec3',
'rsrc/favicons/apple-touch-icon-76x76.png' => 'ecdef672',
'rsrc/favicons/favicon-128.png' => '47cdff03',
'rsrc/favicons/favicon-16x16.png' => 'ee2523ac',
'rsrc/favicons/favicon-32x32.png' => 'b6a8150e',
'rsrc/favicons/favicon-96x96.png' => '8f7ea177',
'rsrc/favicons/mask-icon.svg' => '0460cb1f',
'rsrc/image/BFCFDA.png' => 'd5ec91f4',
'rsrc/image/actions/edit.png' => '2fc41442',
'rsrc/image/avatar.png' => 'e132bb6a',
'rsrc/image/checker_dark.png' => 'd8e65881',
'rsrc/image/checker_light.png' => 'a0155918',
'rsrc/image/checker_lighter.png' => 'd5da91b6',
'rsrc/image/d5d8e1.png' => '0c2a1497',
'rsrc/image/darkload.gif' => '1ffd3ec6',
'rsrc/image/divot.png' => '94dded62',
'rsrc/image/examples/hero.png' => '979a86ae',
'rsrc/image/grippy_texture.png' => 'aca81e2f',
'rsrc/image/icon/fatcow/arrow_branch.png' => '2537c01c',
'rsrc/image/icon/fatcow/arrow_merge.png' => '21b660e0',
'rsrc/image/icon/fatcow/bullet_black.png' => 'ff190031',
'rsrc/image/icon/fatcow/bullet_orange.png' => 'e273e5bb',
'rsrc/image/icon/fatcow/bullet_red.png' => 'c0b75434',
'rsrc/image/icon/fatcow/calendar_edit.png' => '24632275',
'rsrc/image/icon/fatcow/document_black.png' => '45fe1c60',
'rsrc/image/icon/fatcow/flag_blue.png' => 'a01abb1d',
'rsrc/image/icon/fatcow/flag_finish.png' => '67825cee',
'rsrc/image/icon/fatcow/flag_ghost.png' => '20ca8783',
'rsrc/image/icon/fatcow/flag_green.png' => '7e0eaa7a',
'rsrc/image/icon/fatcow/flag_orange.png' => '9e73df66',
'rsrc/image/icon/fatcow/flag_pink.png' => '7e92f3b2',
'rsrc/image/icon/fatcow/flag_purple.png' => 'cc517522',
'rsrc/image/icon/fatcow/flag_red.png' => '04ec726f',
'rsrc/image/icon/fatcow/flag_yellow.png' => '73946fd4',
'rsrc/image/icon/fatcow/key_question.png' => '52a0c26a',
'rsrc/image/icon/fatcow/link.png' => '7afd4d5e',
'rsrc/image/icon/fatcow/page_white_edit.png' => '39a2eed8',
'rsrc/image/icon/fatcow/page_white_put.png' => '08c95a0c',
'rsrc/image/icon/fatcow/source/conduit.png' => '4ea01d2f',
'rsrc/image/icon/fatcow/source/email.png' => '9bab3239',
'rsrc/image/icon/fatcow/source/fax.png' => '04195e68',
'rsrc/image/icon/fatcow/source/mobile.png' => 'f1321264',
'rsrc/image/icon/fatcow/source/tablet.png' => '49396799',
'rsrc/image/icon/fatcow/source/web.png' => '136ccb5d',
'rsrc/image/icon/lightbox/close-2.png' => 'cc40e7c8',
'rsrc/image/icon/lightbox/close-hover-2.png' => 'fb5d6d9e',
'rsrc/image/icon/lightbox/left-arrow-2.png' => '8426133b',
'rsrc/image/icon/lightbox/left-arrow-hover-2.png' => '701e5ee3',
'rsrc/image/icon/lightbox/right-arrow-2.png' => '6d5519a0',
'rsrc/image/icon/lightbox/right-arrow-hover-2.png' => '3a04aa21',
'rsrc/image/icon/subscribe.png' => 'd03ed5a5',
'rsrc/image/icon/tango/attachment.png' => 'ecc8022e',
'rsrc/image/icon/tango/edit.png' => '929a1363',
'rsrc/image/icon/tango/go-down.png' => '96d95e43',
'rsrc/image/icon/tango/log.png' => 'b08cc63a',
'rsrc/image/icon/tango/upload.png' => '7bbb7984',
'rsrc/image/icon/unsubscribe.png' => '25725013',
'rsrc/image/lightblue-header.png' => '5c168b6d',
'rsrc/image/main_texture.png' => '29a2c5ad',
'rsrc/image/menu_texture.png' => '5a17580d',
'rsrc/image/people/harding.png' => '45aa614e',
'rsrc/image/people/jefferson.png' => 'afca0e53',
'rsrc/image/people/lincoln.png' => '9369126d',
'rsrc/image/people/mckinley.png' => 'fb8f16ce',
'rsrc/image/people/taft.png' => 'd7bc402c',
'rsrc/image/people/user0.png' => '03dacaea',
'rsrc/image/people/user1.png' => '4a4e7702',
'rsrc/image/people/user2.png' => '47a0ee40',
'rsrc/image/people/user3.png' => '835ff627',
'rsrc/image/people/user4.png' => 'b0e830f1',
'rsrc/image/people/user5.png' => '9c95b369',
'rsrc/image/people/user6.png' => 'ba3fbfb0',
'rsrc/image/people/user7.png' => 'da613924',
'rsrc/image/people/user8.png' => 'f1035edf',
'rsrc/image/people/user9.png' => '66730be3',
'rsrc/image/people/washington.png' => '40dd301c',
'rsrc/image/phrequent_active.png' => 'a466a8ed',
'rsrc/image/phrequent_inactive.png' => 'bfc15a69',
'rsrc/image/sprite-login-X2.png' => 'e3991e37',
'rsrc/image/sprite-login.png' => '03d5af29',
'rsrc/image/sprite-menu-X2.png' => 'cfd8fca5',
'rsrc/image/sprite-menu.png' => 'd7a99faa',
'rsrc/image/sprite-tokens-X2.png' => '348f1745',
'rsrc/image/sprite-tokens.png' => 'ce0b62be',
'rsrc/image/texture/card-gradient.png' => '815f26e8',
'rsrc/image/texture/dark-menu-hover.png' => '5fa7ece8',
'rsrc/image/texture/dark-menu.png' => '7e22296e',
'rsrc/image/texture/grip.png' => '719404f3',
'rsrc/image/texture/panel-header-gradient.png' => 'e3b8dcfe',
'rsrc/image/texture/phlnx-bg.png' => '8d819209',
'rsrc/image/texture/pholio-background.gif' => 'ba29239c',
'rsrc/image/texture/table_header.png' => '5c433037',
'rsrc/image/texture/table_header_hover.png' => '038ec3b9',
'rsrc/image/texture/table_header_tall.png' => 'd56b434f',
'rsrc/js/application/aphlict/Aphlict.js' => '5359e785',
'rsrc/js/application/aphlict/behavior-aphlict-dropdown.js' => '031cee25',
'rsrc/js/application/aphlict/behavior-aphlict-listen.js' => 'fb20ac8d',
'rsrc/js/application/aphlict/behavior-aphlict-status.js' => 'ea681761',
'rsrc/js/application/aphlict/behavior-desktop-notifications-control.js' => 'edd1ba66',
'rsrc/js/application/auth/behavior-persona-login.js' => '9414ff18',
'rsrc/js/application/calendar/behavior-day-view.js' => '5c46cff2',
'rsrc/js/application/calendar/behavior-event-all-day.js' => '38dcf3c8',
'rsrc/js/application/calendar/behavior-recurring-edit.js' => '5f1c4d5f',
'rsrc/js/application/config/behavior-reorder-fields.js' => 'b6993408',
'rsrc/js/application/conpherence/ConpherenceThreadManager.js' => '01774ab2',
'rsrc/js/application/conpherence/behavior-drag-and-drop-photo.js' => 'cf86d16a',
'rsrc/js/application/conpherence/behavior-durable-column.js' => 'c72aa091',
'rsrc/js/application/conpherence/behavior-menu.js' => '1d45c74d',
'rsrc/js/application/conpherence/behavior-pontificate.js' => '21ba5861',
'rsrc/js/application/conpherence/behavior-quicksand-blacklist.js' => '7927a7d3',
'rsrc/js/application/conpherence/behavior-widget-pane.js' => 'a8458711',
'rsrc/js/application/countdown/timer.js' => 'e4cc26b3',
'rsrc/js/application/daemon/behavior-bulk-job-reload.js' => 'edf8a145',
'rsrc/js/application/dashboard/behavior-dashboard-async-panel.js' => '469c0d9e',
'rsrc/js/application/dashboard/behavior-dashboard-move-panels.js' => '019f36c4',
'rsrc/js/application/dashboard/behavior-dashboard-query-panel-select.js' => '453c5375',
'rsrc/js/application/dashboard/behavior-dashboard-tab-panel.js' => 'd4eecc63',
'rsrc/js/application/differential/ChangesetViewManager.js' => 'a2828756',
'rsrc/js/application/differential/DifferentialInlineCommentEditor.js' => '64a5550f',
'rsrc/js/application/differential/behavior-add-reviewers-and-ccs.js' => 'e10f8e18',
'rsrc/js/application/differential/behavior-comment-jump.js' => '4fdb476d',
'rsrc/js/application/differential/behavior-comment-preview.js' => 'b064af76',
'rsrc/js/application/differential/behavior-diff-radios.js' => 'e1ff79b1',
'rsrc/js/application/differential/behavior-dropdown-menus.js' => '9a6b9324',
'rsrc/js/application/differential/behavior-edit-inline-comments.js' => '4fbbc3e9',
'rsrc/js/application/differential/behavior-keyboard-nav.js' => '2c426492',
'rsrc/js/application/differential/behavior-populate.js' => '8694b1df',
'rsrc/js/application/differential/behavior-toggle-files.js' => 'ca3f91eb',
'rsrc/js/application/differential/behavior-user-select.js' => 'a8d8459d',
'rsrc/js/application/diffusion/DiffusionLocateFileSource.js' => 'b42eddc7',
'rsrc/js/application/diffusion/behavior-audit-preview.js' => 'd835b03a',
'rsrc/js/application/diffusion/behavior-commit-branches.js' => 'bdaf4d04',
'rsrc/js/application/diffusion/behavior-commit-graph.js' => '5a0b1a64',
'rsrc/js/application/diffusion/behavior-jump-to.js' => '73d09eef',
'rsrc/js/application/diffusion/behavior-load-blame.js' => '42126667',
'rsrc/js/application/diffusion/behavior-locate-file.js' => '6d3e1947',
'rsrc/js/application/diffusion/behavior-pull-lastmodified.js' => 'f01586dc',
'rsrc/js/application/doorkeeper/behavior-doorkeeper-tag.js' => 'e5822781',
'rsrc/js/application/drydock/drydock-live-operation-status.js' => '901935ef',
'rsrc/js/application/files/behavior-icon-composer.js' => '8499b6ab',
'rsrc/js/application/files/behavior-launch-icon-composer.js' => '48086888',
'rsrc/js/application/herald/HeraldRuleEditor.js' => '746ca158',
'rsrc/js/application/herald/PathTypeahead.js' => 'f7fc67ec',
'rsrc/js/application/herald/herald-rule-editor.js' => '7ebaeed3',
'rsrc/js/application/maniphest/behavior-batch-editor.js' => '782ab6e7',
'rsrc/js/application/maniphest/behavior-batch-selector.js' => '7b98d7c5',
'rsrc/js/application/maniphest/behavior-line-chart.js' => 'e4232876',
'rsrc/js/application/maniphest/behavior-list-edit.js' => 'a9f88de2',
'rsrc/js/application/maniphest/behavior-subpriorityeditor.js' => '71237763',
'rsrc/js/application/owners/OwnersPathEditor.js' => 'aa1733d0',
'rsrc/js/application/owners/owners-path-editor.js' => '7a68dda3',
'rsrc/js/application/passphrase/passphrase-credential-control.js' => '3cb0b2fc',
'rsrc/js/application/pholio/behavior-pholio-mock-edit.js' => '246dc085',
'rsrc/js/application/pholio/behavior-pholio-mock-view.js' => 'fbe497e7',
'rsrc/js/application/phortune/behavior-stripe-payment-form.js' => '3f5d6dbf',
'rsrc/js/application/phortune/behavior-test-payment-form.js' => 'fc91ab6c',
'rsrc/js/application/phortune/phortune-credit-card-form.js' => '2290aeef',
'rsrc/js/application/policy/behavior-policy-control.js' => 'd0c516d5',
'rsrc/js/application/policy/behavior-policy-rule-editor.js' => '5e9f347c',
'rsrc/js/application/projects/WorkboardBoard.js' => '52291776',
'rsrc/js/application/projects/WorkboardCard.js' => 'c587b80f',
'rsrc/js/application/projects/WorkboardColumn.js' => 'bae58312',
'rsrc/js/application/projects/WorkboardController.js' => '55baf5ed',
'rsrc/js/application/projects/behavior-project-boards.js' => '14a1faae',
'rsrc/js/application/projects/behavior-project-create.js' => '065227cc',
'rsrc/js/application/projects/behavior-reorder-columns.js' => 'e1d25dfb',
'rsrc/js/application/releeph/releeph-preview-branch.js' => 'b2b4fbaf',
'rsrc/js/application/releeph/releeph-request-state-change.js' => 'a0b57eb8',
'rsrc/js/application/releeph/releeph-request-typeahead.js' => 'de2e896f',
'rsrc/js/application/repository/repository-crossreference.js' => 'e5339c43',
'rsrc/js/application/search/behavior-reorder-profile-menu-items.js' => 'e2e0a072',
'rsrc/js/application/search/behavior-reorder-queries.js' => 'e9581f08',
'rsrc/js/application/slowvote/behavior-slowvote-embed.js' => '887ad43f',
'rsrc/js/application/transactions/behavior-comment-actions.js' => '1f2fcaf8',
'rsrc/js/application/transactions/behavior-reorder-configs.js' => 'd7a74243',
'rsrc/js/application/transactions/behavior-reorder-fields.js' => 'b59e1e96',
'rsrc/js/application/transactions/behavior-show-older-transactions.js' => 'dbbf48b6',
'rsrc/js/application/transactions/behavior-transaction-comment-form.js' => 'b23b49e6',
'rsrc/js/application/transactions/behavior-transaction-list.js' => '13c739ea',
'rsrc/js/application/typeahead/behavior-typeahead-browse.js' => '635de1ec',
'rsrc/js/application/typeahead/behavior-typeahead-search.js' => '93d0c9e3',
'rsrc/js/application/uiexample/JavelinViewExample.js' => 'd4a14807',
'rsrc/js/application/uiexample/ReactorButtonExample.js' => 'd19198c8',
'rsrc/js/application/uiexample/ReactorCheckboxExample.js' => '519705ea',
'rsrc/js/application/uiexample/ReactorFocusExample.js' => '40a6a403',
'rsrc/js/application/uiexample/ReactorInputExample.js' => '886fd850',
'rsrc/js/application/uiexample/ReactorMouseoverExample.js' => '47c794d8',
'rsrc/js/application/uiexample/ReactorRadioExample.js' => '988040b4',
'rsrc/js/application/uiexample/ReactorSelectExample.js' => 'a155550f',
'rsrc/js/application/uiexample/ReactorSendClassExample.js' => '1def2711',
'rsrc/js/application/uiexample/ReactorSendPropertiesExample.js' => 'b1f0ccee',
'rsrc/js/application/uiexample/busy-example.js' => '60479091',
'rsrc/js/application/uiexample/gesture-example.js' => '558829c2',
'rsrc/js/application/uiexample/notification-example.js' => '8ce821c5',
'rsrc/js/core/Busy.js' => '59a7976a',
'rsrc/js/core/DragAndDropFileUpload.js' => '81f182b5',
'rsrc/js/core/DraggableList.js' => '5a13c79f',
'rsrc/js/core/FileUpload.js' => '680ea2c8',
'rsrc/js/core/Hovercard.js' => '1bd28176',
'rsrc/js/core/KeyboardShortcut.js' => '1ae869f2',
'rsrc/js/core/KeyboardShortcutManager.js' => 'c1700f6f',
'rsrc/js/core/MultirowRowManager.js' => 'b5d57730',
'rsrc/js/core/Notification.js' => 'ccf1cbf8',
'rsrc/js/core/Prefab.js' => 'e67df814',
'rsrc/js/core/ShapedRequest.js' => '7cbe244b',
'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',
'rsrc/js/core/behavior-audio-source.js' => '59b251eb',
'rsrc/js/core/behavior-autofocus.js' => '7319e029',
'rsrc/js/core/behavior-choose-control.js' => '327a00d1',
'rsrc/js/core/behavior-crop.js' => 'fa0f4fc2',
'rsrc/js/core/behavior-dark-console.js' => 'f411b6ae',
'rsrc/js/core/behavior-device.js' => 'b5b36110',
'rsrc/js/core/behavior-drag-and-drop-textarea.js' => '4f6a4b4e',
'rsrc/js/core/behavior-error-log.js' => '6882e80a',
'rsrc/js/core/behavior-fancy-datepicker.js' => '8ae55229',
'rsrc/js/core/behavior-file-tree.js' => '88236f00',
'rsrc/js/core/behavior-form.js' => '5c54cbf3',
'rsrc/js/core/behavior-gesture.js' => '3ab51e2c',
'rsrc/js/core/behavior-global-drag-and-drop.js' => 'c8e57404',
'rsrc/js/core/behavior-high-security-warning.js' => 'a464fe03',
'rsrc/js/core/behavior-history-install.js' => '7ee2b591',
'rsrc/js/core/behavior-hovercard.js' => 'bcaccd64',
'rsrc/js/core/behavior-keyboard-pager.js' => 'a8da01f0',
'rsrc/js/core/behavior-keyboard-shortcuts.js' => 'd75709e6',
'rsrc/js/core/behavior-lightbox-attachments.js' => 'f8ba29d7',
'rsrc/js/core/behavior-line-linker.js' => '1499a8cb',
'rsrc/js/core/behavior-more.js' => 'a80d0378',
'rsrc/js/core/behavior-object-selector.js' => '49b73b36',
'rsrc/js/core/behavior-oncopy.js' => '2926fff2',
'rsrc/js/core/behavior-phabricator-nav.js' => '56a1ca03',
'rsrc/js/core/behavior-phabricator-remarkup-assist.js' => '340c8eff',
'rsrc/js/core/behavior-refresh-csrf.js' => 'ab2f381b',
'rsrc/js/core/behavior-remarkup-preview.js' => '4b700e9e',
'rsrc/js/core/behavior-reorder-applications.js' => '76b9fc3e',
'rsrc/js/core/behavior-reveal-content.js' => '60821bc7',
'rsrc/js/core/behavior-scrollbar.js' => '834a1173',
'rsrc/js/core/behavior-search-typeahead.js' => '06c32383',
'rsrc/js/core/behavior-select-on-click.js' => '4e3e79a6',
'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' => '42fcb747',
'rsrc/js/core/behavior-watch-anchor.js' => '9f36c42d',
'rsrc/js/core/behavior-workflow.js' => '0a3f3021',
'rsrc/js/core/phtize.js' => 'd254d646',
'rsrc/js/phui/behavior-phui-dropdown-menu.js' => '54733475',
'rsrc/js/phui/behavior-phui-object-box-tabs.js' => '2bfa2836',
'rsrc/js/phui/behavior-phui-profile-menu.js' => '12884df9',
'rsrc/js/phuix/PHUIXActionListView.js' => 'b5c256b8',
'rsrc/js/phuix/PHUIXActionView.js' => '8cf6d262',
'rsrc/js/phuix/PHUIXAutocomplete.js' => '9196fb06',
'rsrc/js/phuix/PHUIXDropdownMenu.js' => 'bd4c8dca',
'rsrc/js/phuix/PHUIXFormControl.js' => 'a7763e11',
'rsrc/js/phuix/PHUIXIconView.js' => 'bff6884b',
),
'symbols' => array(
'almanac-css' => 'dbb9b3af',
'aphront-bars' => '231ac33c',
'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' => '036b6cdc',
'aphront-tokenizer-control-css' => '056da01b',
'aphront-tooltip-css' => '1a07aea8',
'aphront-typeahead-control-css' => 'd4f16145',
'auth-css' => '0877ed6e',
'bulk-job-css' => 'df9c1d4a',
'changeset-view-manager' => 'a2828756',
'conduit-api-css' => '7bc725c4',
'config-options-css' => '0ede4c9b',
'config-welcome-css' => '6abd79be',
'conpherence-durable-column-view' => '86396117',
'conpherence-menu-css' => 'f99fee4c',
'conpherence-message-pane-css' => '5897d3ac',
'conpherence-notification-css' => '6cdcc253',
'conpherence-thread-manager' => '01774ab2',
'conpherence-transaction-css' => '85d0974c',
'conpherence-update-css' => 'faf6be09',
'conpherence-widget-pane-css' => '775eaaba',
'd3' => 'a11a5ff2',
'differential-changeset-view-css' => '3e3b0b76',
'differential-core-view-css' => '5b7b8ff4',
'differential-inline-comment-editor' => '64a5550f',
'differential-revision-add-comment-css' => 'c47f8c40',
'differential-revision-comment-css' => '14b8565a',
'differential-revision-history-css' => '0e8eb855',
'differential-revision-list-css' => 'f3c47d33',
'differential-table-of-contents-css' => 'ae4b7a55',
- 'diffusion-icons-css' => '2941baf1',
+ 'diffusion-icons-css' => '3311444d',
'diffusion-readme-css' => '356a4f3c',
- 'diffusion-source-css' => '075ba788',
+ 'diffusion-source-css' => '68b30fd3',
'diviner-shared-css' => 'aa3656aa',
'font-aleo' => '8bdb2835',
'font-fontawesome' => 'c43323c5',
'font-lato' => 'c7ccd872',
'global-drag-and-drop-css' => '5c1b47c2',
'harbormaster-css' => '834879db',
'herald-css' => 'dc31f6e9',
'herald-rule-editor' => '746ca158',
'herald-test-css' => 'a52e323e',
'inline-comment-summary-css' => '51efda3a',
'javelin-aphlict' => '5359e785',
'javelin-behavior' => '61cbc29a',
'javelin-behavior-aphlict-dropdown' => '031cee25',
'javelin-behavior-aphlict-listen' => 'fb20ac8d',
'javelin-behavior-aphlict-status' => 'ea681761',
'javelin-behavior-aphront-basic-tokenizer' => 'b3a4b884',
'javelin-behavior-aphront-crop' => 'fa0f4fc2',
'javelin-behavior-aphront-drag-and-drop-textarea' => '4f6a4b4e',
'javelin-behavior-aphront-form-disable-on-submit' => '5c54cbf3',
'javelin-behavior-aphront-more' => 'a80d0378',
'javelin-behavior-audio-source' => '59b251eb',
'javelin-behavior-audit-preview' => 'd835b03a',
'javelin-behavior-bulk-job-reload' => 'edf8a145',
'javelin-behavior-choose-control' => '327a00d1',
'javelin-behavior-comment-actions' => '1f2fcaf8',
'javelin-behavior-config-reorder-fields' => 'b6993408',
'javelin-behavior-conpherence-drag-and-drop-photo' => 'cf86d16a',
'javelin-behavior-conpherence-menu' => '1d45c74d',
'javelin-behavior-conpherence-pontificate' => '21ba5861',
'javelin-behavior-conpherence-widget-pane' => 'a8458711',
'javelin-behavior-countdown-timer' => 'e4cc26b3',
'javelin-behavior-dark-console' => 'f411b6ae',
'javelin-behavior-dashboard-async-panel' => '469c0d9e',
'javelin-behavior-dashboard-move-panels' => '019f36c4',
'javelin-behavior-dashboard-query-panel-select' => '453c5375',
'javelin-behavior-dashboard-tab-panel' => 'd4eecc63',
'javelin-behavior-day-view' => '5c46cff2',
'javelin-behavior-desktop-notifications-control' => 'edd1ba66',
'javelin-behavior-device' => 'b5b36110',
'javelin-behavior-differential-add-reviewers-and-ccs' => 'e10f8e18',
'javelin-behavior-differential-comment-jump' => '4fdb476d',
'javelin-behavior-differential-diff-radios' => 'e1ff79b1',
'javelin-behavior-differential-dropdown-menus' => '9a6b9324',
'javelin-behavior-differential-edit-inline-comments' => '4fbbc3e9',
'javelin-behavior-differential-feedback-preview' => 'b064af76',
'javelin-behavior-differential-keyboard-navigation' => '2c426492',
'javelin-behavior-differential-populate' => '8694b1df',
'javelin-behavior-differential-toggle-files' => 'ca3f91eb',
'javelin-behavior-differential-user-select' => 'a8d8459d',
'javelin-behavior-diffusion-commit-branches' => 'bdaf4d04',
'javelin-behavior-diffusion-commit-graph' => '5a0b1a64',
'javelin-behavior-diffusion-jump-to' => '73d09eef',
'javelin-behavior-diffusion-locate-file' => '6d3e1947',
'javelin-behavior-diffusion-pull-lastmodified' => 'f01586dc',
'javelin-behavior-doorkeeper-tag' => 'e5822781',
'javelin-behavior-drydock-live-operation-status' => '901935ef',
'javelin-behavior-durable-column' => 'c72aa091',
'javelin-behavior-editengine-reorder-configs' => 'd7a74243',
'javelin-behavior-editengine-reorder-fields' => 'b59e1e96',
'javelin-behavior-error-log' => '6882e80a',
'javelin-behavior-event-all-day' => '38dcf3c8',
'javelin-behavior-fancy-datepicker' => '8ae55229',
'javelin-behavior-global-drag-and-drop' => 'c8e57404',
'javelin-behavior-herald-rule-editor' => '7ebaeed3',
'javelin-behavior-high-security-warning' => 'a464fe03',
'javelin-behavior-history-install' => '7ee2b591',
'javelin-behavior-icon-composer' => '8499b6ab',
'javelin-behavior-launch-icon-composer' => '48086888',
'javelin-behavior-lightbox-attachments' => 'f8ba29d7',
'javelin-behavior-line-chart' => 'e4232876',
'javelin-behavior-load-blame' => '42126667',
'javelin-behavior-maniphest-batch-editor' => '782ab6e7',
'javelin-behavior-maniphest-batch-selector' => '7b98d7c5',
'javelin-behavior-maniphest-list-editor' => 'a9f88de2',
'javelin-behavior-maniphest-subpriority-editor' => '71237763',
'javelin-behavior-owners-path-editor' => '7a68dda3',
'javelin-behavior-passphrase-credential-control' => '3cb0b2fc',
'javelin-behavior-persona-login' => '9414ff18',
'javelin-behavior-phabricator-active-nav' => 'e379b58e',
'javelin-behavior-phabricator-autofocus' => '7319e029',
'javelin-behavior-phabricator-busy-example' => '60479091',
'javelin-behavior-phabricator-file-tree' => '88236f00',
'javelin-behavior-phabricator-gesture' => '3ab51e2c',
'javelin-behavior-phabricator-gesture-example' => '558829c2',
'javelin-behavior-phabricator-keyboard-pager' => 'a8da01f0',
'javelin-behavior-phabricator-keyboard-shortcuts' => 'd75709e6',
'javelin-behavior-phabricator-line-linker' => '1499a8cb',
'javelin-behavior-phabricator-nav' => '56a1ca03',
'javelin-behavior-phabricator-notification-example' => '8ce821c5',
'javelin-behavior-phabricator-object-selector' => '49b73b36',
'javelin-behavior-phabricator-oncopy' => '2926fff2',
'javelin-behavior-phabricator-remarkup-assist' => '340c8eff',
'javelin-behavior-phabricator-reveal-content' => '60821bc7',
'javelin-behavior-phabricator-search-typeahead' => '06c32383',
'javelin-behavior-phabricator-show-older-transactions' => 'dbbf48b6',
'javelin-behavior-phabricator-tooltips' => '42fcb747',
'javelin-behavior-phabricator-transaction-comment-form' => 'b23b49e6',
'javelin-behavior-phabricator-transaction-list' => '13c739ea',
'javelin-behavior-phabricator-watch-anchor' => '9f36c42d',
'javelin-behavior-pholio-mock-edit' => '246dc085',
'javelin-behavior-pholio-mock-view' => 'fbe497e7',
'javelin-behavior-phui-dropdown-menu' => '54733475',
'javelin-behavior-phui-hovercards' => 'bcaccd64',
'javelin-behavior-phui-object-box-tabs' => '2bfa2836',
'javelin-behavior-phui-profile-menu' => '12884df9',
'javelin-behavior-policy-control' => 'd0c516d5',
'javelin-behavior-policy-rule-editor' => '5e9f347c',
'javelin-behavior-project-boards' => '14a1faae',
'javelin-behavior-project-create' => '065227cc',
'javelin-behavior-quicksand-blacklist' => '7927a7d3',
'javelin-behavior-recurring-edit' => '5f1c4d5f',
'javelin-behavior-refresh-csrf' => 'ab2f381b',
'javelin-behavior-releeph-preview-branch' => 'b2b4fbaf',
'javelin-behavior-releeph-request-state-change' => 'a0b57eb8',
'javelin-behavior-releeph-request-typeahead' => 'de2e896f',
'javelin-behavior-remarkup-preview' => '4b700e9e',
'javelin-behavior-reorder-applications' => '76b9fc3e',
'javelin-behavior-reorder-columns' => 'e1d25dfb',
'javelin-behavior-reorder-profile-menu-items' => 'e2e0a072',
'javelin-behavior-repository-crossreference' => 'e5339c43',
'javelin-behavior-scrollbar' => '834a1173',
'javelin-behavior-search-reorder-queries' => 'e9581f08',
'javelin-behavior-select-on-click' => '4e3e79a6',
'javelin-behavior-slowvote-embed' => '887ad43f',
'javelin-behavior-stripe-payment-form' => '3f5d6dbf',
'javelin-behavior-test-payment-form' => 'fc91ab6c',
'javelin-behavior-time-typeahead' => 'f80d6bf0',
'javelin-behavior-toggle-class' => '5d7c9f33',
'javelin-behavior-typeahead-browse' => '635de1ec',
'javelin-behavior-typeahead-search' => '93d0c9e3',
'javelin-behavior-view-placeholder' => '47830651',
'javelin-behavior-workflow' => '0a3f3021',
'javelin-color' => '7e41274a',
'javelin-cookie' => '62dfea03',
'javelin-diffusion-locate-file-source' => 'b42eddc7',
'javelin-dom' => '805b806a',
'javelin-dynval' => 'f6555212',
'javelin-event' => '2ee659ce',
'javelin-fx' => '54b612ba',
'javelin-history' => 'd4505101',
'javelin-install' => '05270951',
'javelin-json' => '69adf288',
'javelin-leader' => '331b1611',
'javelin-magical-init' => '3010e992',
'javelin-mask' => '8a41885b',
'javelin-quicksand' => '6b8ef10b',
'javelin-reactor' => '2b8de964',
'javelin-reactor-dom' => 'c90a04fc',
'javelin-reactor-node-calmer' => '76f4ebed',
'javelin-reactornode' => '1ad0a787',
'javelin-request' => '94b750d2',
'javelin-resource' => '44959b73',
'javelin-routable' => 'b3e7d692',
'javelin-router' => '29274e2b',
'javelin-scrollbar' => '087e919c',
'javelin-sound' => '949c0fe5',
'javelin-stratcom' => '6ad39b6f',
'javelin-tokenizer' => '8d3bc1b2',
'javelin-typeahead' => '70baed2f',
'javelin-typeahead-composite-source' => '503e17fd',
'javelin-typeahead-normalizer' => 'e6e25838',
'javelin-typeahead-ondemand-source' => '013ffff9',
'javelin-typeahead-preloaded-source' => '54f314a0',
'javelin-typeahead-source' => '1bc11c4a',
'javelin-typeahead-static-source' => '6c0e62fa',
'javelin-uri' => 'c989ade3',
'javelin-util' => '93cc50d6',
'javelin-vector' => '2caa8fb8',
'javelin-view' => '0f764c35',
'javelin-view-html' => 'fe287620',
'javelin-view-interpreter' => 'f829edb3',
'javelin-view-renderer' => '6c2b09a2',
'javelin-view-visitor' => 'efe49472',
'javelin-websocket' => 'e292eaf4',
'javelin-workboard-board' => '52291776',
'javelin-workboard-card' => 'c587b80f',
'javelin-workboard-column' => 'bae58312',
'javelin-workboard-controller' => '55baf5ed',
'javelin-workflow' => '5b2e3e2b',
'lightbox-attachment-css' => '7acac05d',
'maniphest-batch-editor' => 'b0f0b6d5',
'maniphest-report-css' => '9b9580b7',
'maniphest-task-edit-css' => 'fda62a9b',
'maniphest-task-summary-css' => '11cc5344',
'multirow-row-manager' => 'b5d57730',
'owners-path-editor' => 'aa1733d0',
'owners-path-editor-css' => '2f00933b',
'paste-css' => '1898e534',
'path-typeahead' => 'f7fc67ec',
'people-profile-css' => '2473d929',
'phabricator-action-list-view-css' => 'c5eba19d',
'phabricator-application-launch-view-css' => '95351601',
'phabricator-busy' => '59a7976a',
'phabricator-chatlog-css' => 'd295b020',
'phabricator-content-source-view-css' => '4b8b05d4',
'phabricator-core-css' => 'd0801452',
'phabricator-countdown-css' => '96696f21',
'phabricator-dashboard-css' => 'eb458607',
'phabricator-drag-and-drop-file-upload' => '81f182b5',
'phabricator-draggable-list' => '5a13c79f',
'phabricator-fatal-config-template-css' => '8e6c6fcd',
'phabricator-feed-css' => 'ecd4ec57',
'phabricator-file-upload' => '680ea2c8',
'phabricator-filetree-view-css' => 'fccf9f82',
'phabricator-flag-css' => '5337623f',
'phabricator-keyboard-shortcut' => '1ae869f2',
'phabricator-keyboard-shortcut-manager' => 'c1700f6f',
'phabricator-main-menu-view' => 'd00a795a',
'phabricator-nav-view-css' => 'ac79a758',
'phabricator-notification' => 'ccf1cbf8',
'phabricator-notification-css' => '7f684b62',
'phabricator-notification-menu-css' => 'f31c0bde',
'phabricator-object-selector-css' => '85ee8ce6',
'phabricator-phtize' => 'd254d646',
'phabricator-prefab' => 'e67df814',
'phabricator-remarkup-css' => 'fc228f08',
'phabricator-search-results-css' => '7dea472c',
'phabricator-shaped-request' => '7cbe244b',
'phabricator-side-menu-view-css' => '3a3d9f41',
'phabricator-slowvote-css' => 'a94b7230',
'phabricator-source-code-view-css' => 'cbeef983',
'phabricator-standard-page-view' => 'e709f6d0',
'phabricator-textareautils' => '5813016a',
'phabricator-title' => 'df5e11d2',
'phabricator-tooltip' => '6323f942',
'phabricator-ui-example-css' => '528b19de',
'phabricator-uiexample-javelin-view' => 'd4a14807',
'phabricator-uiexample-reactor-button' => 'd19198c8',
'phabricator-uiexample-reactor-checkbox' => '519705ea',
'phabricator-uiexample-reactor-focus' => '40a6a403',
'phabricator-uiexample-reactor-input' => '886fd850',
'phabricator-uiexample-reactor-mouseover' => '47c794d8',
'phabricator-uiexample-reactor-radio' => '988040b4',
'phabricator-uiexample-reactor-select' => 'a155550f',
'phabricator-uiexample-reactor-sendclass' => '1def2711',
'phabricator-uiexample-reactor-sendproperties' => 'b1f0ccee',
'phabricator-zindex-css' => '5b6fcf3f',
'phame-css' => '737792d6',
'pholio-css' => 'ca89d380',
'pholio-edit-css' => '3ad9d1ee',
'pholio-inline-comments-css' => '8e545e49',
'phortune-credit-card-form' => '2290aeef',
'phortune-credit-card-form-css' => '8391eb02',
'phortune-css' => '9149f103',
'phrequent-css' => 'ffc185ad',
'phriction-document-css' => 'd1861e06',
'phui-action-panel-css' => '91c7b835',
'phui-badge-view-css' => 'f25c3476',
'phui-big-info-view-css' => 'bd903741',
- 'phui-box-css' => '96a10c5d',
+ 'phui-box-css' => 'b2d49bae',
'phui-button-css' => 'a64a8de6',
'phui-calendar-css' => 'ccabe893',
'phui-calendar-day-css' => 'd1cf6f93',
'phui-calendar-list-css' => 'c1c7f338',
'phui-calendar-month-css' => '476be7e0',
'phui-chart-css' => '6bf6f78e',
'phui-crumbs-view-css' => '79d536e5',
'phui-curtain-view-css' => '7148ae25',
'phui-document-summary-view-css' => '9ca48bdf',
'phui-document-view-css' => '9c71d2bf',
'phui-document-view-pro-css' => '92d5b648',
'phui-feed-story-css' => '04aec08f',
'phui-font-icon-base-css' => '6449bce8',
'phui-fontkit-css' => '9cda225e',
'phui-form-css' => 'aac1d51d',
'phui-form-view-css' => '4a1a0f5e',
- 'phui-head-thing-view-css' => '31638812',
- 'phui-header-view-css' => '26cffd3d',
+ 'phui-head-thing-view-css' => 'fd311e5f',
+ 'phui-header-view-css' => '230254d3',
'phui-hovercard' => '1bd28176',
'phui-hovercard-view-css' => 'de1a2119',
'phui-icon-set-selector-css' => '1ab67aad',
'phui-icon-view-css' => '3f33ab57',
'phui-image-mask-css' => 'a8498f9c',
'phui-info-panel-css' => '27ea50a1',
- 'phui-info-view-css' => '6d7c3509',
+ 'phui-info-view-css' => '28efab79',
'phui-inline-comment-view-css' => '5953c28e',
'phui-list-view-css' => '9da2aa00',
'phui-object-box-css' => '6b487c57',
'phui-object-item-list-view-css' => '18b2ce8e',
'phui-pager-css' => 'bea33d23',
'phui-pinboard-view-css' => '2495140e',
'phui-profile-menu-css' => '7e92a89a',
- 'phui-property-list-view-css' => 'b12e801c',
+ 'phui-property-list-view-css' => '1d42ee7c',
'phui-remarkup-preview-css' => '1a8f2591',
'phui-segment-bar-view-css' => '46342871',
'phui-spacing-css' => '042804d6',
'phui-status-list-view-css' => '37309046',
'phui-tag-view-css' => '6bbd83e2',
'phui-theme-css' => '027ba77e',
'phui-timeline-view-css' => 'a0173eba',
- 'phui-two-column-view-css' => '61dd6d38',
+ 'phui-two-column-view-css' => 'c110d0c3',
'phui-workboard-color-css' => 'ac6fe6a7',
'phui-workboard-view-css' => 'e6d89647',
'phui-workcard-view-css' => '3646fb96',
'phui-workpanel-view-css' => '92197373',
'phuix-action-list-view' => 'b5c256b8',
'phuix-action-view' => '8cf6d262',
'phuix-autocomplete' => '9196fb06',
'phuix-dropdown-menu' => 'bd4c8dca',
'phuix-form-control-view' => 'a7763e11',
'phuix-icon-view' => 'bff6884b',
'policy-css' => '957ea14c',
'policy-edit-css' => '815c66f7',
'policy-transaction-detail-css' => '82100a43',
'ponder-view-css' => 'fbd45f96',
'project-card-view-css' => '9418c97d',
'project-view-css' => '9ce99f21',
'releeph-core' => '9b3c5733',
'releeph-preview-branch' => 'b7a6f4a5',
'releeph-request-differential-create-dialog' => '8d8b92cd',
'releeph-request-typeahead-css' => '667a48ae',
'setup-issue-css' => 'db7e9c40',
'sprite-login-css' => '60e8560e',
'sprite-menu-css' => '9dd65b92',
'sprite-tokens-css' => '4f399012',
'syntax-highlighting-css' => '9fd11da8',
'tokens-css' => '3d0f239e',
'typeahead-browse-css' => 'd8581d2c',
'unhandled-exception-css' => '4c96257a',
),
'requires' => array(
'013ffff9' => array(
'javelin-install',
'javelin-util',
'javelin-request',
'javelin-typeahead-source',
),
'01774ab2' => array(
'javelin-dom',
'javelin-util',
'javelin-stratcom',
'javelin-install',
'javelin-aphlict',
'javelin-workflow',
'javelin-router',
'javelin-behavior-device',
'javelin-vector',
),
'019f36c4' => array(
'javelin-behavior',
'javelin-dom',
'javelin-util',
'javelin-stratcom',
'javelin-workflow',
'phabricator-draggable-list',
),
'031cee25' => array(
'javelin-behavior',
'javelin-request',
'javelin-stratcom',
'javelin-vector',
'javelin-dom',
'javelin-uri',
'javelin-behavior-device',
'phabricator-title',
),
'05270951' => array(
'javelin-util',
'javelin-magical-init',
),
'056da01b' => array(
'aphront-typeahead-control-css',
'phui-tag-view-css',
),
'065227cc' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
'javelin-workflow',
),
'06c32383' => array(
'javelin-behavior',
'javelin-typeahead-ondemand-source',
'javelin-typeahead',
'javelin-dom',
'javelin-uri',
'javelin-util',
'javelin-stratcom',
'phabricator-prefab',
'phuix-icon-view',
),
'087e919c' => array(
'javelin-install',
'javelin-dom',
'javelin-stratcom',
'javelin-vector',
),
'0a3f3021' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-workflow',
'javelin-dom',
'javelin-router',
),
'0f764c35' => array(
'javelin-install',
'javelin-util',
),
'12884df9' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
),
'13c739ea' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-workflow',
'javelin-dom',
'javelin-uri',
'phabricator-textareautils',
),
'1499a8cb' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
'javelin-history',
),
'14a1faae' => array(
'javelin-behavior',
'javelin-dom',
'javelin-util',
'javelin-vector',
'javelin-stratcom',
'javelin-workflow',
'javelin-workboard-controller',
),
'1ad0a787' => array(
'javelin-install',
'javelin-reactor',
'javelin-util',
'javelin-reactor-node-calmer',
),
'1ae869f2' => array(
'javelin-install',
'javelin-util',
'phabricator-keyboard-shortcut-manager',
),
'1bc11c4a' => array(
'javelin-install',
'javelin-util',
'javelin-dom',
'javelin-typeahead-normalizer',
),
'1bd28176' => array(
'javelin-install',
'javelin-dom',
'javelin-vector',
'javelin-request',
'javelin-uri',
),
'1d45c74d' => array(
'javelin-behavior',
'javelin-dom',
'javelin-util',
'javelin-stratcom',
'javelin-workflow',
'javelin-behavior-device',
'javelin-history',
'javelin-vector',
'javelin-scrollbar',
'phabricator-title',
'phabricator-shaped-request',
'conpherence-thread-manager',
),
'1def2711' => array(
'javelin-install',
'javelin-dom',
'javelin-reactor-dom',
),
'1f2fcaf8' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-workflow',
'javelin-dom',
'phuix-form-control-view',
'phuix-icon-view',
'javelin-behavior-phabricator-gesture',
),
'21ba5861' => array(
'javelin-behavior',
'javelin-dom',
'javelin-util',
'javelin-workflow',
'javelin-stratcom',
'conpherence-thread-manager',
),
'2290aeef' => array(
'javelin-install',
'javelin-dom',
'javelin-json',
'javelin-workflow',
'javelin-util',
),
'246dc085' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
'javelin-workflow',
'javelin-quicksand',
'phabricator-phtize',
'phabricator-drag-and-drop-file-upload',
'phabricator-draggable-list',
),
'2926fff2' => array(
'javelin-behavior',
'javelin-dom',
),
'29274e2b' => array(
'javelin-install',
'javelin-util',
),
'2b8de964' => array(
'javelin-install',
'javelin-util',
),
'2bfa2836' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
),
'2c426492' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
'phabricator-keyboard-shortcut',
),
'2caa8fb8' => array(
'javelin-install',
'javelin-event',
),
'2ee659ce' => array(
'javelin-install',
),
'327a00d1' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
'javelin-workflow',
),
'331b1611' => array(
'javelin-install',
),
'340c8eff' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
'phabricator-phtize',
'phabricator-textareautils',
'javelin-workflow',
'javelin-vector',
'phuix-autocomplete',
),
'3ab51e2c' => array(
'javelin-behavior',
'javelin-behavior-device',
'javelin-stratcom',
'javelin-vector',
'javelin-dom',
'javelin-magical-init',
),
'3cb0b2fc' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
'javelin-workflow',
'javelin-util',
'javelin-uri',
),
'3e3b0b76' => array(
'phui-inline-comment-view-css',
),
'3f5d6dbf' => array(
'javelin-behavior',
'javelin-dom',
'phortune-credit-card-form',
),
'40a6a403' => array(
'javelin-install',
'javelin-dom',
'javelin-reactor-dom',
),
42126667 => array(
'javelin-behavior',
'javelin-dom',
'javelin-request',
),
'42fcb747' => array(
'javelin-behavior',
'javelin-behavior-device',
'javelin-stratcom',
'phabricator-tooltip',
),
'44959b73' => array(
'javelin-util',
'javelin-uri',
'javelin-install',
),
'453c5375' => array(
'javelin-behavior',
'javelin-dom',
),
'469c0d9e' => array(
'javelin-behavior',
'javelin-dom',
'javelin-workflow',
),
47830651 => array(
'javelin-behavior',
'javelin-dom',
'javelin-view-renderer',
'javelin-install',
),
'47c794d8' => array(
'javelin-install',
'javelin-dom',
'javelin-reactor-dom',
),
48086888 => array(
'javelin-behavior',
'javelin-dom',
'javelin-workflow',
),
'49b73b36' => array(
'javelin-behavior',
'javelin-dom',
'javelin-request',
'javelin-util',
),
'4b700e9e' => array(
'javelin-behavior',
'javelin-dom',
'javelin-util',
'phabricator-shaped-request',
),
'4e3e79a6' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
),
'4f6a4b4e' => array(
'javelin-behavior',
'javelin-dom',
'phabricator-drag-and-drop-file-upload',
'phabricator-textareautils',
),
'4fbbc3e9' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
'javelin-util',
'javelin-vector',
'differential-inline-comment-editor',
),
'4fdb476d' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
),
'503e17fd' => array(
'javelin-install',
'javelin-typeahead-source',
'javelin-util',
),
'519705ea' => array(
'javelin-install',
'javelin-dom',
'javelin-reactor-dom',
),
52291776 => array(
'javelin-install',
'javelin-dom',
'javelin-util',
'javelin-stratcom',
'javelin-workflow',
'phabricator-draggable-list',
'javelin-workboard-column',
),
'5359e785' => array(
'javelin-install',
'javelin-util',
'javelin-websocket',
'javelin-leader',
'javelin-json',
),
54733475 => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
'phuix-dropdown-menu',
),
'54b612ba' => array(
'javelin-color',
'javelin-install',
'javelin-util',
),
'54f314a0' => array(
'javelin-install',
'javelin-util',
'javelin-request',
'javelin-typeahead-source',
),
'558829c2' => array(
'javelin-stratcom',
'javelin-behavior',
'javelin-vector',
'javelin-dom',
),
'55baf5ed' => array(
'javelin-install',
'javelin-dom',
'javelin-util',
'javelin-vector',
'javelin-stratcom',
'javelin-workflow',
'phabricator-drag-and-drop-file-upload',
'javelin-workboard-board',
),
'56a1ca03' => array(
'javelin-behavior',
'javelin-behavior-device',
'javelin-stratcom',
'javelin-dom',
'javelin-magical-init',
'javelin-vector',
'javelin-request',
'javelin-util',
),
'5813016a' => array(
'javelin-install',
'javelin-dom',
'javelin-vector',
),
'59a7976a' => array(
'javelin-install',
'javelin-dom',
'javelin-fx',
),
'59b251eb' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-vector',
'javelin-dom',
),
'5a0b1a64' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
),
'5a13c79f' => array(
'javelin-install',
'javelin-dom',
'javelin-stratcom',
'javelin-util',
'javelin-vector',
'javelin-magical-init',
),
'5b2e3e2b' => array(
'javelin-stratcom',
'javelin-request',
'javelin-dom',
'javelin-vector',
'javelin-install',
'javelin-util',
'javelin-mask',
'javelin-uri',
'javelin-routable',
),
'5c54cbf3' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
),
'5d7c9f33' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
),
'5e9f347c' => array(
'javelin-behavior',
'multirow-row-manager',
'javelin-dom',
'javelin-util',
'phabricator-prefab',
'javelin-json',
),
60479091 => array(
'phabricator-busy',
'javelin-behavior',
),
'60821bc7' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
),
'61cbc29a' => array(
'javelin-magical-init',
'javelin-util',
),
'62dfea03' => array(
'javelin-install',
'javelin-util',
),
'6323f942' => array(
'javelin-install',
'javelin-util',
'javelin-dom',
'javelin-vector',
),
'635de1ec' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-workflow',
'javelin-dom',
),
'64a5550f' => array(
'javelin-dom',
'javelin-util',
'javelin-stratcom',
'javelin-install',
'javelin-request',
'javelin-workflow',
),
'680ea2c8' => array(
'javelin-install',
'javelin-dom',
'phabricator-notification',
),
'6882e80a' => array(
'javelin-dom',
),
'69adf288' => array(
'javelin-install',
),
'6ad39b6f' => array(
'javelin-install',
'javelin-event',
'javelin-util',
'javelin-magical-init',
),
'6b8ef10b' => array(
'javelin-install',
),
'6c0e62fa' => array(
'javelin-install',
'javelin-typeahead-source',
),
'6c2b09a2' => array(
'javelin-install',
'javelin-util',
),
'6d3e1947' => array(
'javelin-behavior',
'javelin-diffusion-locate-file-source',
'javelin-dom',
'javelin-typeahead',
'javelin-uri',
),
'70baed2f' => array(
'javelin-install',
'javelin-dom',
'javelin-vector',
'javelin-util',
),
71237763 => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
'javelin-workflow',
'phabricator-draggable-list',
),
'7319e029' => array(
'javelin-behavior',
'javelin-dom',
),
'73d09eef' => array(
'javelin-behavior',
'javelin-vector',
'javelin-dom',
),
'746ca158' => array(
'multirow-row-manager',
'javelin-install',
'javelin-util',
'javelin-dom',
'javelin-stratcom',
'javelin-json',
'phabricator-prefab',
),
'76b9fc3e' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-workflow',
'javelin-dom',
'phabricator-draggable-list',
),
'76f4ebed' => array(
'javelin-install',
'javelin-reactor',
'javelin-util',
),
'782ab6e7' => array(
'javelin-behavior',
'javelin-dom',
'javelin-util',
'phabricator-prefab',
'multirow-row-manager',
'javelin-json',
),
'7927a7d3' => array(
'javelin-behavior',
'javelin-quicksand',
),
'7a68dda3' => array(
'owners-path-editor',
'javelin-behavior',
),
'7b98d7c5' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
'javelin-util',
),
'7cbe244b' => array(
'javelin-install',
'javelin-util',
'javelin-request',
'javelin-router',
),
'7e41274a' => array(
'javelin-install',
),
'7ebaeed3' => array(
'herald-rule-editor',
'javelin-behavior',
),
'7ee2b591' => array(
'javelin-behavior',
'javelin-history',
),
'805b806a' => array(
'javelin-magical-init',
'javelin-install',
'javelin-util',
'javelin-vector',
'javelin-stratcom',
),
'81f182b5' => array(
'javelin-install',
'javelin-util',
'javelin-request',
'javelin-dom',
'javelin-uri',
'phabricator-file-upload',
),
'834a1173' => array(
'javelin-behavior',
'javelin-scrollbar',
),
'8499b6ab' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
),
'85ee8ce6' => array(
'aphront-dialog-view-css',
),
'8694b1df' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
'phabricator-tooltip',
'changeset-view-manager',
),
'88236f00' => array(
'javelin-behavior',
'phabricator-keyboard-shortcut',
'javelin-stratcom',
),
'886fd850' => array(
'javelin-install',
'javelin-reactor-dom',
'javelin-view-html',
'javelin-view-interpreter',
'javelin-view-renderer',
),
'887ad43f' => array(
'javelin-behavior',
'javelin-request',
'javelin-stratcom',
'javelin-dom',
),
'8a41885b' => array(
'javelin-install',
'javelin-dom',
),
'8ae55229' => array(
'javelin-behavior',
'javelin-util',
'javelin-dom',
'javelin-stratcom',
'javelin-vector',
),
'8bdb2835' => array(
'phui-fontkit-css',
),
'8ce821c5' => array(
'phabricator-notification',
'javelin-stratcom',
'javelin-behavior',
),
'8cf6d262' => array(
'javelin-install',
'javelin-dom',
'javelin-util',
),
'8d3bc1b2' => array(
'javelin-dom',
'javelin-util',
'javelin-stratcom',
'javelin-install',
),
'901935ef' => array(
'javelin-behavior',
'javelin-dom',
'javelin-request',
),
'9196fb06' => array(
'javelin-install',
'javelin-dom',
'phuix-icon-view',
'phabricator-prefab',
),
92197373 => array(
'phui-workcard-view-css',
),
'93d0c9e3' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-workflow',
'javelin-dom',
),
'9414ff18' => array(
'javelin-behavior',
'javelin-resource',
'javelin-stratcom',
'javelin-workflow',
'javelin-util',
),
'949c0fe5' => array(
'javelin-install',
),
'94b750d2' => array(
'javelin-install',
'javelin-stratcom',
'javelin-util',
'javelin-behavior',
'javelin-json',
'javelin-dom',
'javelin-resource',
'javelin-routable',
),
'988040b4' => array(
'javelin-install',
'javelin-dom',
'javelin-reactor-dom',
),
'9a6b9324' => array(
'javelin-behavior',
'javelin-dom',
'javelin-util',
'javelin-stratcom',
'javelin-workflow',
'phuix-dropdown-menu',
'phuix-action-list-view',
'phuix-action-view',
'phabricator-phtize',
'changeset-view-manager',
),
'9f36c42d' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
'javelin-vector',
),
'a0b57eb8' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
'javelin-workflow',
'javelin-util',
'phabricator-keyboard-shortcut',
),
'a155550f' => array(
'javelin-install',
'javelin-dom',
'javelin-reactor-dom',
),
'a2828756' => array(
'javelin-dom',
'javelin-util',
'javelin-stratcom',
'javelin-install',
'javelin-workflow',
'javelin-router',
'javelin-behavior-device',
'javelin-vector',
),
'a464fe03' => array(
'javelin-behavior',
'javelin-uri',
'phabricator-notification',
),
'a7763e11' => array(
'javelin-install',
'javelin-dom',
),
'a80d0378' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
),
'a8458711' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
'javelin-workflow',
'javelin-util',
'phabricator-notification',
'javelin-behavior-device',
'phuix-dropdown-menu',
'phuix-action-list-view',
'phuix-action-view',
'conpherence-thread-manager',
),
'a8d8459d' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
),
'a8da01f0' => array(
'javelin-behavior',
'javelin-uri',
'phabricator-keyboard-shortcut',
),
'a9f88de2' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
'javelin-workflow',
'javelin-fx',
'javelin-util',
),
'aa1733d0' => array(
'multirow-row-manager',
'javelin-install',
'path-typeahead',
'javelin-dom',
'javelin-util',
'phabricator-prefab',
),
'ab2f381b' => array(
'javelin-request',
'javelin-behavior',
'javelin-dom',
'javelin-router',
'javelin-util',
'phabricator-busy',
),
'b064af76' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
'javelin-request',
'javelin-util',
'phabricator-shaped-request',
),
'b1f0ccee' => array(
'javelin-install',
'javelin-dom',
'javelin-reactor-dom',
),
'b23b49e6' => array(
'javelin-behavior',
'javelin-dom',
'javelin-util',
'javelin-request',
'phabricator-shaped-request',
),
'b2b4fbaf' => array(
'javelin-behavior',
'javelin-dom',
'javelin-uri',
'javelin-request',
),
'b3a4b884' => array(
'javelin-behavior',
'phabricator-prefab',
),
'b3e7d692' => array(
'javelin-install',
),
'b42eddc7' => array(
'javelin-install',
'javelin-dom',
'javelin-typeahead-preloaded-source',
'javelin-util',
),
'b59e1e96' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-workflow',
'javelin-dom',
'phabricator-draggable-list',
),
'b5b36110' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
'javelin-vector',
'javelin-install',
),
'b5c256b8' => array(
'javelin-install',
'javelin-dom',
),
'b5d57730' => array(
'javelin-install',
'javelin-stratcom',
'javelin-dom',
'javelin-util',
),
'b6993408' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
'javelin-json',
'phabricator-draggable-list',
),
'bae58312' => array(
'javelin-install',
'javelin-workboard-card',
),
'bcaccd64' => array(
'javelin-behavior',
'javelin-behavior-device',
'javelin-stratcom',
'javelin-vector',
'phui-hovercard',
),
'bd4c8dca' => array(
'javelin-install',
'javelin-util',
'javelin-dom',
'javelin-vector',
'javelin-stratcom',
),
'bdaf4d04' => array(
'javelin-behavior',
'javelin-dom',
'javelin-util',
'javelin-request',
),
'bff6884b' => array(
'javelin-install',
'javelin-dom',
),
'c1700f6f' => array(
'javelin-install',
'javelin-util',
'javelin-stratcom',
'javelin-dom',
'javelin-vector',
),
'c587b80f' => array(
'javelin-install',
),
'c72aa091' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
'javelin-behavior-device',
'javelin-scrollbar',
'javelin-quicksand',
'phabricator-keyboard-shortcut',
'conpherence-thread-manager',
),
'c7ccd872' => array(
'phui-fontkit-css',
),
'c8e57404' => array(
'javelin-behavior',
'javelin-dom',
'javelin-uri',
'javelin-mask',
'phabricator-drag-and-drop-file-upload',
),
'c90a04fc' => array(
'javelin-dom',
'javelin-dynval',
'javelin-reactor',
'javelin-reactornode',
'javelin-install',
'javelin-util',
),
'c989ade3' => array(
'javelin-install',
'javelin-util',
'javelin-stratcom',
),
'ca3f91eb' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
'phabricator-phtize',
),
'ccf1cbf8' => array(
'javelin-install',
'javelin-dom',
'javelin-stratcom',
'javelin-util',
'phabricator-notification-css',
),
'cf86d16a' => array(
'javelin-behavior',
'javelin-dom',
'javelin-workflow',
'phabricator-drag-and-drop-file-upload',
),
'd00a795a' => array(
'phui-theme-css',
),
'd0c516d5' => array(
'javelin-behavior',
'javelin-dom',
'javelin-util',
'phuix-dropdown-menu',
'phuix-action-list-view',
'phuix-action-view',
'javelin-workflow',
'phuix-icon-view',
),
'd19198c8' => array(
'javelin-install',
'javelin-dom',
'javelin-util',
'javelin-dynval',
'javelin-reactor-dom',
),
'd254d646' => array(
'javelin-util',
),
'd4505101' => array(
'javelin-stratcom',
'javelin-install',
'javelin-uri',
'javelin-util',
),
'd4a14807' => array(
'javelin-install',
'javelin-dom',
'javelin-view',
),
'd4eecc63' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
),
'd75709e6' => array(
'javelin-behavior',
'javelin-workflow',
'javelin-json',
'javelin-dom',
'phabricator-keyboard-shortcut',
),
'd7a74243' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-workflow',
'javelin-dom',
'phabricator-draggable-list',
),
'd835b03a' => array(
'javelin-behavior',
'javelin-dom',
'javelin-util',
'phabricator-shaped-request',
),
'dbbf48b6' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
'phabricator-busy',
),
'de2e896f' => array(
'javelin-behavior',
'javelin-dom',
'javelin-typeahead',
'javelin-typeahead-ondemand-source',
'javelin-dom',
),
'df5e11d2' => array(
'javelin-install',
),
'e10f8e18' => array(
'javelin-behavior',
'javelin-dom',
'phabricator-prefab',
),
'e1d25dfb' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-workflow',
'javelin-dom',
'phabricator-draggable-list',
),
'e1ff79b1' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
),
'e292eaf4' => array(
'javelin-install',
),
'e2e0a072' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-workflow',
'javelin-dom',
'phabricator-draggable-list',
),
'e379b58e' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-vector',
'javelin-dom',
'javelin-uri',
),
'e4232876' => array(
'javelin-behavior',
'javelin-dom',
'javelin-vector',
'phui-chart-css',
),
'e4cc26b3' => array(
'javelin-behavior',
'javelin-dom',
),
'e5339c43' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
'javelin-uri',
),
'e5822781' => array(
'javelin-behavior',
'javelin-dom',
'javelin-json',
'javelin-workflow',
'javelin-magical-init',
),
'e67df814' => array(
'javelin-install',
'javelin-util',
'javelin-dom',
'javelin-typeahead',
'javelin-tokenizer',
'javelin-typeahead-preloaded-source',
'javelin-typeahead-ondemand-source',
'javelin-dom',
'javelin-stratcom',
'javelin-util',
),
'e6e25838' => array(
'javelin-install',
),
'e9581f08' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-workflow',
'javelin-dom',
'phabricator-draggable-list',
),
'ea681761' => array(
'javelin-behavior',
'javelin-aphlict',
'phabricator-phtize',
'javelin-dom',
),
'edd1ba66' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
'javelin-uri',
'phabricator-notification',
),
'edf8a145' => array(
'javelin-behavior',
'javelin-uri',
),
'efe49472' => array(
'javelin-install',
'javelin-util',
),
'f01586dc' => array(
'javelin-behavior',
'javelin-dom',
'javelin-util',
'javelin-workflow',
'javelin-json',
),
'f411b6ae' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-util',
'javelin-dom',
'javelin-request',
'phabricator-keyboard-shortcut',
),
'f6555212' => array(
'javelin-install',
'javelin-reactornode',
'javelin-util',
'javelin-reactor',
),
'f7fc67ec' => array(
'javelin-install',
'javelin-typeahead',
'javelin-dom',
'javelin-request',
'javelin-typeahead-ondemand-source',
'javelin-util',
),
'f80d6bf0' => array(
'javelin-behavior',
'javelin-util',
'javelin-dom',
'javelin-stratcom',
'javelin-vector',
'javelin-typeahead-static-source',
),
'f829edb3' => array(
'javelin-view',
'javelin-install',
'javelin-dom',
),
'f8ba29d7' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
'javelin-mask',
'javelin-util',
'phabricator-busy',
),
'fa0f4fc2' => array(
'javelin-behavior',
'javelin-dom',
'javelin-vector',
'javelin-magical-init',
),
'fb20ac8d' => array(
'javelin-behavior',
'javelin-aphlict',
'javelin-stratcom',
'javelin-request',
'javelin-uri',
'javelin-dom',
'javelin-json',
'javelin-router',
'javelin-util',
'javelin-leader',
'javelin-sound',
'phabricator-notification',
),
'fbe497e7' => array(
'javelin-behavior',
'javelin-util',
'javelin-stratcom',
'javelin-dom',
'javelin-vector',
'javelin-magical-init',
'javelin-request',
'javelin-history',
'javelin-workflow',
'javelin-mask',
'javelin-behavior-device',
'phabricator-keyboard-shortcut',
),
'fc91ab6c' => array(
'javelin-behavior',
'javelin-dom',
'phortune-credit-card-form',
),
'fe287620' => array(
'javelin-install',
'javelin-dom',
'javelin-view-visitor',
'javelin-util',
),
),
'packages' => array(
'core.pkg.css' => array(
'phabricator-core-css',
'phabricator-zindex-css',
'phui-button-css',
'phabricator-standard-page-view',
'aphront-dialog-view-css',
'phui-form-view-css',
'aphront-panel-view-css',
'aphront-table-view-css',
'aphront-tokenizer-control-css',
'aphront-typeahead-control-css',
'aphront-list-filter-view-css',
'phabricator-remarkup-css',
'syntax-highlighting-css',
'phui-pager-css',
'aphront-tooltip-css',
'phabricator-flag-css',
'phui-info-view-css',
'sprite-menu-css',
'phabricator-main-menu-view',
'phabricator-notification-css',
'phabricator-notification-menu-css',
'lightbox-attachment-css',
'phui-header-view-css',
'phabricator-filetree-view-css',
'phabricator-nav-view-css',
'phabricator-side-menu-view-css',
'phui-crumbs-view-css',
'phui-object-item-list-view-css',
'global-drag-and-drop-css',
'phui-spacing-css',
'phui-form-css',
'phui-icon-view-css',
'phui-profile-menu-css',
'phabricator-application-launch-view-css',
'phabricator-action-list-view-css',
'phui-property-list-view-css',
'phui-tag-view-css',
'phui-list-view-css',
'font-fontawesome',
'phui-font-icon-base-css',
'phui-box-css',
'phui-object-box-css',
'phui-timeline-view-css',
'sprite-tokens-css',
'tokens-css',
'phui-status-list-view-css',
'phui-feed-story-css',
'phabricator-feed-css',
'phabricator-dashboard-css',
'aphront-multi-column-view-css',
'conpherence-durable-column-view',
),
'core.pkg.js' => array(
'javelin-util',
'javelin-install',
'javelin-event',
'javelin-stratcom',
'javelin-behavior',
'javelin-resource',
'javelin-request',
'javelin-vector',
'javelin-dom',
'javelin-json',
'javelin-uri',
'javelin-workflow',
'javelin-mask',
'javelin-typeahead',
'javelin-typeahead-normalizer',
'javelin-typeahead-source',
'javelin-typeahead-preloaded-source',
'javelin-typeahead-ondemand-source',
'javelin-tokenizer',
'javelin-history',
'javelin-router',
'javelin-routable',
'javelin-behavior-aphront-basic-tokenizer',
'javelin-behavior-workflow',
'javelin-behavior-aphront-form-disable-on-submit',
'phabricator-keyboard-shortcut-manager',
'phabricator-keyboard-shortcut',
'javelin-behavior-phabricator-keyboard-shortcuts',
'javelin-behavior-refresh-csrf',
'javelin-behavior-phabricator-watch-anchor',
'javelin-behavior-phabricator-autofocus',
'phuix-dropdown-menu',
'phuix-action-list-view',
'phuix-action-view',
'phabricator-phtize',
'javelin-behavior-phabricator-oncopy',
'phabricator-tooltip',
'javelin-behavior-phabricator-tooltips',
'phabricator-prefab',
'javelin-behavior-device',
'javelin-behavior-toggle-class',
'javelin-behavior-lightbox-attachments',
'phabricator-busy',
'javelin-aphlict',
'phabricator-notification',
'javelin-behavior-aphlict-listen',
'javelin-behavior-phabricator-search-typeahead',
'javelin-behavior-aphlict-dropdown',
'javelin-behavior-history-install',
'javelin-behavior-phabricator-gesture',
'javelin-behavior-phabricator-active-nav',
'javelin-behavior-phabricator-nav',
'javelin-behavior-phabricator-remarkup-assist',
'phabricator-textareautils',
'phabricator-file-upload',
'javelin-behavior-global-drag-and-drop',
'javelin-behavior-phabricator-reveal-content',
'phui-hovercard',
'javelin-behavior-phui-hovercards',
'javelin-color',
'javelin-fx',
'phabricator-draggable-list',
'javelin-behavior-phabricator-transaction-list',
'javelin-behavior-phabricator-show-older-transactions',
'javelin-behavior-phui-dropdown-menu',
'javelin-behavior-doorkeeper-tag',
'phabricator-title',
'javelin-leader',
'javelin-websocket',
'javelin-behavior-dashboard-async-panel',
'javelin-behavior-dashboard-tab-panel',
'javelin-quicksand',
'javelin-behavior-quicksand-blacklist',
'javelin-behavior-high-security-warning',
'javelin-scrollbar',
'javelin-behavior-scrollbar',
'javelin-behavior-durable-column',
'conpherence-thread-manager',
),
'darkconsole.pkg.js' => array(
'javelin-behavior-dark-console',
'javelin-behavior-error-log',
),
'differential.pkg.css' => array(
'differential-core-view-css',
'differential-changeset-view-css',
'differential-revision-history-css',
'differential-revision-list-css',
'differential-table-of-contents-css',
'differential-revision-comment-css',
'differential-revision-add-comment-css',
'phabricator-object-selector-css',
'phabricator-content-source-view-css',
'inline-comment-summary-css',
'phui-inline-comment-view-css',
),
'differential.pkg.js' => array(
'phabricator-drag-and-drop-file-upload',
'phabricator-shaped-request',
'javelin-behavior-differential-feedback-preview',
'javelin-behavior-differential-edit-inline-comments',
'javelin-behavior-differential-populate',
'javelin-behavior-differential-diff-radios',
'javelin-behavior-differential-comment-jump',
'javelin-behavior-differential-add-reviewers-and-ccs',
'javelin-behavior-differential-keyboard-navigation',
'javelin-behavior-aphront-drag-and-drop-textarea',
'javelin-behavior-phabricator-object-selector',
'javelin-behavior-repository-crossreference',
'javelin-behavior-load-blame',
'differential-inline-comment-editor',
'javelin-behavior-differential-dropdown-menus',
'javelin-behavior-differential-toggle-files',
'javelin-behavior-differential-user-select',
'javelin-behavior-aphront-more',
'changeset-view-manager',
),
'diffusion.pkg.css' => array(
'diffusion-icons-css',
),
'diffusion.pkg.js' => array(
'javelin-behavior-diffusion-pull-lastmodified',
'javelin-behavior-diffusion-commit-graph',
'javelin-behavior-audit-preview',
),
'maniphest.pkg.css' => array(
'maniphest-task-summary-css',
),
'maniphest.pkg.js' => array(
'javelin-behavior-maniphest-batch-selector',
'javelin-behavior-maniphest-subpriority-editor',
'javelin-behavior-maniphest-list-editor',
),
),
);
diff --git a/src/applications/audit/constants/PhabricatorAuditCommitStatusConstants.php b/src/applications/audit/constants/PhabricatorAuditCommitStatusConstants.php
index c96f22e338..ca959d4aef 100644
--- a/src/applications/audit/constants/PhabricatorAuditCommitStatusConstants.php
+++ b/src/applications/audit/constants/PhabricatorAuditCommitStatusConstants.php
@@ -1,72 +1,74 @@
<?php
final class PhabricatorAuditCommitStatusConstants extends Phobject {
const NONE = 0;
const NEEDS_AUDIT = 1;
const CONCERN_RAISED = 2;
const PARTIALLY_AUDITED = 3;
const FULLY_AUDITED = 4;
public static function getStatusNameMap() {
$map = array(
self::NONE => pht('None'),
self::NEEDS_AUDIT => pht('Audit Required'),
self::CONCERN_RAISED => pht('Concern Raised'),
self::PARTIALLY_AUDITED => pht('Partially Audited'),
self::FULLY_AUDITED => pht('Audited'),
);
return $map;
}
public static function getStatusName($code) {
return idx(self::getStatusNameMap(), $code, pht('Unknown'));
}
public static function getOpenStatusConstants() {
return array(
self::CONCERN_RAISED,
self::NEEDS_AUDIT,
);
}
public static function getStatusColor($code) {
switch ($code) {
case self::CONCERN_RAISED:
$color = 'red';
break;
case self::NEEDS_AUDIT:
- case self::PARTIALLY_AUDITED:
$color = 'orange';
break;
+ case self::PARTIALLY_AUDITED:
+ $color = 'yellow';
+ break;
case self::FULLY_AUDITED:
$color = 'green';
break;
default:
$color = null;
break;
}
return $color;
}
public static function getStatusIcon($code) {
switch ($code) {
case self::CONCERN_RAISED:
- $icon = 'fa-exclamation-triangle';
+ $icon = 'fa-exclamation-circle';
break;
case self::NEEDS_AUDIT:
case self::PARTIALLY_AUDITED:
- $icon = 'fa-exclamation-triangle';
+ $icon = 'fa-exclamation-circle';
break;
case self::FULLY_AUDITED:
$icon = 'fa-check';
break;
default:
$icon = null;
break;
}
return $icon;
}
}
diff --git a/src/applications/differential/constants/DifferentialChangeType.php b/src/applications/differential/constants/DifferentialChangeType.php
index 2bf4b217a7..7ee3c89b65 100644
--- a/src/applications/differential/constants/DifferentialChangeType.php
+++ b/src/applications/differential/constants/DifferentialChangeType.php
@@ -1,142 +1,157 @@
<?php
final class DifferentialChangeType extends Phobject {
const TYPE_ADD = 1;
const TYPE_CHANGE = 2;
const TYPE_DELETE = 3;
const TYPE_MOVE_AWAY = 4;
const TYPE_COPY_AWAY = 5;
const TYPE_MOVE_HERE = 6;
const TYPE_COPY_HERE = 7;
const TYPE_MULTICOPY = 8;
const TYPE_MESSAGE = 9;
const TYPE_CHILD = 10;
const FILE_TEXT = 1;
const FILE_IMAGE = 2;
const FILE_BINARY = 3;
const FILE_DIRECTORY = 4;
const FILE_SYMLINK = 5;
const FILE_DELETED = 6;
const FILE_NORMAL = 7;
const FILE_SUBMODULE = 8;
public static function getSummaryCharacterForChangeType($type) {
static $types = array(
self::TYPE_ADD => 'A',
self::TYPE_CHANGE => 'M',
self::TYPE_DELETE => 'D',
self::TYPE_MOVE_AWAY => 'V',
self::TYPE_COPY_AWAY => 'P',
self::TYPE_MOVE_HERE => 'V',
self::TYPE_COPY_HERE => 'P',
self::TYPE_MULTICOPY => 'P',
self::TYPE_MESSAGE => 'Q',
self::TYPE_CHILD => '@',
);
return idx($types, coalesce($type, '?'), '~');
}
public static function getSummaryColorForChangeType($type) {
static $types = array(
self::TYPE_ADD => 'green',
self::TYPE_CHANGE => 'black',
self::TYPE_DELETE => 'red',
self::TYPE_MOVE_AWAY => 'orange',
self::TYPE_COPY_AWAY => 'black',
self::TYPE_MOVE_HERE => 'green',
self::TYPE_COPY_HERE => 'green',
self::TYPE_MULTICOPY => 'orange',
self::TYPE_MESSAGE => 'black',
self::TYPE_CHILD => 'black',
);
return idx($types, coalesce($type, '?'), 'black');
}
public static function getShortNameForFileType($type) {
static $names = array(
self::FILE_TEXT => null,
self::FILE_DIRECTORY => 'dir',
self::FILE_IMAGE => 'img',
self::FILE_BINARY => 'bin',
self::FILE_SYMLINK => 'sym',
self::FILE_SUBMODULE => 'sub',
);
return idx($names, coalesce($type, '?'), '???');
}
public static function getIconForFileType($type) {
static $icons = array(
self::FILE_TEXT => 'fa-file-text-o',
self::FILE_IMAGE => 'fa-file-image-o',
self::FILE_BINARY => 'fa-file',
self::FILE_DIRECTORY => 'fa-folder-open',
self::FILE_SYMLINK => 'fa-link',
self::FILE_DELETED => 'fa-file',
self::FILE_NORMAL => 'fa-file-text-o',
self::FILE_SUBMODULE => 'fa-folder-open-o',
);
return idx($icons, $type, 'fa-file');
}
+ public static function getIconColorForFileType($type) {
+ static $icons = array(
+ self::FILE_TEXT => 'black',
+ self::FILE_IMAGE => 'black',
+ self::FILE_BINARY => 'green',
+ self::FILE_DIRECTORY => 'blue',
+ self::FILE_SYMLINK => 'blue',
+ self::FILE_DELETED => 'red',
+ self::FILE_NORMAL => 'black',
+ self::FILE_SUBMODULE => 'blue',
+ );
+
+ return idx($icons, $type, 'black');
+ }
+
public static function isOldLocationChangeType($type) {
static $types = array(
self::TYPE_MOVE_AWAY => true,
self::TYPE_COPY_AWAY => true,
self::TYPE_MULTICOPY => true,
);
return isset($types[$type]);
}
public static function isNewLocationChangeType($type) {
static $types = array(
self::TYPE_MOVE_HERE => true,
self::TYPE_COPY_HERE => true,
);
return isset($types[$type]);
}
public static function isDeleteChangeType($type) {
static $types = array(
self::TYPE_DELETE => true,
self::TYPE_MOVE_AWAY => true,
self::TYPE_MULTICOPY => true,
);
return isset($types[$type]);
}
public static function isCreateChangeType($type) {
static $types = array(
self::TYPE_ADD => true,
self::TYPE_COPY_HERE => true,
self::TYPE_MOVE_HERE => true,
);
return isset($types[$type]);
}
public static function isModifyChangeType($type) {
static $types = array(
self::TYPE_CHANGE => true,
);
return isset($types[$type]);
}
public static function getFullNameForChangeType($type) {
$types = array(
self::TYPE_ADD => pht('Added'),
self::TYPE_CHANGE => pht('Modified'),
self::TYPE_DELETE => pht('Deleted'),
self::TYPE_MOVE_AWAY => pht('Moved Away'),
self::TYPE_COPY_AWAY => pht('Copied Away'),
self::TYPE_MOVE_HERE => pht('Moved Here'),
self::TYPE_COPY_HERE => pht('Copied Here'),
self::TYPE_MULTICOPY => pht('Deleted After Multiple Copy'),
self::TYPE_MESSAGE => pht('Commit Message'),
self::TYPE_CHILD => pht('Contents Modified'),
);
return idx($types, coalesce($type, '?'), pht('Unknown'));
}
}
diff --git a/src/applications/differential/view/DifferentialChangesetListView.php b/src/applications/differential/view/DifferentialChangesetListView.php
index 4f173bda53..f0c611c609 100644
--- a/src/applications/differential/view/DifferentialChangesetListView.php
+++ b/src/applications/differential/view/DifferentialChangesetListView.php
@@ -1,349 +1,359 @@
<?php
final class DifferentialChangesetListView extends AphrontView {
private $changesets = array();
private $visibleChangesets = array();
private $references = array();
private $inlineURI;
private $renderURI = '/differential/changeset/';
private $whitespace;
private $background;
+ private $header;
private $standaloneURI;
private $leftRawFileURI;
private $rightRawFileURI;
private $symbolIndexes = array();
private $repository;
private $branch;
private $diff;
private $vsMap = array();
private $title;
private $parser;
public function setParser(DifferentialChangesetParser $parser) {
$this->parser = $parser;
return $this;
}
public function getParser() {
return $this->parser;
}
public function setTitle($title) {
$this->title = $title;
return $this;
}
private function getTitle() {
return $this->title;
}
public function setBranch($branch) {
$this->branch = $branch;
return $this;
}
private function getBranch() {
return $this->branch;
}
public function setChangesets($changesets) {
$this->changesets = $changesets;
return $this;
}
public function setVisibleChangesets($visible_changesets) {
$this->visibleChangesets = $visible_changesets;
return $this;
}
public function setInlineCommentControllerURI($uri) {
$this->inlineURI = $uri;
return $this;
}
public function setRepository(PhabricatorRepository $repository) {
$this->repository = $repository;
return $this;
}
public function setDiff(DifferentialDiff $diff) {
$this->diff = $diff;
return $this;
}
public function setRenderingReferences(array $references) {
$this->references = $references;
return $this;
}
public function setSymbolIndexes(array $indexes) {
$this->symbolIndexes = $indexes;
return $this;
}
public function setRenderURI($render_uri) {
$this->renderURI = $render_uri;
return $this;
}
public function setWhitespace($whitespace) {
$this->whitespace = $whitespace;
return $this;
}
public function setVsMap(array $vs_map) {
$this->vsMap = $vs_map;
return $this;
}
public function getVsMap() {
return $this->vsMap;
}
public function setStandaloneURI($uri) {
$this->standaloneURI = $uri;
return $this;
}
public function setRawFileURIs($l, $r) {
$this->leftRawFileURI = $l;
$this->rightRawFileURI = $r;
return $this;
}
public function setBackground($background) {
$this->background = $background;
return $this;
}
+ public function setHeader($header) {
+ $this->header = $header;
+ return $this;
+ }
+
public function render() {
$viewer = $this->getViewer();
$this->requireResource('differential-changeset-view-css');
$changesets = $this->changesets;
Javelin::initBehavior('differential-toggle-files', array(
'pht' => array(
'undo' => pht('Undo'),
'collapsed' => pht('This file content has been collapsed.'),
),
));
Javelin::initBehavior(
'differential-dropdown-menus',
array(
'pht' => array(
'Open in Editor' => pht('Open in Editor'),
'Show All Context' => pht('Show All Context'),
'All Context Shown' => pht('All Context Shown'),
"Can't Toggle Unloaded File" => pht("Can't Toggle Unloaded File"),
'Expand File' => pht('Expand File'),
'Collapse File' => pht('Collapse File'),
'Browse in Diffusion' => pht('Browse in Diffusion'),
'View Standalone' => pht('View Standalone'),
'Show Raw File (Left)' => pht('Show Raw File (Left)'),
'Show Raw File (Right)' => pht('Show Raw File (Right)'),
'Configure Editor' => pht('Configure Editor'),
'Load Changes' => pht('Load Changes'),
'View Side-by-Side' => pht('View Side-by-Side'),
'View Unified' => pht('View Unified'),
'Change Text Encoding...' => pht('Change Text Encoding...'),
'Highlight As...' => pht('Highlight As...'),
),
));
$renderer = DifferentialChangesetParser::getDefaultRendererForViewer(
$viewer);
$output = array();
$ids = array();
foreach ($changesets as $key => $changeset) {
$file = $changeset->getFilename();
$class = 'differential-changeset';
if (!$this->inlineURI) {
$class .= ' differential-changeset-noneditable';
}
$ref = $this->references[$key];
$detail = id(new DifferentialChangesetDetailView())
->setUser($viewer);
$uniq_id = 'diff-'.$changeset->getAnchorName();
$detail->setID($uniq_id);
$view_options = $this->renderViewOptionsDropdown(
$detail,
$ref,
$changeset);
$detail->setChangeset($changeset);
$detail->addButton($view_options);
$detail->setSymbolIndex(idx($this->symbolIndexes, $key));
$detail->setVsChangesetID(idx($this->vsMap, $changeset->getID()));
$detail->setEditable(true);
$detail->setRenderingRef($ref);
$detail->setRenderURI($this->renderURI);
$detail->setWhitespace($this->whitespace);
$detail->setRenderer($renderer);
if ($this->getParser()) {
$detail->appendChild($this->getParser()->renderChangeset());
$detail->setLoaded(true);
} else {
$detail->setAutoload(isset($this->visibleChangesets[$key]));
if (isset($this->visibleChangesets[$key])) {
$load = pht('Loading...');
} else {
$load = javelin_tag(
'a',
array(
'class' => 'button grey',
'href' => '#'.$uniq_id,
'sigil' => 'differential-load',
'meta' => array(
'id' => $detail->getID(),
'kill' => true,
),
'mustcapture' => true,
),
pht('Load File'));
}
$detail->appendChild(
phutil_tag(
'div',
array(
'id' => $uniq_id,
),
phutil_tag(
'div',
array('class' => 'differential-loading'),
$load)));
}
$output[] = $detail->render();
$ids[] = $detail->getID();
}
$this->requireResource('aphront-tooltip-css');
$this->initBehavior('differential-populate', array(
'changesetViewIDs' => $ids,
));
$this->initBehavior('differential-comment-jump', array());
if ($this->inlineURI) {
Javelin::initBehavior('differential-edit-inline-comments', array(
'uri' => $this->inlineURI,
'stage' => 'differential-review-stage',
'revealIcon' => hsprintf('%s', new PHUIDiffRevealIconView()),
));
}
- $header = id(new PHUIHeaderView())
- ->setHeader($this->getTitle());
+ if ($this->header) {
+ $header = $this->header;
+ } else {
+ $header = id(new PHUIHeaderView())
+ ->setHeader($this->getTitle());
+ }
$content = phutil_tag(
'div',
array(
'class' => 'differential-review-stage',
'id' => 'differential-review-stage',
),
$output);
$object_box = id(new PHUIObjectBoxView())
->setHeader($header)
- ->setCollapsed(true)
->setBackground($this->background)
+ ->setCollapsed(true)
->appendChild($content);
return $object_box;
}
private function renderViewOptionsDropdown(
DifferentialChangesetDetailView $detail,
$ref,
DifferentialChangeset $changeset) {
$viewer = $this->getViewer();
$meta = array();
$qparams = array(
'ref' => $ref,
'whitespace' => $this->whitespace,
);
if ($this->standaloneURI) {
$uri = new PhutilURI($this->standaloneURI);
$uri->setQueryParams($uri->getQueryParams() + $qparams);
$meta['standaloneURI'] = (string)$uri;
}
$repository = $this->repository;
if ($repository) {
try {
$meta['diffusionURI'] =
(string)$repository->getDiffusionBrowseURIForPath(
$viewer,
$changeset->getAbsoluteRepositoryPath($repository, $this->diff),
idx($changeset->getMetadata(), 'line:first'),
$this->getBranch());
} catch (DiffusionSetupException $e) {
// Ignore
}
}
$change = $changeset->getChangeType();
if ($this->leftRawFileURI) {
if ($change != DifferentialChangeType::TYPE_ADD) {
$uri = new PhutilURI($this->leftRawFileURI);
$uri->setQueryParams($uri->getQueryParams() + $qparams);
$meta['leftURI'] = (string)$uri;
}
}
if ($this->rightRawFileURI) {
if ($change != DifferentialChangeType::TYPE_DELETE &&
$change != DifferentialChangeType::TYPE_MULTICOPY) {
$uri = new PhutilURI($this->rightRawFileURI);
$uri->setQueryParams($uri->getQueryParams() + $qparams);
$meta['rightURI'] = (string)$uri;
}
}
if ($viewer && $repository) {
$path = ltrim(
$changeset->getAbsoluteRepositoryPath($repository, $this->diff),
'/');
$line = idx($changeset->getMetadata(), 'line:first', 1);
$editor_link = $viewer->loadEditorLink($path, $line, $repository);
if ($editor_link) {
$meta['editor'] = $editor_link;
} else {
$meta['editorConfigure'] = '/settings/panel/display/';
}
}
$meta['containerID'] = $detail->getID();
$caret = phutil_tag('span', array('class' => 'caret'), '');
return javelin_tag(
'a',
array(
'class' => 'button grey dropdown',
'meta' => $meta,
'href' => idx($meta, 'detailURI', '#'),
'target' => '_blank',
'sigil' => 'differential-view-options',
),
array(pht('View Options'), $caret));
}
}
diff --git a/src/applications/diffusion/controller/DiffusionBranchTableController.php b/src/applications/diffusion/controller/DiffusionBranchTableController.php
index 3a025e90c5..5c76469b5e 100644
--- a/src/applications/diffusion/controller/DiffusionBranchTableController.php
+++ b/src/applications/diffusion/controller/DiffusionBranchTableController.php
@@ -1,85 +1,95 @@
<?php
final class DiffusionBranchTableController extends DiffusionController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
$response = $this->loadDiffusionContext();
if ($response) {
return $response;
}
$viewer = $this->getViewer();
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$pager = id(new PHUIPagerView())
->readFromRequest($request);
$params = array(
'offset' => $pager->getOffset(),
'limit' => $pager->getPageSize() + 1,
);
$contains = $drequest->getSymbolicCommit();
if (strlen($contains)) {
$params['contains'] = $contains;
}
$branches = $this->callConduitWithDiffusionRequest(
'diffusion.branchquery',
$params);
$branches = $pager->sliceResults($branches);
$branches = DiffusionRepositoryRef::loadAllFromDictionaries($branches);
$content = null;
if (!$branches) {
$content = $this->renderStatusMessage(
pht('No Branches'),
pht('This repository has no branches.'));
} else {
$commits = id(new DiffusionCommitQuery())
->setViewer($viewer)
->withIdentifiers(mpull($branches, 'getCommitIdentifier'))
->withRepository($repository)
->execute();
- $view = id(new DiffusionBranchTableView())
+ $table = id(new DiffusionBranchTableView())
->setUser($viewer)
->setBranches($branches)
->setCommits($commits)
->setDiffusionRequest($drequest);
- $panel = id(new PHUIObjectBoxView())
- ->setHeaderText(pht('Branches'))
- ->setTable($view);
-
- $content = $panel;
+ $content = id(new PHUIObjectBoxView())
+ ->setHeaderText($repository->getName())
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
+ ->setTable($table);
}
$crumbs = $this->buildCrumbs(
array(
'branches' => true,
));
+ $crumbs->setBorder(true);
$pager_box = $this->renderTablePagerBox($pager);
+ $header = id(new PHUIHeaderView())
+ ->setHeader(pht('Branches'))
+ ->setHeaderIcon('fa-code-fork');
+
+ $view = id(new PHUITwoColumnView())
+ ->setHeader($header)
+ ->setFooter(array(
+ $content,
+ $pager_box,
+ ));
+
return $this->newPage()
->setTitle(
array(
pht('Branches'),
$repository->getDisplayName(),
))
->setCrumbs($crumbs)
->appendChild(
array(
- $content,
- $pager_box,
+ $view,
));
}
}
diff --git a/src/applications/diffusion/controller/DiffusionBrowseController.php b/src/applications/diffusion/controller/DiffusionBrowseController.php
index a2e9a3a4b3..81adacf7c9 100644
--- a/src/applications/diffusion/controller/DiffusionBrowseController.php
+++ b/src/applications/diffusion/controller/DiffusionBrowseController.php
@@ -1,1868 +1,1892 @@
<?php
final class DiffusionBrowseController extends DiffusionController {
private $lintCommit;
private $lintMessages;
private $coverage;
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
$response = $this->loadDiffusionContext();
if ($response) {
return $response;
}
$drequest = $this->getDiffusionRequest();
// Figure out if we're browsing a directory, a file, or a search result
// list.
$grep = $request->getStr('grep');
$find = $request->getStr('find');
if (strlen($grep) || strlen($find)) {
return $this->browseSearch();
}
$pager = id(new PHUIPagerView())
->readFromRequest($request);
$results = DiffusionBrowseResultSet::newFromConduit(
$this->callConduitWithDiffusionRequest(
'diffusion.browsequery',
array(
'path' => $drequest->getPath(),
'commit' => $drequest->getStableCommit(),
'offset' => $pager->getOffset(),
'limit' => $pager->getPageSize() + 1,
)));
$reason = $results->getReasonForEmptyResultSet();
$is_file = ($reason == DiffusionBrowseResultSet::REASON_IS_FILE);
if ($is_file) {
return $this->browseFile($results);
} else {
$paths = $results->getPaths();
$paths = $pager->sliceResults($paths);
$results->setPaths($paths);
return $this->browseDirectory($results, $pager);
}
}
private function browseSearch() {
- $drequest = $this->getDiffusionRequest();
-
- $actions = $this->buildActionView($drequest);
- $properties = $this->buildPropertyView($drequest, $actions);
- $object_box = id(new PHUIObjectBoxView())
- ->setHeader($this->buildHeaderView($drequest))
- ->addPropertyList($properties);
+ $drequest = $this->getDiffusionRequest();
+ $header = $this->buildHeaderView($drequest);
- $content = array();
+ $search_form = $this->renderSearchForm();
+ $search_results = $this->renderSearchResults();
- $content[] = $object_box;
- $content[] = $this->renderSearchForm($collapsed = false);
- $content[] = $this->renderSearchResults();
+ $search_form = id(new PHUIObjectBoxView())
+ ->setHeaderText(pht('Search'))
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
+ ->appendChild($search_form);
$crumbs = $this->buildCrumbs(
array(
'branch' => true,
'path' => true,
'view' => 'browse',
));
+ $crumbs->setBorder(true);
+
+ $view = id(new PHUITwoColumnView())
+ ->setHeader($header)
+ ->setFooter(array(
+ $search_form,
+ $search_results,
+ ));
return $this->newPage()
->setTitle(
array(
nonempty(basename($drequest->getPath()), '/'),
$drequest->getRepository()->getDisplayName(),
))
->setCrumbs($crumbs)
- ->appendChild($content);
+ ->appendChild($view);
}
private function browseFile() {
$viewer = $this->getViewer();
$request = $this->getRequest();
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$before = $request->getStr('before');
if ($before) {
return $this->buildBeforeResponse($before);
}
$path = $drequest->getPath();
$preferences = $viewer->loadPreferences();
$show_blame = $request->getBool(
'blame',
$preferences->getPreference(
PhabricatorUserPreferences::PREFERENCE_DIFFUSION_BLAME,
false));
$show_color = $request->getBool(
'color',
$preferences->getPreference(
PhabricatorUserPreferences::PREFERENCE_DIFFUSION_COLOR,
true));
$view = $request->getStr('view');
if ($request->isFormPost() && $view != 'raw' && $viewer->isLoggedIn()) {
$preferences->setPreference(
PhabricatorUserPreferences::PREFERENCE_DIFFUSION_BLAME,
$show_blame);
$preferences->setPreference(
PhabricatorUserPreferences::PREFERENCE_DIFFUSION_COLOR,
$show_color);
$preferences->save();
$uri = $request->getRequestURI()
->alter('blame', null)
->alter('color', null);
return id(new AphrontRedirectResponse())->setURI($uri);
}
// We need the blame information if blame is on and we're building plain
// text, or blame is on and this is an Ajax request. If blame is on and
// this is a colorized request, we don't show blame at first (we ajax it
// in afterward) so we don't need to query for it.
$needs_blame = ($show_blame && !$show_color) ||
($show_blame && $request->isAjax());
$params = array(
'commit' => $drequest->getCommit(),
'path' => $drequest->getPath(),
);
$byte_limit = null;
if ($view !== 'raw') {
$byte_limit = PhabricatorFileStorageEngine::getChunkThreshold();
$time_limit = 10;
$params += array(
'timeout' => $time_limit,
'byteLimit' => $byte_limit,
);
}
$response = $this->callConduitWithDiffusionRequest(
'diffusion.filecontentquery',
$params);
$hit_byte_limit = $response['tooHuge'];
$hit_time_limit = $response['tooSlow'];
$file_phid = $response['filePHID'];
if ($hit_byte_limit) {
$corpus = $this->buildErrorCorpus(
pht(
'This file is larger than %s byte(s), and too large to display '.
'in the web UI.',
phutil_format_bytes($byte_limit)));
} else if ($hit_time_limit) {
$corpus = $this->buildErrorCorpus(
pht(
'This file took too long to load from the repository (more than '.
'%s second(s)).',
new PhutilNumber($time_limit)));
} else {
$file = id(new PhabricatorFileQuery())
->setViewer($viewer)
->withPHIDs(array($file_phid))
->executeOne();
if (!$file) {
throw new Exception(pht('Failed to load content file!'));
}
if ($view === 'raw') {
return $file->getRedirectResponse();
}
$data = $file->loadFileData();
if (ArcanistDiffUtils::isHeuristicBinaryFile($data)) {
$file_uri = $file->getBestURI();
if ($file->isViewableImage()) {
$corpus = $this->buildImageCorpus($file_uri);
} else {
$corpus = $this->buildBinaryCorpus($file_uri, $data);
}
} else {
$this->loadLintMessages();
$this->coverage = $drequest->loadCoverage();
// Build the content of the file.
$corpus = $this->buildCorpus(
$show_blame,
$show_color,
$data,
$needs_blame,
$drequest,
$path,
$data);
}
}
if ($request->isAjax()) {
return id(new AphrontAjaxResponse())->setContent($corpus);
}
require_celerity_resource('diffusion-source-css');
// Render the page.
- $view = $this->buildActionView($drequest);
- $action_list = $this->enrichActionView(
+ $view = $this->buildCurtain($drequest);
+ $curtain = $this->enrichCurtain(
$view,
$drequest,
$show_blame,
$show_color);
- $properties = $this->buildPropertyView($drequest, $action_list);
- $object_box = id(new PHUIObjectBoxView())
- ->setHeader($this->buildHeaderView($drequest))
- ->addPropertyList($properties);
+ $properties = $this->buildPropertyView($drequest);
+ $header = $this->buildHeaderView($drequest);
+ $header->setHeaderIcon('fa-file-code-o');
$content = array();
- $content[] = $object_box;
$follow = $request->getStr('follow');
if ($follow) {
$notice = new PHUIInfoView();
$notice->setSeverity(PHUIInfoView::SEVERITY_WARNING);
$notice->setTitle(pht('Unable to Continue'));
switch ($follow) {
case 'first':
$notice->appendChild(
pht(
'Unable to continue tracing the history of this file because '.
'this commit is the first commit in the repository.'));
break;
case 'created':
$notice->appendChild(
pht(
'Unable to continue tracing the history of this file because '.
'this commit created the file.'));
break;
}
$content[] = $notice;
}
$renamed = $request->getStr('renamed');
if ($renamed) {
$notice = new PHUIInfoView();
$notice->setSeverity(PHUIInfoView::SEVERITY_NOTICE);
$notice->setTitle(pht('File Renamed'));
$notice->appendChild(
pht(
'File history passes through a rename from "%s" to "%s".',
$drequest->getPath(),
$renamed));
$content[] = $notice;
}
$content[] = $corpus;
$content[] = $this->buildOpenRevisions();
$crumbs = $this->buildCrumbs(
array(
'branch' => true,
'path' => true,
'view' => 'browse',
));
+ $crumbs->setBorder(true);
$basename = basename($this->getDiffusionRequest()->getPath());
+ $view = id(new PHUITwoColumnView())
+ ->setHeader($header)
+ ->setCurtain($curtain)
+ ->setMainColumn(array(
+ $content,
+ ));
+
+ if ($properties) {
+ $view->addPropertySection(pht('DETAILS'), $properties);
+ }
+
+ $title = array($basename, $repository->getDisplayName());
+
return $this->newPage()
- ->setTitle(
- array(
- $basename,
- $repository->getDisplayName(),
- ))
+ ->setTitle($title)
->setCrumbs($crumbs)
- ->appendChild($content);
+ ->appendChild(
+ array(
+ $view,
+ ));
+
}
public function browseDirectory(
DiffusionBrowseResultSet $results,
PHUIPagerView $pager) {
$request = $this->getRequest();
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$reason = $results->getReasonForEmptyResultSet();
- $content = array();
- $actions = $this->buildActionView($drequest);
- $properties = $this->buildPropertyView($drequest, $actions);
+ $curtain = $this->buildCurtain($drequest);
+ $details = $this->buildPropertyView($drequest);
- $object_box = id(new PHUIObjectBoxView())
- ->setHeader($this->buildHeaderView($drequest))
- ->addPropertyList($properties);
+ $header = $this->buildHeaderView($drequest);
+ $header->setHeaderIcon('fa-folder-open');
- $content[] = $object_box;
- $content[] = $this->renderSearchForm($collapsed = true);
+ $search_form = $this->renderSearchForm();
+ $empty_result = null;
+ $browse_panel = null;
if (!$results->isValidResults()) {
$empty_result = new DiffusionEmptyResultView();
$empty_result->setDiffusionRequest($drequest);
$empty_result->setDiffusionBrowseResultSet($results);
$empty_result->setView($request->getStr('view'));
- $content[] = $empty_result;
} else {
$phids = array();
foreach ($results->getPaths() as $result) {
$data = $result->getLastCommitData();
if ($data) {
if ($data->getCommitDetail('authorPHID')) {
$phids[$data->getCommitDetail('authorPHID')] = true;
}
}
}
$phids = array_keys($phids);
$handles = $this->loadViewerHandles($phids);
- $browse_table = new DiffusionBrowseTableView();
- $browse_table->setDiffusionRequest($drequest);
- $browse_table->setHandles($handles);
- $browse_table->setPaths($results->getPaths());
- $browse_table->setUser($request->getUser());
+ $browse_table = id(new DiffusionBrowseTableView())
+ ->setDiffusionRequest($drequest)
+ ->setHandles($handles)
+ ->setPaths($results->getPaths())
+ ->setUser($request->getUser());
- $browse_panel = new PHUIObjectBoxView();
- $browse_panel->setHeaderText($drequest->getPath(), '/');
- $browse_panel->setTable($browse_table);
+ $browse_header = id(new PHUIHeaderView())
+ ->setHeader(nonempty(basename($drequest->getPath()), '/'))
+ ->setHeaderIcon('fa-folder-open');
- $content[] = $browse_panel;
+ $browse_panel = id(new PHUIObjectBoxView())
+ ->setHeader($browse_header)
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
+ ->setTable($browse_table);
+
+ $browse_panel->setShowHide(
+ array(pht('Show Search')),
+ pht('Hide Search'),
+ $search_form,
+ '#');
}
- $content[] = $this->buildOpenRevisions();
- $content[] = $this->renderDirectoryReadme($results);
+ $open_revisions = $this->buildOpenRevisions();
+ $readme = $this->renderDirectoryReadme($results);
$crumbs = $this->buildCrumbs(
array(
'branch' => true,
'path' => true,
'view' => 'browse',
));
$pager_box = $this->renderTablePagerBox($pager);
+ $crumbs->setBorder(true);
+
+ $view = id(new PHUITwoColumnView())
+ ->setHeader($header)
+ ->setCurtain($curtain)
+ ->setMainColumn(array(
+ $empty_result,
+ $browse_panel,
+ ))
+ ->setFooter(array(
+ $open_revisions,
+ $readme,
+ $pager_box,
+ ));
+
+ if ($details) {
+ $view->addPropertySection(pht('DETAILS'), $details);
+ }
return $this->newPage()
- ->setTitle(
- array(
+ ->setTitle(array(
nonempty(basename($drequest->getPath()), '/'),
$repository->getDisplayName(),
))
->setCrumbs($crumbs)
->appendChild(
array(
- $content,
- $pager_box,
+ $view,
));
}
private function renderSearchResults() {
$request = $this->getRequest();
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$results = array();
$pager = id(new PHUIPagerView())
->readFromRequest($request);
$search_mode = null;
switch ($repository->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
$results = array();
break;
default:
if (strlen($this->getRequest()->getStr('grep'))) {
$search_mode = 'grep';
$query_string = $request->getStr('grep');
$results = $this->callConduitWithDiffusionRequest(
'diffusion.searchquery',
array(
'grep' => $query_string,
'commit' => $drequest->getStableCommit(),
'path' => $drequest->getPath(),
'limit' => $pager->getPageSize() + 1,
'offset' => $pager->getOffset(),
));
} else { // Filename search.
$search_mode = 'find';
$query_string = $request->getStr('find');
$results = $this->callConduitWithDiffusionRequest(
'diffusion.querypaths',
array(
'pattern' => $query_string,
'commit' => $drequest->getStableCommit(),
'path' => $drequest->getPath(),
'limit' => $pager->getPageSize() + 1,
'offset' => $pager->getOffset(),
));
}
break;
}
$results = $pager->sliceResults($results);
if ($search_mode == 'grep') {
$table = $this->renderGrepResults($results, $query_string);
$header = pht(
'File content matching "%s" under "%s"',
$query_string,
nonempty($drequest->getPath(), '/'));
} else {
$table = $this->renderFindResults($results);
$header = pht(
'Paths matching "%s" under "%s"',
$query_string,
nonempty($drequest->getPath(), '/'));
}
$box = id(new PHUIObjectBoxView())
->setHeaderText($header)
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setTable($table);
$pager_box = $this->renderTablePagerBox($pager);
return array($box, $pager_box);
}
private function renderGrepResults(array $results, $pattern) {
$drequest = $this->getDiffusionRequest();
require_celerity_resource('phabricator-search-results-css');
$rows = array();
foreach ($results as $result) {
list($path, $line, $string) = $result;
$href = $drequest->generateURI(array(
'action' => 'browse',
'path' => $path,
'line' => $line,
));
$matches = null;
$count = @preg_match_all(
'('.$pattern.')u',
$string,
$matches,
PREG_OFFSET_CAPTURE);
if (!$count) {
$output = ltrim($string);
} else {
$output = array();
$cursor = 0;
$length = strlen($string);
foreach ($matches[0] as $match) {
$offset = $match[1];
if ($cursor != $offset) {
$output[] = array(
'text' => substr($string, $cursor, $offset),
'highlight' => false,
);
}
$output[] = array(
'text' => $match[0],
'highlight' => true,
);
$cursor = $offset + strlen($match[0]);
}
if ($cursor != $length) {
$output[] = array(
'text' => substr($string, $cursor),
'highlight' => false,
);
}
if ($output) {
$output[0]['text'] = ltrim($output[0]['text']);
}
foreach ($output as $key => $segment) {
if ($segment['highlight']) {
$output[$key] = phutil_tag('strong', array(), $segment['text']);
} else {
$output[$key] = $segment['text'];
}
}
}
$string = phutil_tag(
'pre',
array('class' => 'PhabricatorMonospaced phui-source-fragment'),
$output);
$path = Filesystem::readablePath($path, $drequest->getPath());
$rows[] = array(
phutil_tag('a', array('href' => $href), $path),
$line,
$string,
);
}
$table = id(new AphrontTableView($rows))
->setClassName('remarkup-code')
->setHeaders(array(pht('Path'), pht('Line'), pht('String')))
->setColumnClasses(array('', 'n', 'wide'))
->setNoDataString(
pht(
'The pattern you searched for was not found in the content of any '.
'files.'));
return $table;
}
private function renderFindResults(array $results) {
$drequest = $this->getDiffusionRequest();
$rows = array();
foreach ($results as $result) {
$href = $drequest->generateURI(array(
'action' => 'browse',
'path' => $result,
));
$readable = Filesystem::readablePath($result, $drequest->getPath());
$rows[] = array(
phutil_tag('a', array('href' => $href), $readable),
);
}
$table = id(new AphrontTableView($rows))
->setHeaders(array(pht('Path')))
->setColumnClasses(array('wide'))
->setNoDataString(
pht(
'The pattern you searched for did not match the names of any '.
'files.'));
return $table;
}
private function loadLintMessages() {
$drequest = $this->getDiffusionRequest();
$branch = $drequest->loadBranch();
if (!$branch || !$branch->getLintCommit()) {
return;
}
$this->lintCommit = $branch->getLintCommit();
$conn = id(new PhabricatorRepository())->establishConnection('r');
$where = '';
if ($drequest->getLint()) {
$where = qsprintf(
$conn,
'AND code = %s',
$drequest->getLint());
}
$this->lintMessages = queryfx_all(
$conn,
'SELECT * FROM %T WHERE branchID = %d %Q AND path = %s',
PhabricatorRepository::TABLE_LINTMESSAGE,
$branch->getID(),
$where,
'/'.$drequest->getPath());
}
private function buildCorpus(
$show_blame,
$show_color,
$file_corpus,
$needs_blame,
DiffusionRequest $drequest,
$path,
$data) {
$viewer = $this->getViewer();
$blame_timeout = 15;
$blame_failed = false;
$highlight_limit = DifferentialChangesetParser::HIGHLIGHT_BYTE_LIMIT;
$blame_limit = DifferentialChangesetParser::HIGHLIGHT_BYTE_LIMIT;
$can_highlight = (strlen($file_corpus) <= $highlight_limit);
$can_blame = (strlen($file_corpus) <= $blame_limit);
if ($needs_blame && $can_blame) {
$blame = $this->loadBlame($path, $drequest->getCommit(), $blame_timeout);
list($blame_list, $blame_commits) = $blame;
if ($blame_list === null) {
$blame_failed = true;
$blame_list = array();
}
} else {
$blame_list = array();
$blame_commits = array();
}
if (!$show_color) {
$corpus = $this->renderPlaintextCorpus(
$file_corpus,
$blame_list,
$blame_commits,
$show_blame);
} else {
if ($can_highlight) {
require_celerity_resource('syntax-highlighting-css');
$highlighted = PhabricatorSyntaxHighlighter::highlightWithFilename(
$path,
$file_corpus);
$lines = phutil_split_lines($highlighted);
} else {
$lines = phutil_split_lines($file_corpus);
}
$rows = $this->buildDisplayRows(
$lines,
$blame_list,
$blame_commits,
$show_blame,
$show_color);
$corpus_table = javelin_tag(
'table',
array(
'class' => 'diffusion-source remarkup-code PhabricatorMonospaced',
'sigil' => 'phabricator-source',
),
$rows);
if ($this->getRequest()->isAjax()) {
return $corpus_table;
}
$id = celerity_generate_unique_node_id();
$repo = $drequest->getRepository();
$symbol_repos = nonempty($repo->getSymbolSources(), array());
$symbol_repos[] = $repo->getPHID();
$lang = last(explode('.', $drequest->getPath()));
$repo_languages = $repo->getSymbolLanguages();
$repo_languages = nonempty($repo_languages, array());
$repo_languages = array_fill_keys($repo_languages, true);
$needs_symbols = true;
if ($repo_languages && $symbol_repos) {
$have_symbols = id(new DiffusionSymbolQuery())
->existsSymbolsInRepository($repo->getPHID());
if (!$have_symbols) {
$needs_symbols = false;
}
}
if ($needs_symbols && $repo_languages) {
$needs_symbols = isset($repo_languages[$lang]);
}
if ($needs_symbols) {
Javelin::initBehavior(
'repository-crossreference',
array(
'container' => $id,
'lang' => $lang,
'repositories' => $symbol_repos,
));
}
$corpus = phutil_tag(
'div',
array(
'id' => $id,
),
$corpus_table);
Javelin::initBehavior('load-blame', array('id' => $id));
}
$edit = $this->renderEditButton();
$file = $this->renderFileButton();
$header = id(new PHUIHeaderView())
- ->setHeader(pht('File Contents'))
+ ->setHeader(basename($this->getDiffusionRequest()->getPath()))
+ ->setHeaderIcon('fa-file-code-o')
->addActionLink($edit)
->addActionLink($file);
$corpus = id(new PHUIObjectBoxView())
->setHeader($header)
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->appendChild($corpus)
->setCollapsed(true);
$messages = array();
if (!$can_highlight) {
$messages[] = pht(
'This file is larger than %s, so syntax highlighting is disabled '.
'by default.',
phutil_format_bytes($highlight_limit));
}
if ($show_blame && !$can_blame) {
$messages[] = pht(
'This file is larger than %s, so blame is disabled.',
phutil_format_bytes($blame_limit));
}
if ($blame_failed) {
$messages[] = pht(
'Failed to load blame information for this file in %s second(s).',
new PhutilNumber($blame_timeout));
}
if ($messages) {
$corpus->setInfoView(
id(new PHUIInfoView())
->setSeverity(PHUIInfoView::SEVERITY_WARNING)
->setErrors($messages));
}
return $corpus;
}
- private function enrichActionView(
- PhabricatorActionListView $view,
+ private function enrichCurtain(
+ PHUICurtainView $curtain,
DiffusionRequest $drequest,
$show_blame,
$show_color) {
- $viewer = $this->getRequest()->getUser();
+ $viewer = $this->getViewer();
$base_uri = $this->getRequest()->getRequestURI();
- $view->addAction(
+ $curtain->addAction(
id(new PhabricatorActionView())
->setName(pht('Show Last Change'))
->setHref(
$drequest->generateURI(
array(
'action' => 'change',
)))
->setIcon('fa-backward'));
if ($show_blame) {
$blame_text = pht('Disable Blame');
$blame_icon = 'fa-exclamation-circle lightgreytext';
$blame_value = 0;
} else {
$blame_text = pht('Enable Blame');
$blame_icon = 'fa-exclamation-circle';
$blame_value = 1;
}
- $view->addAction(
+ $curtain->addAction(
id(new PhabricatorActionView())
->setName($blame_text)
->setHref($base_uri->alter('blame', $blame_value))
->setIcon($blame_icon)
->setUser($viewer)
->setRenderAsForm($viewer->isLoggedIn()));
if ($show_color) {
$highlight_text = pht('Disable Highlighting');
$highlight_icon = 'fa-star-o grey';
$highlight_value = 0;
} else {
$highlight_text = pht('Enable Highlighting');
$highlight_icon = 'fa-star';
$highlight_value = 1;
}
- $view->addAction(
+ $curtain->addAction(
id(new PhabricatorActionView())
->setName($highlight_text)
->setHref($base_uri->alter('color', $highlight_value))
->setIcon($highlight_icon)
->setUser($viewer)
->setRenderAsForm($viewer->isLoggedIn()));
$href = null;
if ($this->getRequest()->getStr('lint') !== null) {
$lint_text = pht('Hide %d Lint Message(s)', count($this->lintMessages));
$href = $base_uri->alter('lint', null);
} else if ($this->lintCommit === null) {
$lint_text = pht('Lint not Available');
} else {
$lint_text = pht(
'Show %d Lint Message(s)',
count($this->lintMessages));
$href = $this->getDiffusionRequest()->generateURI(array(
'action' => 'browse',
'commit' => $this->lintCommit,
))->alter('lint', '');
}
- $view->addAction(
+ $curtain->addAction(
id(new PhabricatorActionView())
->setName($lint_text)
->setHref($href)
->setIcon('fa-exclamation-triangle')
->setDisabled(!$href));
- return $view;
+
+ $repository = $drequest->getRepository();
+
+ $owners = 'PhabricatorOwnersApplication';
+ if (PhabricatorApplication::isClassInstalled($owners)) {
+ $package_query = id(new PhabricatorOwnersPackageQuery())
+ ->setViewer($viewer)
+ ->withStatuses(array(PhabricatorOwnersPackage::STATUS_ACTIVE))
+ ->withControl(
+ $repository->getPHID(),
+ array(
+ $drequest->getPath(),
+ ));
+
+ $package_query->execute();
+
+ $packages = $package_query->getControllingPackagesForPath(
+ $repository->getPHID(),
+ $drequest->getPath());
+
+ if ($packages) {
+ $ownership = id(new PHUIStatusListView())
+ ->setUser($viewer);
+
+ foreach ($packages as $package) {
+ $icon = 'fa-list-alt';
+ $color = 'grey';
+
+ $item = id(new PHUIStatusItemView())
+ ->setIcon($icon, $color)
+ ->setTarget($viewer->renderHandle($package->getPHID()));
+
+ $ownership->addItem($item);
+ }
+ } else {
+ $ownership = phutil_tag('em', array(), pht('None'));
+ }
+
+ $curtain->newPanel()
+ ->setHeaderText(pht('Owners'))
+ ->appendChild($ownership);
+ }
+
+ return $curtain;
}
private function renderEditButton() {
$request = $this->getRequest();
$user = $request->getUser();
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$path = $drequest->getPath();
$line = nonempty((int)$drequest->getLine(), 1);
$editor_link = $user->loadEditorLink($path, $line, $repository);
$template = $user->loadEditorLink($path, '%l', $repository);
$button = id(new PHUIButtonView())
->setTag('a')
->setText(pht('Open in Editor'))
->setHref($editor_link)
->setIcon('fa-pencil')
->setID('editor_link')
->setMetadata(array('link_template' => $template))
->setDisabled(!$editor_link);
return $button;
}
private function renderFileButton($file_uri = null) {
$base_uri = $this->getRequest()->getRequestURI();
if ($file_uri) {
$text = pht('Download Raw File');
$href = $file_uri;
$icon = 'fa-download';
} else {
$text = pht('View Raw File');
$href = $base_uri->alter('view', 'raw');
$icon = 'fa-file-text';
}
$button = id(new PHUIButtonView())
->setTag('a')
->setText($text)
->setHref($href)
->setIcon($icon);
return $button;
}
private function buildDisplayRows(
array $lines,
array $blame_list,
array $blame_commits,
$show_color,
$show_blame) {
$request = $this->getRequest();
$viewer = $this->getViewer();
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$revision_map = array();
$revisions = array();
if ($blame_commits) {
$commit_map = mpull($blame_commits, 'getCommitIdentifier', 'getPHID');
$revision_ids = id(new DifferentialRevision())
->loadIDsByCommitPHIDs(array_keys($commit_map));
if ($revision_ids) {
$revisions = id(new DifferentialRevisionQuery())
->setViewer($viewer)
->withIDs($revision_ids)
->execute();
$revisions = mpull($revisions, null, 'getID');
}
foreach ($revision_ids as $commit_phid => $revision_id) {
$revision_map[$commit_map[$commit_phid]] = $revision_id;
}
}
$phids = array();
foreach ($blame_commits as $commit) {
$author_phid = $commit->getAuthorPHID();
if ($author_phid === null) {
continue;
}
$phids[$author_phid] = $author_phid;
}
foreach ($revisions as $revision) {
$author_phid = $revision->getAuthorPHID();
if ($author_phid === null) {
continue;
}
$phids[$author_phid] = $author_phid;
}
$handles = $viewer->loadHandles($phids);
$colors = array();
if ($blame_commits) {
$epochs = array();
foreach ($blame_commits as $identifier => $commit) {
$epochs[$identifier] = $commit->getEpoch();
}
$epoch_list = array_filter($epochs);
$epoch_list = array_unique($epoch_list);
$epoch_list = array_values($epoch_list);
$epoch_min = min($epoch_list);
$epoch_max = max($epoch_list);
$epoch_range = ($epoch_max - $epoch_min) + 1;
foreach ($blame_commits as $identifier => $commit) {
$epoch = $epochs[$identifier];
if (!$epoch) {
$color = '#ffffdd'; // Warning color, missing data.
} else {
$color_ratio = ($epoch - $epoch_min) / $epoch_range;
$color_value = 0xE6 * (1.0 - $color_ratio);
$color = sprintf(
'#%02x%02x%02x',
$color_value,
0xF6,
$color_value);
}
$colors[$identifier] = $color;
}
}
$display = array();
$last_identifier = null;
$last_color = null;
foreach ($lines as $line_index => $line) {
$color = '#f6f6f6';
$duplicate = false;
if (isset($blame_list[$line_index])) {
$identifier = $blame_list[$line_index];
if (isset($colors[$identifier])) {
$color = $colors[$identifier];
}
if ($identifier === $last_identifier) {
$duplicate = true;
} else {
$last_identifier = $identifier;
}
}
$display[$line_index] = array(
'data' => $line,
'target' => false,
'highlighted' => false,
'color' => $color,
'duplicate' => $duplicate,
);
}
$line_arr = array();
$line_str = $drequest->getLine();
$ranges = explode(',', $line_str);
foreach ($ranges as $range) {
if (strpos($range, '-') !== false) {
list($min, $max) = explode('-', $range, 2);
$line_arr[] = array(
'min' => min($min, $max),
'max' => max($min, $max),
);
} else if (strlen($range)) {
$line_arr[] = array(
'min' => $range,
'max' => $range,
);
}
}
// Mark the first highlighted line as the target line.
if ($line_arr) {
$target_line = $line_arr[0]['min'];
if (isset($display[$target_line - 1])) {
$display[$target_line - 1]['target'] = true;
}
}
// Mark all other highlighted lines as highlighted.
foreach ($line_arr as $range) {
for ($ii = $range['min']; $ii <= $range['max']; $ii++) {
if (isset($display[$ii - 1])) {
$display[$ii - 1]['highlighted'] = true;
}
}
}
$engine = null;
$inlines = array();
if ($this->getRequest()->getStr('lint') !== null && $this->lintMessages) {
$engine = new PhabricatorMarkupEngine();
$engine->setViewer($viewer);
foreach ($this->lintMessages as $message) {
$inline = id(new PhabricatorAuditInlineComment())
->setSyntheticAuthor(
ArcanistLintSeverity::getStringForSeverity($message['severity']).
' '.$message['code'].' ('.$message['name'].')')
->setLineNumber($message['line'])
->setContent($message['description']);
$inlines[$message['line']][] = $inline;
$engine->addObject(
$inline,
PhabricatorInlineCommentInterface::MARKUP_FIELD_BODY);
}
$engine->process();
require_celerity_resource('differential-changeset-view-css');
}
$rows = $this->renderInlines(
idx($inlines, 0, array()),
$show_blame,
(bool)$this->coverage,
$engine);
// NOTE: We're doing this manually because rendering is otherwise
// dominated by URI generation for very large files.
$line_base = (string)$drequest->generateURI(
array(
'action' => 'browse',
'stable' => true,
));
require_celerity_resource('aphront-tooltip-css');
Javelin::initBehavior('phabricator-oncopy');
Javelin::initBehavior('phabricator-tooltips');
Javelin::initBehavior('phabricator-line-linker');
// Render these once, since they tend to get repeated many times in large
// blame outputs.
$commit_links = $this->renderCommitLinks($blame_commits, $handles);
$revision_links = $this->renderRevisionLinks($revisions, $handles);
$skip_text = pht('Skip Past This Commit');
foreach ($display as $line_index => $line) {
$row = array();
$line_number = $line_index + 1;
$line_href = $line_base.'$'.$line_number;
if (isset($blame_list[$line_index])) {
$identifier = $blame_list[$line_index];
} else {
$identifier = null;
}
$revision_link = null;
$commit_link = null;
$before_link = null;
$style = 'background: '.$line['color'].';';
if ($identifier && !$line['duplicate']) {
if (isset($commit_links[$identifier])) {
$commit_link = $commit_links[$identifier];
}
if (isset($revision_map[$identifier])) {
$revision_id = $revision_map[$identifier];
if (isset($revision_links[$revision_id])) {
$revision_link = $revision_links[$revision_id];
}
}
$skip_href = $line_href.'?before='.$identifier.'&view=blame';
$before_link = javelin_tag(
'a',
array(
'href' => $skip_href,
'sigil' => 'has-tooltip',
'meta' => array(
'tip' => $skip_text,
'align' => 'E',
'size' => 300,
),
),
"\xC2\xAB");
}
$row[] = phutil_tag(
'th',
array(
'class' => 'diffusion-blame-link',
),
$before_link);
$object_links = array();
$object_links[] = $commit_link;
if ($revision_link) {
$object_links[] = phutil_tag('span', array(), '/');
$object_links[] = $revision_link;
}
$row[] = phutil_tag(
'th',
array(
'class' => 'diffusion-rev-link',
),
$object_links);
$line_link = phutil_tag(
'a',
array(
'href' => $line_href,
'style' => $style,
),
$line_number);
$row[] = javelin_tag(
'th',
array(
'class' => 'diffusion-line-link',
'sigil' => 'phabricator-source-line',
'style' => $style,
),
$line_link);
if ($line['target']) {
Javelin::initBehavior(
'diffusion-jump-to',
array(
'target' => 'scroll_target',
));
$anchor_text = phutil_tag(
'a',
array(
'id' => 'scroll_target',
),
'');
} else {
$anchor_text = null;
}
$row[] = phutil_tag(
'td',
array(
),
array(
$anchor_text,
// NOTE: See phabricator-oncopy behavior.
"\xE2\x80\x8B",
// TODO: [HTML] Not ideal.
phutil_safe_html(str_replace("\t", ' ', $line['data'])),
));
if ($this->coverage) {
require_celerity_resource('differential-changeset-view-css');
$cov_index = $line_index;
if (isset($this->coverage[$cov_index])) {
$cov_class = $this->coverage[$cov_index];
} else {
$cov_class = 'N';
}
$row[] = phutil_tag(
'td',
array(
'class' => 'cov cov-'.$cov_class,
),
'');
}
$rows[] = phutil_tag(
'tr',
array(
'class' => ($line['highlighted'] ?
'phabricator-source-highlight' :
null),
),
$row);
$cur_inlines = $this->renderInlines(
idx($inlines, $line_number, array()),
$show_blame,
$this->coverage,
$engine);
foreach ($cur_inlines as $cur_inline) {
$rows[] = $cur_inline;
}
}
return $rows;
}
private function renderInlines(
array $inlines,
$show_blame,
$has_coverage,
$engine) {
$rows = array();
foreach ($inlines as $inline) {
// TODO: This should use modern scaffolding code.
$inline_view = id(new PHUIDiffInlineCommentDetailView())
->setUser($this->getViewer())
->setMarkupEngine($engine)
->setInlineComment($inline)
->render();
$row = array_fill(0, ($show_blame ? 3 : 1), phutil_tag('th'));
$row[] = phutil_tag('td', array(), $inline_view);
if ($has_coverage) {
$row[] = phutil_tag(
'td',
array(
'class' => 'cov cov-I',
));
}
$rows[] = phutil_tag('tr', array('class' => 'inline'), $row);
}
return $rows;
}
private function buildImageCorpus($file_uri) {
$properties = new PHUIPropertyListView();
$properties->addImageContent(
phutil_tag(
'img',
array(
'src' => $file_uri,
)));
$file = $this->renderFileButton($file_uri);
$header = id(new PHUIHeaderView())
- ->setHeader(pht('Image'))
- ->addActionLink($file);
+ ->setHeader(basename($this->getDiffusionRequest()->getPath()))
+ ->addActionLink($file)
+ ->setHeaderIcon('fa-file-image-o');
return id(new PHUIObjectBoxView())
->setHeader($header)
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addPropertyList($properties);
}
private function buildBinaryCorpus($file_uri, $data) {
$size = new PhutilNumber(strlen($data));
$text = pht('This is a binary file. It is %s byte(s) in length.', $size);
$text = id(new PHUIBoxView())
->addPadding(PHUI::PADDING_LARGE)
->appendChild($text);
$file = $this->renderFileButton($file_uri);
$header = id(new PHUIHeaderView())
- ->setHeader(pht('Details'))
+ ->setHeader(pht('DETAILS'))
->addActionLink($file);
$box = id(new PHUIObjectBoxView())
->setHeader($header)
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->appendChild($text);
return $box;
}
private function buildErrorCorpus($message) {
$text = id(new PHUIBoxView())
->addPadding(PHUI::PADDING_LARGE)
->appendChild($message);
$header = id(new PHUIHeaderView())
- ->setHeader(pht('Details'));
+ ->setHeader(pht('DETAILS'));
$box = id(new PHUIObjectBoxView())
->setHeader($header)
->appendChild($text);
return $box;
}
private function buildBeforeResponse($before) {
$request = $this->getRequest();
$drequest = $this->getDiffusionRequest();
// NOTE: We need to get the grandparent so we can capture filename changes
// in the parent.
$parent = $this->loadParentCommitOf($before);
$old_filename = null;
$was_created = false;
if ($parent) {
$grandparent = $this->loadParentCommitOf($parent);
if ($grandparent) {
$rename_query = new DiffusionRenameHistoryQuery();
$rename_query->setRequest($drequest);
$rename_query->setOldCommit($grandparent);
$rename_query->setViewer($request->getUser());
$old_filename = $rename_query->loadOldFilename();
$was_created = $rename_query->getWasCreated();
}
}
$follow = null;
if ($was_created) {
// If the file was created in history, that means older commits won't
// have it. Since we know it existed at 'before', it must have been
// created then; jump there.
$target_commit = $before;
$follow = 'created';
} else if ($parent) {
// If we found a parent, jump to it. This is the normal case.
$target_commit = $parent;
} else {
// If there's no parent, this was probably created in the initial commit?
// And the "was_created" check will fail because we can't identify the
// grandparent. Keep the user at 'before'.
$target_commit = $before;
$follow = 'first';
}
$path = $drequest->getPath();
$renamed = null;
if ($old_filename !== null &&
$old_filename !== '/'.$path) {
$renamed = $path;
$path = $old_filename;
}
$line = null;
// If there's a follow error, drop the line so the user sees the message.
if (!$follow) {
$line = $this->getBeforeLineNumber($target_commit);
}
$before_uri = $drequest->generateURI(
array(
'action' => 'browse',
'commit' => $target_commit,
'line' => $line,
'path' => $path,
));
$before_uri->setQueryParams($request->getRequestURI()->getQueryParams());
$before_uri = $before_uri->alter('before', null);
$before_uri = $before_uri->alter('renamed', $renamed);
$before_uri = $before_uri->alter('follow', $follow);
return id(new AphrontRedirectResponse())->setURI($before_uri);
}
private function getBeforeLineNumber($target_commit) {
$drequest = $this->getDiffusionRequest();
$line = $drequest->getLine();
if (!$line) {
return null;
}
$raw_diff = $this->callConduitWithDiffusionRequest(
'diffusion.rawdiffquery',
array(
'commit' => $drequest->getCommit(),
'path' => $drequest->getPath(),
'againstCommit' => $target_commit,
));
$old_line = 0;
$new_line = 0;
foreach (explode("\n", $raw_diff) as $text) {
if ($text[0] == '-' || $text[0] == ' ') {
$old_line++;
}
if ($text[0] == '+' || $text[0] == ' ') {
$new_line++;
}
if ($new_line == $line) {
return $old_line;
}
}
// We didn't find the target line.
return $line;
}
private function loadParentCommitOf($commit) {
$drequest = $this->getDiffusionRequest();
$user = $this->getRequest()->getUser();
$before_req = DiffusionRequest::newFromDictionary(
array(
'user' => $user,
'repository' => $drequest->getRepository(),
'commit' => $commit,
));
$parents = DiffusionQuery::callConduitWithDiffusionRequest(
$user,
$before_req,
'diffusion.commitparentsquery',
array(
'commit' => $commit,
));
return head($parents);
}
private function renderRevisionTooltip(
DifferentialRevision $revision,
$handles) {
$viewer = $this->getRequest()->getUser();
$date = phabricator_date($revision->getDateModified(), $viewer);
$id = $revision->getID();
$title = $revision->getTitle();
$header = "D{$id} {$title}";
$author = $handles[$revision->getAuthorPHID()]->getName();
return "{$header}\n{$date} \xC2\xB7 {$author}";
}
private function renderCommitTooltip(
PhabricatorRepositoryCommit $commit,
$author) {
$viewer = $this->getRequest()->getUser();
$date = phabricator_date($commit->getEpoch(), $viewer);
$summary = trim($commit->getSummary());
return "{$summary}\n{$date} \xC2\xB7 {$author}";
}
- protected function renderSearchForm($collapsed) {
+ protected function renderSearchForm() {
$drequest = $this->getDiffusionRequest();
$forms = array();
$form = id(new AphrontFormView())
- ->setUser($this->getRequest()->getUser())
+ ->setUser($this->getViewer())
->setMethod('GET');
switch ($drequest->getRepository()->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
$forms[] = id(clone $form)
->appendChild(pht('Search is not available in Subversion.'));
break;
default:
$forms[] = id(clone $form)
->appendChild(
id(new AphrontFormTextWithSubmitControl())
->setLabel(pht('File Name'))
->setSubmitLabel(pht('Search File Names'))
->setName('find')
->setValue($this->getRequest()->getStr('find')));
$forms[] = id(clone $form)
->appendChild(
id(new AphrontFormTextWithSubmitControl())
->setLabel(pht('Pattern'))
->setSubmitLabel(pht('Grep File Content'))
->setName('grep')
->setValue($this->getRequest()->getStr('grep')));
break;
}
- $filter = new AphrontListFilterView();
- $filter->appendChild($forms);
-
- if ($collapsed) {
- $filter->setCollapsed(
- pht('Show Search'),
- pht('Hide Search'),
- pht('Search for file names or content in this directory.'),
- '#');
- }
+ require_celerity_resource('diffusion-icons-css');
+ $form_box = phutil_tag_div('diffusion-search-boxen', $forms);
- $filter = id(new PHUIBoxView())
- ->addClass('mlt mlb')
- ->appendChild($filter);
-
- return $filter;
+ return $form_box;
}
protected function markupText($text) {
$engine = PhabricatorMarkupEngine::newDiffusionMarkupEngine();
$engine->setConfig('viewer', $this->getRequest()->getUser());
$text = $engine->markupText($text);
$text = phutil_tag(
'div',
array(
'class' => 'phabricator-remarkup',
),
$text);
return $text;
}
protected function buildHeaderView(DiffusionRequest $drequest) {
- $viewer = $this->getRequest()->getUser();
+ $viewer = $this->getViewer();
+
+ $tag = $this->renderCommitHashTag($drequest);
$header = id(new PHUIHeaderView())
->setUser($viewer)
->setHeader($this->renderPathLinks($drequest, $mode = 'browse'))
- ->setPolicyObject($drequest->getRepository());
+ ->addTag($tag);
return $header;
}
- protected function buildActionView(DiffusionRequest $drequest) {
- $viewer = $this->getRequest()->getUser();
+ protected function buildCurtain(DiffusionRequest $drequest) {
+ $viewer = $this->getViewer();
- $view = id(new PhabricatorActionListView())
- ->setUser($viewer);
+ $curtain = $this->newCurtainView($drequest);
$history_uri = $drequest->generateURI(
array(
'action' => 'history',
));
- $view->addAction(
+ $curtain->addAction(
id(new PhabricatorActionView())
->setName(pht('View History'))
->setHref($history_uri)
->setIcon('fa-list'));
$behind_head = $drequest->getSymbolicCommit();
$head_uri = $drequest->generateURI(
array(
'commit' => '',
'action' => 'browse',
));
- $view->addAction(
+ $curtain->addAction(
id(new PhabricatorActionView())
->setName(pht('Jump to HEAD'))
->setHref($head_uri)
->setIcon('fa-home')
->setDisabled(!$behind_head));
- return $view;
+ return $curtain;
}
protected function buildPropertyView(
- DiffusionRequest $drequest,
- PhabricatorActionListView $actions) {
+ DiffusionRequest $drequest) {
$viewer = $this->getViewer();
-
$view = id(new PHUIPropertyListView())
- ->setUser($viewer)
- ->setActionList($actions);
-
- $stable_commit = $drequest->getStableCommit();
-
- $view->addProperty(
- pht('Commit'),
- phutil_tag(
- 'a',
- array(
- 'href' => $drequest->generateURI(
- array(
- 'action' => 'commit',
- 'commit' => $stable_commit,
- )),
- ),
- $drequest->getRepository()->formatCommitName($stable_commit)));
+ ->setUser($viewer);
if ($drequest->getSymbolicType() == 'tag') {
$symbolic = $drequest->getSymbolicCommit();
$view->addProperty(pht('Tag'), $symbolic);
$tags = $this->callConduitWithDiffusionRequest(
'diffusion.tagsquery',
array(
'names' => array($symbolic),
'needMessages' => true,
));
$tags = DiffusionRepositoryTag::newFromConduit($tags);
$tags = mpull($tags, null, 'getName');
$tag = idx($tags, $symbolic);
if ($tag && strlen($tag->getMessage())) {
$view->addSectionHeader(
pht('Tag Content'), 'fa-tag');
$view->addTextContent($this->markupText($tag->getMessage()));
}
}
- $repository = $drequest->getRepository();
-
- $owners = 'PhabricatorOwnersApplication';
- if (PhabricatorApplication::isClassInstalled($owners)) {
- $package_query = id(new PhabricatorOwnersPackageQuery())
- ->setViewer($viewer)
- ->withStatuses(array(PhabricatorOwnersPackage::STATUS_ACTIVE))
- ->withControl(
- $repository->getPHID(),
- array(
- $drequest->getPath(),
- ));
-
- $package_query->execute();
-
- $packages = $package_query->getControllingPackagesForPath(
- $repository->getPHID(),
- $drequest->getPath());
-
- if ($packages) {
- $ownership = id(new PHUIStatusListView())
- ->setUser($viewer);
-
- foreach ($packages as $package) {
- $icon = 'fa-list-alt';
- $color = 'grey';
-
- $item = id(new PHUIStatusItemView())
- ->setIcon($icon, $color)
- ->setTarget($viewer->renderHandle($package->getPHID()));
-
- $ownership->addItem($item);
- }
- } else {
- $ownership = phutil_tag('em', array(), pht('None'));
- }
-
- $view->addProperty(pht('Packages'), $ownership);
+ if ($view->hasAnyProperties()) {
+ return $view;
}
- return $view;
+ return null;
}
private function buildOpenRevisions() {
$viewer = $this->getViewer();
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$path = $drequest->getPath();
$path_map = id(new DiffusionPathIDQuery(array($path)))->loadPathIDs();
$path_id = idx($path_map, $path);
if (!$path_id) {
return null;
}
$recent = (PhabricatorTime::getNow() - phutil_units('30 days in seconds'));
$revisions = id(new DifferentialRevisionQuery())
->setViewer($viewer)
->withPath($repository->getID(), $path_id)
->withStatus(DifferentialRevisionQuery::STATUS_OPEN)
->withUpdatedEpochBetween($recent, null)
->setOrder(DifferentialRevisionQuery::ORDER_MODIFIED)
->setLimit(10)
->needRelationships(true)
->needFlags(true)
->needDrafts(true)
->execute();
if (!$revisions) {
return null;
}
$header = id(new PHUIHeaderView())
->setHeader(pht('Open Revisions'))
->setSubheader(
pht('Recently updated open revisions affecting this file.'));
$view = id(new DifferentialRevisionListView())
->setHeader($header)
->setRevisions($revisions)
->setUser($viewer);
$phids = $view->getRequiredHandlePHIDs();
$handles = $this->loadViewerHandles($phids);
$view->setHandles($handles);
return $view;
}
private function loadBlame($path, $commit, $timeout) {
$blame = $this->callConduitWithDiffusionRequest(
'diffusion.blame',
array(
'commit' => $commit,
'paths' => array($path),
'timeout' => $timeout,
));
$identifiers = idx($blame, $path, null);
if ($identifiers) {
$viewer = $this->getViewer();
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$commits = id(new DiffusionCommitQuery())
->setViewer($viewer)
->withRepository($repository)
->withIdentifiers($identifiers)
// TODO: We only fetch this to improve author display behavior, but
// shouldn't really need to?
->needCommitData(true)
->execute();
$commits = mpull($commits, null, 'getCommitIdentifier');
} else {
$commits = array();
}
return array($identifiers, $commits);
}
private function renderCommitLinks(array $commits, $handles) {
$links = array();
foreach ($commits as $identifier => $commit) {
$tooltip = $this->renderCommitTooltip(
$commit,
$commit->renderAuthorShortName($handles));
$commit_link = javelin_tag(
'a',
array(
'href' => $commit->getURI(),
'sigil' => 'has-tooltip',
'meta' => array(
'tip' => $tooltip,
'align' => 'E',
'size' => 600,
),
),
$commit->getLocalName());
$links[$identifier] = $commit_link;
}
return $links;
}
private function renderRevisionLinks(array $revisions, $handles) {
$links = array();
foreach ($revisions as $revision) {
$revision_id = $revision->getID();
$tooltip = $this->renderRevisionTooltip($revision, $handles);
$revision_link = javelin_tag(
'a',
array(
'href' => '/'.$revision->getMonogram(),
'sigil' => 'has-tooltip',
'meta' => array(
'tip' => $tooltip,
'align' => 'E',
'size' => 600,
),
),
$revision->getMonogram());
$links[$revision_id] = $revision_link;
}
return $links;
}
private function renderPlaintextCorpus(
$file_corpus,
array $blame_list,
array $blame_commits,
$show_blame) {
$viewer = $this->getViewer();
if (!$show_blame) {
$corpus = $file_corpus;
} else {
$author_phids = array();
foreach ($blame_commits as $commit) {
$author_phid = $commit->getAuthorPHID();
if ($author_phid === null) {
continue;
}
$author_phids[$author_phid] = $author_phid;
}
if ($author_phids) {
$handles = $viewer->loadHandles($author_phids);
} else {
$handles = array();
}
$authors = array();
$names = array();
foreach ($blame_commits as $identifier => $commit) {
$author = $commit->renderAuthorShortName($handles);
$name = $commit->getLocalName();
$authors[$identifier] = $author;
$names[$identifier] = $name;
}
$lines = phutil_split_lines($file_corpus);
$rows = array();
foreach ($lines as $line_number => $line) {
$commit_name = null;
$author = null;
if (isset($blame_list[$line_number])) {
$identifier = $blame_list[$line_number];
if (isset($names[$identifier])) {
$commit_name = $names[$identifier];
}
if (isset($authors[$identifier])) {
$author = $authors[$identifier];
}
}
$rows[] = sprintf(
'%-10s %-20s %s',
$commit_name,
$author,
$line);
}
$corpus = implode('', $rows);
}
return phutil_tag(
'textarea',
array(
'style' => 'border: none; width: 100%; height: 80em; '.
'font-family: monospace',
),
$corpus);
}
}
diff --git a/src/applications/diffusion/controller/DiffusionChangeController.php b/src/applications/diffusion/controller/DiffusionChangeController.php
index 86b371c38b..90258134c4 100644
--- a/src/applications/diffusion/controller/DiffusionChangeController.php
+++ b/src/applications/diffusion/controller/DiffusionChangeController.php
@@ -1,170 +1,186 @@
<?php
final class DiffusionChangeController extends DiffusionController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
$response = $this->loadDiffusionContext();
if ($response) {
return $response;
}
$viewer = $this->getViewer();
$drequest = $this->getDiffusionRequest();
- $content = array();
-
$data = $this->callConduitWithDiffusionRequest(
'diffusion.diffquery',
array(
'commit' => $drequest->getCommit(),
'path' => $drequest->getPath(),
));
$drequest->updateSymbolicCommit($data['effectiveCommit']);
$raw_changes = ArcanistDiffChange::newFromConduit($data['changes']);
$diff = DifferentialDiff::newEphemeralFromRawChanges(
$raw_changes);
$changesets = $diff->getChangesets();
$changeset = reset($changesets);
if (!$changeset) {
// TODO: Refine this.
return new Aphront404Response();
}
$repository = $drequest->getRepository();
$changesets = array(
0 => $changeset,
);
+ $changeset_header = $this->buildChangesetHeader($drequest);
+
$changeset_view = new DifferentialChangesetListView();
- $changeset_view->setTitle(pht('Change'));
$changeset_view->setChangesets($changesets);
+ $changeset_view->setBackground(PHUIObjectBoxView::BLUE_PROPERTY);
$changeset_view->setVisibleChangesets($changesets);
$changeset_view->setRenderingReferences(
array(
0 => $drequest->generateURI(array('action' => 'rendering-ref')),
));
$raw_params = array(
'action' => 'browse',
'params' => array(
'view' => 'raw',
),
);
$right_uri = $drequest->generateURI($raw_params);
$raw_params['params']['before'] = $drequest->getStableCommit();
$left_uri = $drequest->generateURI($raw_params);
$changeset_view->setRawFileURIs($left_uri, $right_uri);
$changeset_view->setRenderURI($repository->getPathURI('diff/'));
$changeset_view->setWhitespace(
DifferentialChangesetParser::WHITESPACE_SHOW_ALL);
$changeset_view->setUser($viewer);
+ $changeset_view->setHeader($changeset_header);
// TODO: This is pretty awkward, unify the CSS between Diffusion and
// Differential better.
require_celerity_resource('differential-core-view-css');
- $content[] = $changeset_view->render();
$crumbs = $this->buildCrumbs(
array(
'branch' => true,
'path' => true,
'view' => 'change',
));
+ $crumbs->setBorder(true);
$links = $this->renderPathLinks($drequest, $mode = 'browse');
+ $header = $this->buildHeader($drequest, $links);
- $header = id(new PHUIHeaderView())
- ->setHeader($links)
- ->setUser($viewer)
- ->setPolicyObject($drequest->getRepository());
- $actions = $this->buildActionView($drequest);
- $properties = $this->buildPropertyView($drequest, $actions);
-
- $object_box = id(new PHUIObjectBoxView())
+ $view = id(new PHUITwoColumnView())
->setHeader($header)
- ->addPropertyList($properties);
+ ->setMainColumn(array(
+ ))
+ ->setFooter(array(
+ $changeset_view,
+ ));
return $this->newPage()
->setTitle(
array(
basename($drequest->getPath()),
$repository->getDisplayName(),
))
->setCrumbs($crumbs)
->appendChild(
array(
- $object_box,
- $content,
+ $view,
));
}
- private function buildActionView(DiffusionRequest $drequest) {
- $viewer = $this->getRequest()->getUser();
+ private function buildHeader(
+ DiffusionRequest $drequest,
+ $links) {
+ $viewer = $this->getViewer();
- $view = id(new PhabricatorActionListView())
- ->setUser($viewer);
+ $tag = $this->renderCommitHashTag($drequest);
+
+ $header = id(new PHUIHeaderView())
+ ->setHeader($links)
+ ->setUser($viewer)
+ ->setPolicyObject($drequest->getRepository())
+ ->addTag($tag);
+
+ return $header;
+ }
+
+ private function buildChangesetHeader(DiffusionRequest $drequest) {
+ $viewer = $this->getViewer();
+
+ $header = id(new PHUIHeaderView())
+ ->setHeader(pht('Changes'));
$history_uri = $drequest->generateURI(
array(
'action' => 'history',
));
- $view->addAction(
- id(new PhabricatorActionView())
- ->setName(pht('View History'))
+ $header->addActionLink(
+ id(new PHUIButtonView())
+ ->setTag('a')
+ ->setText(pht('View History'))
->setHref($history_uri)
->setIcon('fa-clock-o'));
$browse_uri = $drequest->generateURI(
array(
'action' => 'browse',
));
- $view->addAction(
- id(new PhabricatorActionView())
- ->setName(pht('Browse Content'))
+ $header->addActionLink(
+ id(new PHUIButtonView())
+ ->setTag('a')
+ ->setText(pht('Browse Content'))
->setHref($browse_uri)
->setIcon('fa-files-o'));
- return $view;
+ return $header;
}
protected function buildPropertyView(
DiffusionRequest $drequest,
PhabricatorActionListView $actions) {
$viewer = $this->getRequest()->getUser();
$view = id(new PHUIPropertyListView())
->setUser($viewer)
->setActionList($actions);
$stable_commit = $drequest->getStableCommit();
$view->addProperty(
pht('Commit'),
phutil_tag(
'a',
array(
'href' => $drequest->generateURI(
array(
'action' => 'commit',
'commit' => $stable_commit,
)),
),
$drequest->getRepository()->formatCommitName($stable_commit)));
return $view;
}
}
diff --git a/src/applications/diffusion/controller/DiffusionCommitController.php b/src/applications/diffusion/controller/DiffusionCommitController.php
index 94ca15ac4f..b14477ffa3 100644
--- a/src/applications/diffusion/controller/DiffusionCommitController.php
+++ b/src/applications/diffusion/controller/DiffusionCommitController.php
@@ -1,1237 +1,1283 @@
<?php
final class DiffusionCommitController extends DiffusionController {
const CHANGES_LIMIT = 100;
private $auditAuthorityPHIDs;
private $highlightedAudits;
private $commitParents;
private $commitRefs;
private $commitMerges;
private $commitErrors;
private $commitExists;
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
$response = $this->loadDiffusionContext();
if ($response) {
return $response;
}
$drequest = $this->getDiffusionRequest();
-
- $user = $request->getUser();
+ $viewer = $request->getUser();
if ($request->getStr('diff')) {
return $this->buildRawDiffResponse($drequest);
}
$repository = $drequest->getRepository();
- $content = array();
$commit = id(new DiffusionCommitQuery())
- ->setViewer($request->getUser())
+ ->setViewer($viewer)
->withRepository($repository)
->withIdentifiers(array($drequest->getCommit()))
->needCommitData(true)
->needAuditRequests(true)
->executeOne();
$crumbs = $this->buildCrumbs(array(
'commit' => true,
));
+ $crumbs->setBorder(true);
if (!$commit) {
if (!$this->getCommitExists()) {
return new Aphront404Response();
}
$error = id(new PHUIInfoView())
->setTitle(pht('Commit Still Parsing'))
->appendChild(
pht(
'Failed to load the commit because the commit has not been '.
'parsed yet.'));
return $this->buildApplicationPage(
array(
$crumbs,
$error,
),
array(
'title' => pht('Commit Still Parsing'),
));
}
$audit_requests = $commit->getAudits();
$this->auditAuthorityPHIDs =
- PhabricatorAuditCommentEditor::loadAuditPHIDsForUser($user);
+ PhabricatorAuditCommentEditor::loadAuditPHIDsForUser($viewer);
$commit_data = $commit->getCommitData();
$is_foreign = $commit_data->getCommitDetail('foreign-svn-stub');
+ $error_panel = null;
if ($is_foreign) {
$subpath = $commit_data->getCommitDetail('svn-subpath');
$error_panel = new PHUIInfoView();
$error_panel->setTitle(pht('Commit Not Tracked'));
$error_panel->setSeverity(PHUIInfoView::SEVERITY_WARNING);
$error_panel->appendChild(
pht(
"This Diffusion repository is configured to track only one ".
"subdirectory of the entire Subversion repository, and this commit ".
"didn't affect the tracked subdirectory ('%s'), so no ".
"information is available.",
$subpath));
- $content[] = $error_panel;
} else {
$engine = PhabricatorMarkupEngine::newDifferentialMarkupEngine();
- $engine->setConfig('viewer', $user);
+ $engine->setConfig('viewer', $viewer);
- $headsup_view = id(new PHUIHeaderView())
+ $commit_tag = $this->renderCommitHashTag($drequest);
+ $header = id(new PHUIHeaderView())
->setHeader(nonempty($commit->getSummary(), pht('Commit Detail')))
- ->setSubheader(pht('Commit: %s', $commit->getCommitIdentifier()));
-
- $headsup_actions = $this->renderHeadsupActionList($commit, $repository);
+ ->setHeaderIcon('fa-code-fork')
+ ->addTag($commit_tag);
+
+ if ($commit->getAuditStatus()) {
+ $icon = PhabricatorAuditCommitStatusConstants::getStatusIcon(
+ $commit->getAuditStatus());
+ $color = PhabricatorAuditCommitStatusConstants::getStatusColor(
+ $commit->getAuditStatus());
+ $status = PhabricatorAuditCommitStatusConstants::getStatusName(
+ $commit->getAuditStatus());
+
+ $header->setStatus($icon, $color, $status);
+ }
- $commit_properties = $this->loadCommitProperties(
+ $curtain = $this->buildCurtain($commit, $repository);
+ $subheader = $this->buildSubheaderView($commit, $commit_data);
+ $details = $this->buildPropertyListView(
$commit,
$commit_data,
$audit_requests);
- $property_list = id(new PHUIPropertyListView())
- ->setHasKeyboardShortcuts(true)
- ->setUser($user)
- ->setObject($commit);
- foreach ($commit_properties as $key => $value) {
- $property_list->addProperty($key, $value);
- }
$message = $commit_data->getCommitMessage();
$revision = $commit->getCommitIdentifier();
$message = $this->linkBugtraq($message);
-
$message = $engine->markupText($message);
- $property_list->invokeWillRenderEvent();
- $property_list->setActionList($headsup_actions);
-
$detail_list = new PHUIPropertyListView();
- $detail_list->addSectionHeader(
- pht('Description'),
- PHUIPropertyListView::ICON_SUMMARY);
$detail_list->addTextContent(
phutil_tag(
'div',
array(
'class' => 'diffusion-commit-message phabricator-remarkup',
),
$message));
- $headsup_view->setTall(true);
-
- $object_box = id(new PHUIObjectBoxView())
- ->setHeader($headsup_view)
- ->setFormErrors($this->getCommitErrors())
- ->addPropertyList($property_list)
- ->addPropertyList($detail_list);
-
- $content[] = $object_box;
+ if ($this->getCommitErrors()) {
+ $error_panel = id(new PHUIInfoView())
+ ->appendChild($this->getCommitErrors())
+ ->setSeverity(PHUIInfoView::SEVERITY_WARNING);
+ }
}
- $content[] = $this->buildComments($commit);
-
+ $timeline = $this->buildComments($commit);
$hard_limit = 1000;
if ($commit->isImported()) {
$change_query = DiffusionPathChangeQuery::newFromDiffusionRequest(
$drequest);
$change_query->setLimit($hard_limit + 1);
$changes = $change_query->loadChanges();
} else {
$changes = array();
}
$was_limited = (count($changes) > $hard_limit);
if ($was_limited) {
$changes = array_slice($changes, 0, $hard_limit);
}
- $content[] = $this->buildMergesTable($commit);
+ $merge_table = $this->buildMergesTable($commit);
$highlighted_audits = $commit->getAuthorityAudits(
- $user,
+ $viewer,
$this->auditAuthorityPHIDs);
$count = count($changes);
$bad_commit = null;
if ($count == 0) {
$bad_commit = queryfx_one(
id(new PhabricatorRepository())->establishConnection('r'),
'SELECT * FROM %T WHERE fullCommitName = %s',
PhabricatorRepository::TABLE_BADCOMMIT,
$commit->getMonogram());
}
$show_changesets = false;
+ $info_panel = null;
+ $change_list = null;
+ $change_table = null;
if ($bad_commit) {
- $content[] = $this->renderStatusMessage(
+ $info_panel = $this->renderStatusMessage(
pht('Bad Commit'),
$bad_commit['description']);
} else if ($is_foreign) {
// Don't render anything else.
} else if (!$commit->isImported()) {
- $content[] = $this->renderStatusMessage(
+ $info_panel = $this->renderStatusMessage(
pht('Still Importing...'),
pht(
'This commit is still importing. Changes will be visible once '.
'the import finishes.'));
} else if (!count($changes)) {
- $content[] = $this->renderStatusMessage(
+ $info_panel = $this->renderStatusMessage(
pht('Empty Commit'),
pht(
'This commit is empty and does not affect any paths.'));
} else if ($was_limited) {
- $content[] = $this->renderStatusMessage(
+ $info_panel = $this->renderStatusMessage(
pht('Enormous Commit'),
pht(
'This commit is enormous, and affects more than %d files. '.
'Changes are not shown.',
$hard_limit));
} else if (!$this->getCommitExists()) {
- $content[] = $this->renderStatusMessage(
+ $info_panel = $this->renderStatusMessage(
pht('Commit No Longer Exists'),
pht('This commit no longer exists in the repository.'));
} else {
$show_changesets = true;
// The user has clicked "Show All Changes", and we should show all the
// changes inline even if there are more than the soft limit.
$show_all_details = $request->getBool('show_all');
- $header = id(new PHUIHeaderView())
+ $change_header = id(new PHUIHeaderView())
->setHeader(pht('Changes (%s)', new PhutilNumber($count)));
$warning_view = null;
if ($count > self::CHANGES_LIMIT && !$show_all_details) {
$button = id(new PHUIButtonView())
->setText(pht('Show All Changes'))
->setHref('?show_all=true')
->setTag('a')
->setIcon('fa-files-o');
$warning_view = id(new PHUIInfoView())
->setSeverity(PHUIInfoView::SEVERITY_WARNING)
->setTitle(pht('Very Large Commit'))
- ->addButton($button)
->appendChild(
pht('This commit is very large. Load each file individually.'));
+
+ $change_header->addActionLink($button);
}
$changesets = DiffusionPathChange::convertToDifferentialChangesets(
- $user,
+ $viewer,
$changes);
// TODO: This table and panel shouldn't really be separate, but we need
// to clean up the "Load All Files" interaction first.
$change_table = $this->buildTableOfContents(
$changesets,
- $header,
+ $change_header,
$warning_view);
- $content[] = $change_table;
-
$vcs = $repository->getVersionControlSystem();
switch ($vcs) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
$vcs_supports_directory_changes = true;
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
$vcs_supports_directory_changes = false;
break;
default:
throw new Exception(pht('Unknown VCS.'));
}
$references = array();
foreach ($changesets as $key => $changeset) {
$file_type = $changeset->getFileType();
if ($file_type == DifferentialChangeType::FILE_DIRECTORY) {
if (!$vcs_supports_directory_changes) {
unset($changesets[$key]);
continue;
}
}
$references[$key] = $drequest->generateURI(
array(
'action' => 'rendering-ref',
'path' => $changeset->getFilename(),
));
}
// TODO: Some parts of the views still rely on properties of the
// DifferentialChangeset. Make the objects ephemeral to make sure we don't
// accidentally save them, and then set their ID to the appropriate ID for
// this application (the path IDs).
$path_ids = array_flip(mpull($changes, 'getPath'));
foreach ($changesets as $changeset) {
$changeset->makeEphemeral();
$changeset->setID($path_ids[$changeset->getFilename()]);
}
if ($count <= self::CHANGES_LIMIT || $show_all_details) {
$visible_changesets = $changesets;
} else {
$visible_changesets = array();
$inlines = PhabricatorAuditInlineComment::loadDraftAndPublishedComments(
- $user,
+ $viewer,
$commit->getPHID());
$path_ids = mpull($inlines, null, 'getPathID');
foreach ($changesets as $key => $changeset) {
if (array_key_exists($changeset->getID(), $path_ids)) {
$visible_changesets[$key] = $changeset;
}
}
}
$change_list_title = $commit->getDisplayName();
$change_list = new DifferentialChangesetListView();
$change_list->setTitle($change_list_title);
$change_list->setChangesets($changesets);
$change_list->setVisibleChangesets($visible_changesets);
$change_list->setRenderingReferences($references);
- $change_list->setRenderURI(
- $repository->getPathURI('diff/'));
+ $change_list->setRenderURI($repository->getPathURI('diff/'));
$change_list->setRepository($repository);
- $change_list->setUser($user);
+ $change_list->setUser($viewer);
+ $change_list->setBackground(PHUIObjectBoxView::BLUE_PROPERTY);
// TODO: Try to setBranch() to something reasonable here?
$change_list->setStandaloneURI(
$repository->getPathURI('diff/'));
$change_list->setRawFileURIs(
// TODO: Implement this, somewhat tricky if there's an octopus merge
// or whatever?
null,
$repository->getPathURI('diff/?view=r'));
$change_list->setInlineCommentControllerURI(
'/diffusion/inline/edit/'.phutil_escape_uri($commit->getPHID()).'/');
- $content[] = $change_list->render();
}
- $content[] = $this->renderAddCommentPanel($commit, $audit_requests);
+ $add_comment = $this->renderAddCommentPanel($commit, $audit_requests);
- $prefs = $user->loadPreferences();
+ $prefs = $viewer->loadPreferences();
$pref_filetree = PhabricatorUserPreferences::PREFERENCE_DIFF_FILETREE;
$pref_collapse = PhabricatorUserPreferences::PREFERENCE_NAV_COLLAPSED;
$show_filetree = $prefs->getPreference($pref_filetree);
$collapsed = $prefs->getPreference($pref_collapse);
+ $nav = null;
if ($show_changesets && $show_filetree) {
$nav = id(new DifferentialChangesetFileTreeSideNavBuilder())
->setTitle($commit->getDisplayName())
->setBaseURI(new PhutilURI($commit->getURI()))
->build($changesets)
->setCrumbs($crumbs)
- ->setCollapsed((bool)$collapsed)
- ->appendChild($content);
- $content = $nav;
- } else {
- $content = array($crumbs, $content);
+ ->setCollapsed((bool)$collapsed);
}
- return $this->buildApplicationPage(
- $content,
- array(
- 'title' => $commit->getDisplayName(),
- 'pageObjects' => array($commit->getPHID()),
+ $view = id(new PHUITwoColumnView())
+ ->setHeader($header)
+ ->setSubheader($subheader)
+ ->setMainColumn(array(
+ $error_panel,
+ $timeline,
+ $merge_table,
+ $info_panel,
+ ))
+ ->setFooter(array(
+ $change_table,
+ $change_list,
+ $add_comment,
+ ))
+ ->addPropertySection(pht('DESCRIPTION'), $detail_list)
+ ->addPropertySection(pht('DETAILS'), $details)
+ ->setCurtain($curtain);
+
+ $page = $this->newPage()
+ ->setTitle($commit->getDisplayName())
+ ->setCrumbs($crumbs)
+ ->setPageObjectPHIDS(array($commit->getPHID()))
+ ->appendChild(
+ array(
+ $view,
));
+
+ if ($nav) {
+ $page->setNavigation($nav);
+ }
+
+ return $page;
+
}
- private function loadCommitProperties(
+ private function buildPropertyListView(
PhabricatorRepositoryCommit $commit,
PhabricatorRepositoryCommitData $data,
array $audit_requests) {
- $viewer = $this->getRequest()->getUser();
+ $viewer = $this->getViewer();
$commit_phid = $commit->getPHID();
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
+ $view = id(new PHUIPropertyListView())
+ ->setUser($this->getRequest()->getUser());
+
$edge_query = id(new PhabricatorEdgeQuery())
->withSourcePHIDs(array($commit_phid))
->withEdgeTypes(array(
DiffusionCommitHasTaskEdgeType::EDGECONST,
DiffusionCommitHasRevisionEdgeType::EDGECONST,
DiffusionCommitRevertsCommitEdgeType::EDGECONST,
DiffusionCommitRevertedByCommitEdgeType::EDGECONST,
));
$edges = $edge_query->execute();
$task_phids = array_keys(
$edges[$commit_phid][DiffusionCommitHasTaskEdgeType::EDGECONST]);
$revision_phid = key(
$edges[$commit_phid][DiffusionCommitHasRevisionEdgeType::EDGECONST]);
$reverts_phids = array_keys(
$edges[$commit_phid][DiffusionCommitRevertsCommitEdgeType::EDGECONST]);
$reverted_by_phids = array_keys(
$edges[$commit_phid][DiffusionCommitRevertedByCommitEdgeType::EDGECONST]);
$phids = $edge_query->getDestinationPHIDs(array($commit_phid));
if ($data->getCommitDetail('authorPHID')) {
$phids[] = $data->getCommitDetail('authorPHID');
}
if ($data->getCommitDetail('reviewerPHID')) {
$phids[] = $data->getCommitDetail('reviewerPHID');
}
if ($data->getCommitDetail('committerPHID')) {
$phids[] = $data->getCommitDetail('committerPHID');
}
// NOTE: We should never normally have more than a single push log, but
// it can occur naturally if a commit is pushed, then the branch it was
// on is deleted, then the commit is pushed again (or through other similar
// chains of events). This should be rare, but does not indicate a bug
// or data issue.
// NOTE: We never query push logs in SVN because the commiter is always
// the pusher and the commit time is always the push time; the push log
// is redundant and we save a query by skipping it.
$push_logs = array();
if ($repository->isHosted() && !$repository->isSVN()) {
$push_logs = id(new PhabricatorRepositoryPushLogQuery())
->setViewer($viewer)
->withRepositoryPHIDs(array($repository->getPHID()))
->withNewRefs(array($commit->getCommitIdentifier()))
->withRefTypes(array(PhabricatorRepositoryPushLog::REFTYPE_COMMIT))
->execute();
foreach ($push_logs as $log) {
$phids[] = $log->getPusherPHID();
}
}
$handles = array();
if ($phids) {
$handles = $this->loadViewerHandles($phids);
}
$props = array();
- if ($commit->getAuditStatus()) {
- $status = PhabricatorAuditCommitStatusConstants::getStatusName(
- $commit->getAuditStatus());
- $tag = id(new PHUITagView())
- ->setType(PHUITagView::TYPE_STATE)
- ->setName($status);
-
- switch ($commit->getAuditStatus()) {
- case PhabricatorAuditCommitStatusConstants::NEEDS_AUDIT:
- $tag->setBackgroundColor(PHUITagView::COLOR_ORANGE);
- break;
- case PhabricatorAuditCommitStatusConstants::CONCERN_RAISED:
- $tag->setBackgroundColor(PHUITagView::COLOR_RED);
- break;
- case PhabricatorAuditCommitStatusConstants::PARTIALLY_AUDITED:
- $tag->setBackgroundColor(PHUITagView::COLOR_BLUE);
- break;
- case PhabricatorAuditCommitStatusConstants::FULLY_AUDITED:
- $tag->setBackgroundColor(PHUITagView::COLOR_GREEN);
- break;
- }
-
- $props['Status'] = $tag;
- }
-
if ($audit_requests) {
$user_requests = array();
$other_requests = array();
foreach ($audit_requests as $audit_request) {
if ($audit_request->isUser()) {
$user_requests[] = $audit_request;
} else {
$other_requests[] = $audit_request;
}
}
if ($user_requests) {
- $props['Auditors'] = $this->renderAuditStatusView(
- $user_requests);
+ $view->addProperty(
+ pht('Auditors'),
+ $this->renderAuditStatusView($user_requests));
}
if ($other_requests) {
- $props['Project/Package Auditors'] = $this->renderAuditStatusView(
- $other_requests);
+ $view->addProperty(
+ pht('Project/Package Auditors'),
+ $this->renderAuditStatusView($other_requests));
}
}
$author_phid = $data->getCommitDetail('authorPHID');
$author_name = $data->getAuthorName();
-
- if (!$repository->isSVN()) {
- $authored_info = id(new PHUIStatusItemView());
-
- $author_epoch = $data->getCommitDetail('authorEpoch');
- if ($author_epoch !== null) {
- $authored_info->setNote(
- phabricator_datetime($author_epoch, $viewer));
- }
-
- if ($author_phid) {
- $authored_info->setTarget($handles[$author_phid]->renderLink());
- } else if (strlen($author_name)) {
- $authored_info->setTarget($author_name);
- }
-
- $props['Authored'] = id(new PHUIStatusListView())
- ->addItem($authored_info);
- }
+ $author_epoch = $data->getCommitDetail('authorEpoch');
$committed_info = id(new PHUIStatusItemView())
->setNote(phabricator_datetime($commit->getEpoch(), $viewer));
$committer_phid = $data->getCommitDetail('committerPHID');
$committer_name = $data->getCommitDetail('committer');
if ($committer_phid) {
$committed_info->setTarget($handles[$committer_phid]->renderLink());
} else if (strlen($committer_name)) {
$committed_info->setTarget($committer_name);
} else if ($author_phid) {
$committed_info->setTarget($handles[$author_phid]->renderLink());
} else if (strlen($author_name)) {
$committed_info->setTarget($author_name);
}
- $props['Committed'] = id(new PHUIStatusListView())
- ->addItem($committed_info);
+ $view->addProperty(
+ pht('Committed'),
+ $committed_info);
if ($push_logs) {
$pushed_list = new PHUIStatusListView();
foreach ($push_logs as $push_log) {
$pushed_item = id(new PHUIStatusItemView())
->setTarget($handles[$push_log->getPusherPHID()]->renderLink())
->setNote(phabricator_datetime($push_log->getEpoch(), $viewer));
$pushed_list->addItem($pushed_item);
}
- $props['Pushed'] = $pushed_list;
+ $view->addProperty(
+ pht('Pushed'),
+ $pushed_list);
}
$reviewer_phid = $data->getCommitDetail('reviewerPHID');
if ($reviewer_phid) {
- $props['Reviewer'] = $handles[$reviewer_phid]->renderLink();
+ $view->addProperty(
+ pht('Reviewer'),
+ $handles[$reviewer_phid]->renderLink());
}
if ($revision_phid) {
- $props['Differential Revision'] = $handles[$revision_phid]->renderLink();
+ $view->addProperty(
+ pht('Differential Revision'),
+ $handles[$revision_phid]->renderLink());
}
$parents = $this->getCommitParents();
if ($parents) {
- $props['Parents'] = $viewer->renderHandleList(mpull($parents, 'getPHID'));
+ $view->addProperty(
+ pht('Parents'),
+ $viewer->renderHandleList(mpull($parents, 'getPHID')));
}
if ($this->getCommitExists()) {
- $props['Branches'] = phutil_tag(
+ $view->addProperty(
+ pht('Branches'),
+ phutil_tag(
'span',
array(
'id' => 'commit-branches',
),
- pht('Unknown'));
- $props['Tags'] = phutil_tag(
+ pht('Unknown')));
+
+ $view->addProperty(
+ pht('Tags'),
+ phutil_tag(
'span',
array(
'id' => 'commit-tags',
),
- pht('Unknown'));
+ pht('Unknown')));
$identifier = $commit->getCommitIdentifier();
$root = $repository->getPathURI("commit/{$identifier}");
Javelin::initBehavior(
'diffusion-commit-branches',
array(
$root.'/branches/' => 'commit-branches',
$root.'/tags/' => 'commit-tags',
));
}
$refs = $this->getCommitRefs();
if ($refs) {
$ref_links = array();
foreach ($refs as $ref_data) {
$ref_links[] = phutil_tag(
'a',
array(
'href' => $ref_data['href'],
),
$ref_data['ref']);
}
- $props['References'] = phutil_implode_html(', ', $ref_links);
+ $view->addProperty(
+ pht('References'),
+ phutil_implode_html(', ', $ref_links));
}
if ($reverts_phids) {
- $props[pht('Reverts')] = $viewer->renderHandleList($reverts_phids);
+ $view->addProperty(
+ pht('Reverts'),
+ $viewer->renderHandleList($reverts_phids));
}
if ($reverted_by_phids) {
- $props[pht('Reverted By')] = $viewer->renderHandleList(
- $reverted_by_phids);
+ $view->addProperty(
+ pht('Reverted By'),
+ $viewer->renderHandleList($reverted_by_phids));
}
if ($task_phids) {
$task_list = array();
foreach ($task_phids as $phid) {
$task_list[] = $handles[$phid]->renderLink();
}
$task_list = phutil_implode_html(phutil_tag('br'), $task_list);
- $props['Tasks'] = $task_list;
+ $view->addProperty(
+ pht('Tasks'),
+ $task_list);
}
- return $props;
+ return $view;
}
+ private function buildSubheaderView(
+ PhabricatorRepositoryCommit $commit,
+ PhabricatorRepositoryCommitData $data) {
+
+ $viewer = $this->getViewer();
+ $drequest = $this->getDiffusionRequest();
+ $repository = $drequest->getRepository();
+
+ if ($repository->isSVN()) {
+ return null;
+ }
+
+ $author_phid = $data->getCommitDetail('authorPHID');
+ $author_name = $data->getAuthorName();
+ $author_epoch = $data->getCommitDetail('authorEpoch');
+ $date = null;
+ if ($author_epoch !== null) {
+ $date = phabricator_datetime($author_epoch, $viewer);
+ }
+
+ if ($author_phid) {
+ $handles = $viewer->loadHandles(array($author_phid));
+ $image_uri = $handles[$author_phid]->getImageURI();
+ $image_href = $handles[$author_phid]->getURI();
+ $author = $handles[$author_phid]->renderLink();
+ } else if (strlen($author_name)) {
+ $author = $author_name;
+ $image_uri = null;
+ $image_href = null;
+ }
+
+ $author = phutil_tag('strong', array(), $author);
+ if ($date) {
+ $content = pht('Authored by %s on %s.', $author, $date);
+ } else {
+ $content = pht('Authored by %s.', $author);
+ }
+
+ return id(new PHUIHeadThingView())
+ ->setImage($image_uri)
+ ->setImageHref($image_href)
+ ->setContent($content);
+
+ }
+
+
private function buildComments(PhabricatorRepositoryCommit $commit) {
$timeline = $this->buildTransactionTimeline(
$commit,
new PhabricatorAuditTransactionQuery());
$commit->willRenderTimeline($timeline, $this->getRequest());
return $timeline;
}
private function renderAddCommentPanel(
PhabricatorRepositoryCommit $commit,
array $audit_requests) {
assert_instances_of($audit_requests, 'PhabricatorRepositoryAuditRequest');
$request = $this->getRequest();
- $user = $request->getUser();
+ $viewer = $request->getUser();
- if (!$user->isLoggedIn()) {
+ if (!$viewer->isLoggedIn()) {
return id(new PhabricatorApplicationTransactionCommentView())
- ->setUser($user)
+ ->setUser($viewer)
->setRequestURI($request->getRequestURI());
}
$is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business');
$pane_id = celerity_generate_unique_node_id();
Javelin::initBehavior(
'differential-keyboard-navigation',
array(
'haunt' => $pane_id,
));
$draft = id(new PhabricatorDraft())->loadOneWhere(
'authorPHID = %s AND draftKey = %s',
- $user->getPHID(),
+ $viewer->getPHID(),
'diffusion-audit-'.$commit->getID());
if ($draft) {
$draft = $draft->getDraft();
} else {
$draft = null;
}
$actions = $this->getAuditActions($commit, $audit_requests);
$mailable_source = new PhabricatorMetaMTAMailableDatasource();
$auditor_source = new DiffusionAuditorDatasource();
$form = id(new AphrontFormView())
- ->setUser($user)
+ ->setUser($viewer)
->setAction('/audit/addcomment/')
->addHiddenInput('commit', $commit->getPHID())
->appendChild(
id(new AphrontFormSelectControl())
->setLabel(pht('Action'))
->setName('action')
->setID('audit-action')
->setOptions($actions))
->appendControl(
id(new AphrontFormTokenizerControl())
->setLabel(pht('Add Auditors'))
->setName('auditors')
->setControlID('add-auditors')
->setControlStyle('display: none')
->setID('add-auditors-tokenizer')
->setDisableBehavior(true)
->setDatasource($auditor_source))
->appendControl(
id(new AphrontFormTokenizerControl())
->setLabel(pht('Add CCs'))
->setName('ccs')
->setControlID('add-ccs')
->setControlStyle('display: none')
->setID('add-ccs-tokenizer')
->setDisableBehavior(true)
->setDatasource($mailable_source))
->appendChild(
id(new PhabricatorRemarkupControl())
->setLabel(pht('Comments'))
->setName('content')
->setValue($draft)
->setID('audit-content')
- ->setUser($user))
+ ->setUser($viewer))
->appendChild(
id(new AphrontFormSubmitControl())
->setValue(pht('Submit')));
$header = new PHUIHeaderView();
$header->setHeader(
$is_serious ? pht('Audit Commit') : pht('Creative Accounting'));
Javelin::initBehavior(
'differential-add-reviewers-and-ccs',
array(
'dynamic' => array(
'add-auditors-tokenizer' => array(
'actions' => array('add_auditors' => 1),
'src' => $auditor_source->getDatasourceURI(),
'row' => 'add-auditors',
'placeholder' => $auditor_source->getPlaceholderText(),
),
'add-ccs-tokenizer' => array(
'actions' => array('add_ccs' => 1),
'src' => $mailable_source->getDatasourceURI(),
'row' => 'add-ccs',
'placeholder' => $mailable_source->getPlaceholderText(),
),
),
'select' => 'audit-action',
));
Javelin::initBehavior('differential-feedback-preview', array(
'uri' => '/audit/preview/'.$commit->getID().'/',
'preview' => 'audit-preview',
'content' => 'audit-content',
'action' => 'audit-action',
'previewTokenizers' => array(
'auditors' => 'add-auditors-tokenizer',
'ccs' => 'add-ccs-tokenizer',
),
'inline' => 'inline-comment-preview',
'inlineuri' => '/diffusion/inline/preview/'.$commit->getPHID().'/',
));
$loading = phutil_tag_div(
'aphront-panel-preview-loading-text',
pht('Loading preview...'));
$preview_panel = phutil_tag_div(
'aphront-panel-preview aphront-panel-flush',
array(
phutil_tag('div', array('id' => 'audit-preview'), $loading),
phutil_tag('div', array('id' => 'inline-comment-preview')),
));
// TODO: This is pretty awkward, unify the CSS between Diffusion and
// Differential better.
require_celerity_resource('differential-core-view-css');
$anchor = id(new PhabricatorAnchorView())
->setAnchorName('comment')
->setNavigationMarker(true)
->render();
$comment_box = id(new PHUIObjectBoxView())
->setHeader($header)
->appendChild($form);
return phutil_tag(
'div',
array(
'id' => $pane_id,
),
phutil_tag_div(
'differential-add-comment-panel',
array($anchor, $comment_box, $preview_panel)));
}
/**
* Return a map of available audit actions for rendering into a <select />.
* This shows the user valid actions, and does not show nonsense/invalid
* actions (like closing an already-closed commit, or resigning from a commit
* you have no association with).
*/
private function getAuditActions(
PhabricatorRepositoryCommit $commit,
array $audit_requests) {
assert_instances_of($audit_requests, 'PhabricatorRepositoryAuditRequest');
- $user = $this->getRequest()->getUser();
+ $viewer = $this->getViewer();
- $user_is_author = ($commit->getAuthorPHID() == $user->getPHID());
+ $user_is_author = ($commit->getAuthorPHID() == $viewer->getPHID());
$user_request = null;
foreach ($audit_requests as $audit_request) {
- if ($audit_request->getAuditorPHID() == $user->getPHID()) {
+ if ($audit_request->getAuditorPHID() == $viewer->getPHID()) {
$user_request = $audit_request;
break;
}
}
$actions = array();
$actions[PhabricatorAuditActionConstants::COMMENT] = true;
// We allow you to accept your own commits. A use case here is that you
// notice an issue with your own commit and "Raise Concern" as an indicator
// to other auditors that you're on top of the issue, then later resolve it
// and "Accept". You can not accept on behalf of projects or packages,
// however.
$actions[PhabricatorAuditActionConstants::ACCEPT] = true;
$actions[PhabricatorAuditActionConstants::CONCERN] = true;
// To resign, a user must have authority on some request and not be the
// commit's author.
if (!$user_is_author) {
$may_resign = false;
$authority_map = array_fill_keys($this->auditAuthorityPHIDs, true);
foreach ($audit_requests as $request) {
if (empty($authority_map[$request->getAuditorPHID()])) {
continue;
}
$may_resign = true;
break;
}
// If the user has already resigned, don't show "Resign...".
$status_resigned = PhabricatorAuditStatusConstants::RESIGNED;
if ($user_request) {
if ($user_request->getAuditStatus() == $status_resigned) {
$may_resign = false;
}
}
if ($may_resign) {
$actions[PhabricatorAuditActionConstants::RESIGN] = true;
}
}
$status_concern = PhabricatorAuditCommitStatusConstants::CONCERN_RAISED;
$concern_raised = ($commit->getAuditStatus() == $status_concern);
$can_close_option = PhabricatorEnv::getEnvConfig(
'audit.can-author-close-audit');
if ($can_close_option && $user_is_author && $concern_raised) {
$actions[PhabricatorAuditActionConstants::CLOSE] = true;
}
$actions[PhabricatorAuditActionConstants::ADD_AUDITORS] = true;
$actions[PhabricatorAuditActionConstants::ADD_CCS] = true;
foreach ($actions as $constant => $ignored) {
$actions[$constant] =
PhabricatorAuditActionConstants::getActionName($constant);
}
return $actions;
}
private function buildMergesTable(PhabricatorRepositoryCommit $commit) {
$viewer = $this->getViewer();
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$merges = $this->getCommitMerges();
if (!$merges) {
return null;
}
$limit = $this->getMergeDisplayLimit();
$caption = null;
if (count($merges) > $limit) {
$merges = array_slice($merges, 0, $limit);
$caption = new PHUIInfoView();
$caption->setSeverity(PHUIInfoView::SEVERITY_NOTICE);
$caption->appendChild(
pht(
'This commit merges a very large number of changes. '.
'Only the first %s are shown.',
new PhutilNumber($limit)));
}
$history_table = id(new DiffusionHistoryTableView())
->setUser($viewer)
->setDiffusionRequest($drequest)
->setHistory($merges);
$history_table->loadRevisions();
- $panel = new PHUIObjectBoxView();
- $panel->setHeaderText(pht('Merged Changes'));
- $panel->setTable($history_table);
+ $panel = id(new PHUIObjectBoxView())
+ ->setHeaderText(pht('Merged Changes'))
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
+ ->setTable($history_table);
if ($caption) {
$panel->setInfoView($caption);
}
return $panel;
}
- private function renderHeadsupActionList(
+ private function buildCurtain(
PhabricatorRepositoryCommit $commit,
PhabricatorRepository $repository) {
$request = $this->getRequest();
- $user = $request->getUser();
-
- $actions = id(new PhabricatorActionListView())
- ->setUser($user)
- ->setObject($commit);
+ $viewer = $this->getViewer();
+ $curtain = $this->newCurtainView($commit);
$can_edit = PhabricatorPolicyFilter::hasCapability(
- $user,
+ $viewer,
$commit,
PhabricatorPolicyCapability::CAN_EDIT);
$identifier = $commit->getCommitIdentifier();
$uri = $repository->getPathURI("commit/{$identifier}/edit/");
$action = id(new PhabricatorActionView())
->setName(pht('Edit Commit'))
->setHref($uri)
->setIcon('fa-pencil')
->setDisabled(!$can_edit)
->setWorkflow(!$can_edit);
- $actions->addAction($action);
+ $curtain->addAction($action);
require_celerity_resource('phabricator-object-selector-css');
require_celerity_resource('javelin-behavior-phabricator-object-selector');
$maniphest = 'PhabricatorManiphestApplication';
if (PhabricatorApplication::isClassInstalled($maniphest)) {
$action = id(new PhabricatorActionView())
->setName(pht('Edit Maniphest Tasks'))
->setIcon('fa-anchor')
->setHref('/search/attach/'.$commit->getPHID().'/TASK/edge/')
->setWorkflow(true)
->setDisabled(!$can_edit);
- $actions->addAction($action);
+ $curtain->addAction($action);
}
$action = id(new PhabricatorActionView())
->setName(pht('Download Raw Diff'))
->setHref($request->getRequestURI()->alter('diff', true))
->setIcon('fa-download');
- $actions->addAction($action);
+ $curtain->addAction($action);
- return $actions;
+ return $curtain;
}
private function buildRawDiffResponse(DiffusionRequest $drequest) {
$raw_diff = $this->callConduitWithDiffusionRequest(
'diffusion.rawdiffquery',
array(
'commit' => $drequest->getCommit(),
'path' => $drequest->getPath(),
));
$file = PhabricatorFile::buildFromFileDataOrHash(
$raw_diff,
array(
'name' => $drequest->getCommit().'.diff',
'ttl' => (60 * 60 * 24),
'viewPolicy' => PhabricatorPolicies::POLICY_NOONE,
));
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
$file->attachToObject($drequest->getRepository()->getPHID());
unset($unguarded);
return $file->getRedirectResponse();
}
private function renderAuditStatusView(array $audit_requests) {
assert_instances_of($audit_requests, 'PhabricatorRepositoryAuditRequest');
$viewer = $this->getViewer();
$authority_map = array_fill_keys($this->auditAuthorityPHIDs, true);
$view = new PHUIStatusListView();
foreach ($audit_requests as $request) {
$code = $request->getAuditStatus();
$item = new PHUIStatusItemView();
$item->setIcon(
PhabricatorAuditStatusConstants::getStatusIcon($code),
PhabricatorAuditStatusConstants::getStatusColor($code),
PhabricatorAuditStatusConstants::getStatusName($code));
$note = array();
foreach ($request->getAuditReasons() as $reason) {
$note[] = phutil_tag('div', array(), $reason);
}
$item->setNote($note);
$auditor_phid = $request->getAuditorPHID();
$target = $viewer->renderHandle($auditor_phid);
$item->setTarget($target);
if (isset($authority_map[$auditor_phid])) {
$item->setHighlighted(true);
}
$view->addItem($item);
}
return $view;
}
private function linkBugtraq($corpus) {
$url = PhabricatorEnv::getEnvConfig('bugtraq.url');
if (!strlen($url)) {
return $corpus;
}
$regexes = PhabricatorEnv::getEnvConfig('bugtraq.logregex');
if (!$regexes) {
return $corpus;
}
$parser = id(new PhutilBugtraqParser())
->setBugtraqPattern("[[ {$url} | %BUGID% ]]")
->setBugtraqCaptureExpression(array_shift($regexes));
$select = array_shift($regexes);
if ($select) {
$parser->setBugtraqSelectExpression($select);
}
return $parser->processCorpus($corpus);
}
private function buildTableOfContents(
array $changesets,
$header,
$info_view) {
$drequest = $this->getDiffusionRequest();
$viewer = $this->getViewer();
$toc_view = id(new PHUIDiffTableOfContentsListView())
->setUser($viewer)
- ->setHeader($header);
+ ->setHeader($header)
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY);
if ($info_view) {
$toc_view->setInfoView($info_view);
}
// TODO: This is hacky, we just want access to the linkX() methods on
// DiffusionView.
$diffusion_view = id(new DiffusionEmptyResultView())
->setDiffusionRequest($drequest);
$have_owners = PhabricatorApplication::isClassInstalledForViewer(
'PhabricatorOwnersApplication',
$viewer);
if (!$changesets) {
$have_owners = false;
}
if ($have_owners) {
if ($viewer->getPHID()) {
$packages = id(new PhabricatorOwnersPackageQuery())
->setViewer($viewer)
->withStatuses(array(PhabricatorOwnersPackage::STATUS_ACTIVE))
->withAuthorityPHIDs(array($viewer->getPHID()))
->execute();
$toc_view->setAuthorityPackages($packages);
}
$repository = $drequest->getRepository();
$repository_phid = $repository->getPHID();
$control_query = id(new PhabricatorOwnersPackageQuery())
->setViewer($viewer)
->withStatuses(array(PhabricatorOwnersPackage::STATUS_ACTIVE))
->withControl($repository_phid, mpull($changesets, 'getFilename'));
$control_query->execute();
}
foreach ($changesets as $changeset_id => $changeset) {
$path = $changeset->getFilename();
$anchor = substr(md5($path), 0, 8);
$history_link = $diffusion_view->linkHistory($path);
$browse_link = $diffusion_view->linkBrowse(
$path,
array(
'type' => $changeset->getFileType(),
));
$item = id(new PHUIDiffTableOfContentsItemView())
->setChangeset($changeset)
->setAnchor($anchor)
->setContext(
array(
$history_link,
' ',
$browse_link,
));
if ($have_owners) {
$packages = $control_query->getControllingPackagesForPath(
$repository_phid,
$changeset->getFilename());
$item->setPackages($packages);
}
$toc_view->addItem($item);
}
return $toc_view;
}
private function loadCommitState() {
$viewer = $this->getViewer();
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$commit = $drequest->getCommit();
// TODO: We could use futures here and resolve these calls in parallel.
$exceptions = array();
try {
$parent_refs = $this->callConduitWithDiffusionRequest(
'diffusion.commitparentsquery',
array(
'commit' => $commit,
));
if ($parent_refs) {
$parents = id(new DiffusionCommitQuery())
->setViewer($viewer)
->withRepository($repository)
->withIdentifiers($parent_refs)
->execute();
} else {
$parents = array();
}
$this->commitParents = $parents;
} catch (Exception $ex) {
$this->commitParents = false;
$exceptions[] = $ex;
}
$merge_limit = $this->getMergeDisplayLimit();
try {
if ($repository->isSVN()) {
$this->commitMerges = array();
} else {
$merges = $this->callConduitWithDiffusionRequest(
'diffusion.mergedcommitsquery',
array(
'commit' => $commit,
'limit' => $merge_limit + 1,
));
$this->commitMerges = DiffusionPathChange::newFromConduit($merges);
}
} catch (Exception $ex) {
$this->commitMerges = false;
$exceptions[] = $ex;
}
try {
if ($repository->isGit()) {
$refs = $this->callConduitWithDiffusionRequest(
'diffusion.refsquery',
array(
'commit' => $commit,
));
} else {
$refs = array();
}
$this->commitRefs = $refs;
} catch (Exception $ex) {
$this->commitRefs = false;
$exceptions[] = $ex;
}
if ($exceptions) {
$exists = $this->callConduitWithDiffusionRequest(
'diffusion.existsquery',
array(
'commit' => $commit,
));
if ($exists) {
$this->commitExists = true;
foreach ($exceptions as $exception) {
$this->commitErrors[] = $exception->getMessage();
}
} else {
$this->commitExists = false;
$this->commitErrors[] = pht(
'This commit no longer exists in the repository. It may have '.
'been part of a branch which was deleted.');
}
} else {
$this->commitExists = true;
$this->commitErrors = array();
}
}
private function getMergeDisplayLimit() {
return 50;
}
private function getCommitExists() {
if ($this->commitExists === null) {
$this->loadCommitState();
}
return $this->commitExists;
}
private function getCommitParents() {
if ($this->commitParents === null) {
$this->loadCommitState();
}
return $this->commitParents;
}
private function getCommitRefs() {
if ($this->commitRefs === null) {
$this->loadCommitState();
}
return $this->commitRefs;
}
private function getCommitMerges() {
if ($this->commitMerges === null) {
$this->loadCommitState();
}
return $this->commitMerges;
}
private function getCommitErrors() {
if ($this->commitErrors === null) {
$this->loadCommitState();
}
return $this->commitErrors;
}
}
diff --git a/src/applications/diffusion/controller/DiffusionController.php b/src/applications/diffusion/controller/DiffusionController.php
index c83990cc15..a77b000db9 100644
--- a/src/applications/diffusion/controller/DiffusionController.php
+++ b/src/applications/diffusion/controller/DiffusionController.php
@@ -1,348 +1,370 @@
<?php
abstract class DiffusionController extends PhabricatorController {
private $diffusionRequest;
protected function getDiffusionRequest() {
if (!$this->diffusionRequest) {
throw new PhutilInvalidStateException('loadDiffusionContext');
}
return $this->diffusionRequest;
}
protected function hasDiffusionRequest() {
return (bool)$this->diffusionRequest;
}
public function willBeginExecution() {
$request = $this->getRequest();
// Check if this is a VCS request, e.g. from "git clone", "hg clone", or
// "svn checkout". If it is, we jump off into repository serving code to
// process the request.
$serve_controller = new DiffusionServeController();
if ($serve_controller->isVCSRequest($request)) {
return $this->delegateToController($serve_controller);
}
return parent::willBeginExecution();
}
protected function loadDiffusionContextForEdit() {
return $this->loadContext(
array(
'edit' => true,
));
}
protected function loadDiffusionContext() {
return $this->loadContext(array());
}
private function loadContext(array $options) {
$request = $this->getRequest();
$viewer = $this->getViewer();
$identifier = $this->getRepositoryIdentifierFromRequest($request);
$params = $options + array(
'repository' => $identifier,
'user' => $viewer,
'blob' => $this->getDiffusionBlobFromRequest($request),
'commit' => $request->getURIData('commit'),
'path' => $request->getURIData('path'),
'line' => $request->getURIData('line'),
'branch' => $request->getURIData('branch'),
'lint' => $request->getStr('lint'),
);
$drequest = DiffusionRequest::newFromDictionary($params);
if (!$drequest) {
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;
}
protected function getDiffusionBlobFromRequest(AphrontRequest $request) {
return $request->getURIData('dblob');
}
protected function getRepositoryIdentifierFromRequest(
AphrontRequest $request) {
$identifier = $request->getURIData('repositoryCallsign');
if (strlen($identifier)) {
return $identifier;
}
$id = $request->getURIData('repositoryID');
if (strlen($id)) {
return (int)$id;
}
return null;
}
public function buildCrumbs(array $spec = array()) {
$crumbs = $this->buildApplicationCrumbs();
$crumb_list = $this->buildCrumbList($spec);
foreach ($crumb_list as $crumb) {
$crumbs->addCrumb($crumb);
}
return $crumbs;
}
private function buildCrumbList(array $spec = array()) {
$spec = $spec + array(
'commit' => null,
'tags' => null,
'branches' => null,
'view' => null,
);
$crumb_list = array();
// On the home page, we don't have a DiffusionRequest.
if ($this->hasDiffusionRequest()) {
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
} else {
$drequest = null;
$repository = null;
}
if (!$repository) {
return $crumb_list;
}
$repository_name = $repository->getName();
if (!$spec['commit'] && !$spec['tags'] && !$spec['branches']) {
$branch_name = $drequest->getBranch();
if ($branch_name) {
$repository_name .= ' ('.$branch_name.')';
}
}
$crumb = id(new PHUICrumbView())
->setName($repository_name);
if (!$spec['view'] && !$spec['commit'] &&
!$spec['tags'] && !$spec['branches']) {
$crumb_list[] = $crumb;
return $crumb_list;
}
$crumb->setHref(
$drequest->generateURI(
array(
'action' => 'branch',
'path' => '/',
)));
$crumb_list[] = $crumb;
$stable_commit = $drequest->getStableCommit();
$commit_name = $repository->formatCommitName($stable_commit, $local = true);
$commit_uri = $repository->getCommitURI($stable_commit);
if ($spec['tags']) {
$crumb = new PHUICrumbView();
if ($spec['commit']) {
$crumb->setName(pht('Tags for %s', $commit_name));
$crumb->setHref($commit_uri);
} else {
$crumb->setName(pht('Tags'));
}
$crumb_list[] = $crumb;
return $crumb_list;
}
if ($spec['branches']) {
$crumb = id(new PHUICrumbView())
->setName(pht('Branches'));
$crumb_list[] = $crumb;
return $crumb_list;
}
if ($spec['commit']) {
$crumb = id(new PHUICrumbView())
->setName($commit_name);
$crumb_list[] = $crumb;
return $crumb_list;
}
$crumb = new PHUICrumbView();
$view = $spec['view'];
switch ($view) {
case 'history':
$view_name = pht('History');
break;
case 'browse':
$view_name = pht('Browse');
break;
case 'lint':
$view_name = pht('Lint');
break;
case 'change':
$view_name = pht('Change');
break;
}
$crumb = id(new PHUICrumbView())
->setName($view_name);
$crumb_list[] = $crumb;
return $crumb_list;
}
protected function callConduitWithDiffusionRequest(
$method,
array $params = array()) {
$user = $this->getRequest()->getUser();
$drequest = $this->getDiffusionRequest();
return DiffusionQuery::callConduitWithDiffusionRequest(
$user,
$drequest,
$method,
$params);
}
protected function getRepositoryControllerURI(
PhabricatorRepository $repository,
$path) {
return $repository->getPathURI($path);
}
protected function renderPathLinks(DiffusionRequest $drequest, $action) {
$path = $drequest->getPath();
$path_parts = array_filter(explode('/', trim($path, '/')));
$divider = phutil_tag(
'span',
array(
'class' => 'phui-header-divider',
),
'/');
$links = array();
if ($path_parts) {
$links[] = phutil_tag(
'a',
array(
'href' => $drequest->generateURI(
array(
'action' => $action,
'path' => '',
)),
),
$drequest->getRepository()->getDisplayName());
$links[] = $divider;
$accum = '';
$last_key = last_key($path_parts);
foreach ($path_parts as $key => $part) {
$accum .= '/'.$part;
if ($key === $last_key) {
$links[] = $part;
} else {
$links[] = phutil_tag(
'a',
array(
'href' => $drequest->generateURI(
array(
'action' => $action,
'path' => $accum.'/',
)),
),
$part);
$links[] = $divider;
}
}
} else {
$links[] = $drequest->getRepository()->getDisplayName();
$links[] = $divider;
}
return $links;
}
protected function renderStatusMessage($title, $body) {
return id(new PHUIInfoView())
->setSeverity(PHUIInfoView::SEVERITY_WARNING)
->setTitle($title)
+ ->setFlush(true)
->appendChild($body);
}
protected function renderTablePagerBox(PHUIPagerView $pager) {
return id(new PHUIBoxView())
->addMargin(PHUI::MARGIN_LARGE)
->appendChild($pager);
}
+ protected function renderCommitHashTag(DiffusionRequest $drequest) {
+ $stable_commit = $drequest->getStableCommit();
+ $commit = phutil_tag(
+ 'a',
+ array(
+ 'href' => $drequest->generateURI(
+ array(
+ 'action' => 'commit',
+ 'commit' => $stable_commit,
+ )),
+ ),
+ $drequest->getRepository()->formatCommitName($stable_commit, true));
+
+ $tag = id(new PHUITagView())
+ ->setName($commit)
+ ->setShade('indigo')
+ ->setType(PHUITagView::TYPE_SHADE);
+
+ return $tag;
+ }
+
protected function renderDirectoryReadme(DiffusionBrowseResultSet $browse) {
$readme_path = $browse->getReadmePath();
if ($readme_path === null) {
return null;
}
$drequest = $this->getDiffusionRequest();
$viewer = $this->getViewer();
try {
$result = $this->callConduitWithDiffusionRequest(
'diffusion.filecontentquery',
array(
'path' => $readme_path,
'commit' => $drequest->getStableCommit(),
));
} catch (Exception $ex) {
return null;
}
$file_phid = $result['filePHID'];
if (!$file_phid) {
return null;
}
$file = id(new PhabricatorFileQuery())
->setViewer($viewer)
->withPHIDs(array($file_phid))
->executeOne();
if (!$file) {
return null;
}
$corpus = $file->loadFileData();
if (!strlen($corpus)) {
return null;
}
return id(new DiffusionReadmeView())
->setUser($this->getViewer())
->setPath($readme_path)
->setContent($corpus);
}
}
diff --git a/src/applications/diffusion/controller/DiffusionHistoryController.php b/src/applications/diffusion/controller/DiffusionHistoryController.php
index 59248b7acf..eca8fe2a2f 100644
--- a/src/applications/diffusion/controller/DiffusionHistoryController.php
+++ b/src/applications/diffusion/controller/DiffusionHistoryController.php
@@ -1,170 +1,154 @@
<?php
final class DiffusionHistoryController extends DiffusionController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
$response = $this->loadDiffusionContext();
if ($response) {
return $response;
}
$viewer = $this->getViewer();
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$pager = id(new PHUIPagerView())
->readFromRequest($request);
$params = array(
'commit' => $drequest->getCommit(),
'path' => $drequest->getPath(),
'offset' => $pager->getOffset(),
'limit' => $pager->getPageSize() + 1,
);
if (!$request->getBool('copies')) {
$params['needDirectChanges'] = true;
$params['needChildChanges'] = true;
}
$history_results = $this->callConduitWithDiffusionRequest(
'diffusion.historyquery',
$params);
$history = DiffusionPathChange::newFromConduit(
$history_results['pathChanges']);
$history = $pager->sliceResults($history);
$show_graph = !strlen($drequest->getPath());
- $content = array();
-
$history_table = id(new DiffusionHistoryTableView())
->setUser($request->getUser())
->setDiffusionRequest($drequest)
->setHistory($history);
$history_table->loadRevisions();
if ($show_graph) {
$history_table->setParents($history_results['parents']);
$history_table->setIsHead(!$pager->getOffset());
$history_table->setIsTail(!$pager->getHasMorePages());
}
- $history_panel = new PHUIObjectBoxView();
- $history_panel->setHeaderText(pht('History'));
- $history_panel->setTable($history_table);
-
- $content[] = $history_panel;
+ $history_header = $this->buildHistoryHeader($drequest);
+ $history_panel = id(new PHUIObjectBoxView())
+ ->setHeader($history_header)
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
+ ->setTable($history_table);
- $header = id(new PHUIHeaderView())
- ->setUser($viewer)
- ->setPolicyObject($repository)
- ->setHeader($this->renderPathLinks($drequest, $mode = 'history'));
-
- $actions = $this->buildActionView($drequest);
- $properties = $this->buildPropertyView($drequest, $actions);
-
- $object_box = id(new PHUIObjectBoxView())
- ->setHeader($header)
- ->addPropertyList($properties);
+ $header = $this->buildHeader($drequest, $repository);
$crumbs = $this->buildCrumbs(
array(
'branch' => true,
'path' => true,
'view' => 'history',
));
+ $crumbs->setBorder(true);
$pager_box = $this->renderTablePagerBox($pager);
+ $view = id(new PHUITwoColumnView())
+ ->setHeader($header)
+ ->setFooter(array(
+ $history_panel,
+ $pager_box,
+ ));
+
return $this->newPage()
->setTitle(
array(
pht('History'),
$repository->getDisplayName(),
))
->setCrumbs($crumbs)
->appendChild(
array(
- $object_box,
- $content,
- $pager_box,
+ $view,
));
}
- private function buildActionView(DiffusionRequest $drequest) {
- $viewer = $this->getRequest()->getUser();
+ private function buildHeader(DiffusionRequest $drequest) {
+ $viewer = $this->getViewer();
- $view = id(new PhabricatorActionListView())
- ->setUser($viewer);
+ $tag = $this->renderCommitHashTag($drequest);
+
+ $header = id(new PHUIHeaderView())
+ ->setUser($viewer)
+ ->setPolicyObject($drequest->getRepository())
+ ->addTag($tag)
+ ->setHeader($this->renderPathLinks($drequest, $mode = 'history'))
+ ->setHeaderIcon('fa-clock-o');
+
+ return $header;
+
+ }
+
+ private function buildHistoryHeader(DiffusionRequest $drequest) {
+ $viewer = $this->getViewer();
$browse_uri = $drequest->generateURI(
array(
'action' => 'browse',
));
- $view->addAction(
- id(new PhabricatorActionView())
- ->setName(pht('Browse Content'))
- ->setHref($browse_uri)
- ->setIcon('fa-files-o'));
+ $browse_button = id(new PHUIButtonView())
+ ->setTag('a')
+ ->setText(pht('Browse'))
+ ->setHref($browse_uri)
+ ->setIcon('fa-files-o');
// TODO: Sometimes we do have a change view, we need to look at the most
// recent history entry to figure it out.
$request = $this->getRequest();
if ($request->getBool('copies')) {
$branch_name = pht('Hide Copies/Branches');
$branch_uri = $request->getRequestURI()
->alter('offset', null)
->alter('copies', null);
} else {
$branch_name = pht('Show Copies/Branches');
$branch_uri = $request->getRequestURI()
->alter('offset', null)
->alter('copies', true);
}
- $view->addAction(
- id(new PhabricatorActionView())
- ->setName($branch_name)
- ->setIcon('fa-code-fork')
- ->setHref($branch_uri));
-
- return $view;
- }
+ $branch_button = id(new PHUIButtonView())
+ ->setTag('a')
+ ->setText($branch_name)
+ ->setIcon('fa-code-fork')
+ ->setHref($branch_uri);
- protected function buildPropertyView(
- DiffusionRequest $drequest,
- PhabricatorActionListView $actions) {
-
- $viewer = $this->getRequest()->getUser();
-
- $view = id(new PHUIPropertyListView())
- ->setUser($viewer)
- ->setActionList($actions);
-
- $stable_commit = $drequest->getStableCommit();
+ $header = id(new PHUIHeaderView())
+ ->setHeader(pht('History'))
+ ->addActionLink($browse_button)
+ ->addActionLink($branch_button);
- $view->addProperty(
- pht('Commit'),
- phutil_tag(
- 'a',
- array(
- 'href' => $drequest->generateURI(
- array(
- 'action' => 'commit',
- 'commit' => $stable_commit,
- )),
- ),
- $drequest->getRepository()->formatCommitName($stable_commit)));
-
- return $view;
+ return $header;
}
}
diff --git a/src/applications/diffusion/controller/DiffusionLintController.php b/src/applications/diffusion/controller/DiffusionLintController.php
index dcbb217d99..fbd059796a 100644
--- a/src/applications/diffusion/controller/DiffusionLintController.php
+++ b/src/applications/diffusion/controller/DiffusionLintController.php
@@ -1,514 +1,535 @@
<?php
final class DiffusionLintController extends DiffusionController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
$viewer = $this->getViewer();
if ($this->getRepositoryIdentifierFromRequest($request)) {
$response = $this->loadDiffusionContext();
if ($response) {
return $response;
}
$drequest = $this->getDiffusionRequest();
} else {
$drequest = null;
}
$code = $request->getStr('lint');
if (strlen($code)) {
return $this->buildDetailsResponse();
}
$owners = array();
if (!$drequest) {
if (!$request->getArr('owner')) {
$owners = array($viewer->getPHID());
} else {
$owners = array(head($request->getArr('owner')));
}
}
$codes = $this->loadLintCodes($drequest, $owners);
if ($codes) {
$branches = id(new PhabricatorRepositoryBranch())->loadAllWhere(
'id IN (%Ld)',
array_unique(ipull($codes, 'branchID')));
$branches = mpull($branches, null, 'getID');
} else {
$branches = array();
}
if ($branches) {
$repositories = id(new PhabricatorRepositoryQuery())
->setViewer($viewer)
->withIDs(mpull($branches, 'getRepositoryID'))
->execute();
$repositories = mpull($repositories, null, 'getID');
} else {
$repositories = array();
}
$rows = array();
$total = 0;
foreach ($codes as $code) {
$branch = idx($branches, $code['branchID']);
if (!$branch) {
continue;
}
$repository = idx($repositories, $branch->getRepositoryID());
if (!$repository) {
continue;
}
$total += $code['n'];
if ($drequest) {
$href_lint = $drequest->generateURI(
array(
'action' => 'lint',
'lint' => $code['code'],
));
$href_browse = $drequest->generateURI(
array(
'action' => 'browse',
'lint' => $code['code'],
));
$href_repo = $drequest->generateURI(
array(
'action' => 'lint',
));
} else {
$href_lint = $repository->generateURI(
array(
'action' => 'lint',
'lint' => $code['code'],
));
$href_browse = $repository->generateURI(
array(
'action' => 'browse',
'lint' => $code['code'],
));
$href_repo = $repository->generateURI(
array(
'action' => 'lint',
));
}
$rows[] = array(
phutil_tag('a', array('href' => $href_lint), $code['n']),
phutil_tag('a', array('href' => $href_browse), $code['files']),
phutil_tag(
'a',
array(
'href' => $href_repo,
),
$repository->getDisplayName()),
ArcanistLintSeverity::getStringForSeverity($code['maxSeverity']),
$code['code'],
$code['maxName'],
$code['maxDescription'],
);
}
$table = id(new AphrontTableView($rows))
->setHeaders(array(
pht('Problems'),
pht('Files'),
pht('Repository'),
pht('Severity'),
pht('Code'),
pht('Name'),
pht('Example'),
))
->setColumnVisibility(array(true, true, !$drequest))
->setColumnClasses(array('n', 'n', '', '', 'pri', '', ''));
$content = array();
if (!$drequest) {
$form = id(new AphrontFormView())
->setUser($viewer)
->setMethod('GET')
->appendControl(
id(new AphrontFormTokenizerControl())
->setDatasource(new PhabricatorPeopleDatasource())
->setLimit(1)
->setName('owner')
->setLabel(pht('Owner'))
->setValue($owners))
->appendChild(
id(new AphrontFormSubmitControl())
->setValue(pht('Filter')));
$content[] = id(new AphrontListFilterView())->appendChild($form);
}
$content[] = id(new PHUIObjectBoxView())
->setHeaderText(pht('Lint'))
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setTable($table);
$title = array('Lint');
$crumbs = $this->buildCrumbs(
array(
'branch' => true,
'path' => true,
'view' => 'lint',
));
if ($drequest) {
$title[] = $drequest->getRepository()->getDisplayName();
} else {
$crumbs->addTextCrumb(pht('All Lint'));
}
if ($drequest) {
$branch = $drequest->loadBranch();
$header = id(new PHUIHeaderView())
->setHeader($this->renderPathLinks($drequest, 'lint'))
->setUser($viewer)
- ->setPolicyObject($drequest->getRepository());
+ ->setHeaderIcon('fa-code');
$actions = $this->buildActionView($drequest);
$properties = $this->buildPropertyView(
$drequest,
$branch,
$total,
$actions);
$object_box = id(new PHUIObjectBoxView())
->setHeader($header)
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addPropertyList($properties);
} else {
$object_box = null;
+ $header = id(new PHUIHeaderView())
+ ->setHeader(pht('All Lint'))
+ ->setHeaderIcon('fa-code');
}
+ $view = id(new PHUITwoColumnView())
+ ->setHeader($header)
+ ->setFooter(array(
+ $object_box,
+ $content,
+ ));
+
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
->appendChild(
array(
- $object_box,
- $content,
+ $view,
));
}
private function loadLintCodes($drequest, array $owner_phids) {
$conn = id(new PhabricatorRepository())->establishConnection('r');
$where = array('1 = 1');
if ($drequest) {
$branch = $drequest->loadBranch();
if (!$branch) {
return array();
}
$where[] = qsprintf($conn, 'branchID = %d', $branch->getID());
if ($drequest->getPath() != '') {
$path = '/'.$drequest->getPath();
$is_dir = (substr($path, -1) == '/');
$where[] = ($is_dir
? qsprintf($conn, 'path LIKE %>', $path)
: qsprintf($conn, 'path = %s', $path));
}
}
if ($owner_phids) {
$or = array();
$or[] = qsprintf($conn, 'authorPHID IN (%Ls)', $owner_phids);
$paths = array();
$packages = id(new PhabricatorOwnersOwner())
->loadAllWhere('userPHID IN (%Ls)', $owner_phids);
if ($packages) {
$paths = id(new PhabricatorOwnersPath())->loadAllWhere(
'packageID IN (%Ld)',
mpull($packages, 'getPackageID'));
}
if ($paths) {
$repositories = id(new PhabricatorRepositoryQuery())
->setViewer($this->getRequest()->getUser())
->withPHIDs(mpull($paths, 'getRepositoryPHID'))
->execute();
$repositories = mpull($repositories, 'getID', 'getPHID');
$branches = id(new PhabricatorRepositoryBranch())->loadAllWhere(
'repositoryID IN (%Ld)',
$repositories);
$branches = mgroup($branches, 'getRepositoryID');
}
foreach ($paths as $path) {
$branch = idx(
$branches,
idx(
$repositories,
$path->getRepositoryPHID()));
if ($branch) {
$condition = qsprintf(
$conn,
'(branchID IN (%Ld) AND path LIKE %>)',
array_keys($branch),
$path->getPath());
if ($path->getExcluded()) {
$where[] = 'NOT '.$condition;
} else {
$or[] = $condition;
}
}
}
$where[] = '('.implode(' OR ', $or).')';
}
return queryfx_all(
$conn,
'SELECT
branchID,
code,
MAX(severity) AS maxSeverity,
MAX(name) AS maxName,
MAX(description) AS maxDescription,
COUNT(DISTINCT path) AS files,
COUNT(*) AS n
FROM %T
WHERE %Q
GROUP BY branchID, code
ORDER BY n DESC',
PhabricatorRepository::TABLE_LINTMESSAGE,
implode(' AND ', $where));
}
protected function buildActionView(DiffusionRequest $drequest) {
$viewer = $this->getRequest()->getUser();
$view = id(new PhabricatorActionListView())
->setUser($viewer);
$list_uri = $drequest->generateURI(
array(
'action' => 'lint',
'lint' => '',
));
$view->addAction(
id(new PhabricatorActionView())
->setName(pht('View As List'))
->setHref($list_uri)
->setIcon('fa-list'));
$history_uri = $drequest->generateURI(
array(
'action' => 'history',
));
$view->addAction(
id(new PhabricatorActionView())
->setName(pht('View History'))
->setHref($history_uri)
->setIcon('fa-clock-o'));
$browse_uri = $drequest->generateURI(
array(
'action' => 'browse',
));
$view->addAction(
id(new PhabricatorActionView())
->setName(pht('Browse Content'))
->setHref($browse_uri)
->setIcon('fa-files-o'));
return $view;
}
protected function buildPropertyView(
DiffusionRequest $drequest,
PhabricatorRepositoryBranch $branch,
$total,
PhabricatorActionListView $actions) {
$viewer = $this->getRequest()->getUser();
$view = id(new PHUIPropertyListView())
->setUser($viewer)
->setActionList($actions);
$lint_commit = $branch->getLintCommit();
$view->addProperty(
pht('Lint Commit'),
phutil_tag(
'a',
array(
'href' => $drequest->generateURI(
array(
'action' => 'commit',
'commit' => $lint_commit,
)),
),
$drequest->getRepository()->formatCommitName($lint_commit)));
$view->addProperty(
pht('Total Messages'),
pht('%s', new PhutilNumber($total)));
return $view;
}
private function buildDetailsResponse() {
$request = $this->getRequest();
$limit = 500;
$pager = id(new PHUIPagerView())
->readFromRequest($request)
->setPageSize($limit);
$offset = $pager->getOffset();
$drequest = $this->getDiffusionRequest();
$branch = $drequest->loadBranch();
$messages = $this->loadLintMessages($branch, $limit, $offset);
$is_dir = (substr('/'.$drequest->getPath(), -1) == '/');
$pager->setHasMorePages(count($messages) >= $limit);
$authors = $this->loadViewerHandles(ipull($messages, 'authorPHID'));
$rows = array();
foreach ($messages as $message) {
$path = phutil_tag(
'a',
array(
'href' => $drequest->generateURI(array(
'action' => 'lint',
'path' => $message['path'],
)),
),
substr($message['path'], strlen($drequest->getPath()) + 1));
$line = phutil_tag(
'a',
array(
'href' => $drequest->generateURI(array(
'action' => 'browse',
'path' => $message['path'],
'line' => $message['line'],
'commit' => $branch->getLintCommit(),
)),
),
$message['line']);
$author = $message['authorPHID'];
if ($author && $authors[$author]) {
$author = $authors[$author]->renderLink();
}
$rows[] = array(
$path,
$line,
$author,
ArcanistLintSeverity::getStringForSeverity($message['severity']),
$message['name'],
$message['description'],
);
}
$table = id(new AphrontTableView($rows))
->setHeaders(array(
pht('Path'),
pht('Line'),
pht('Author'),
pht('Severity'),
pht('Name'),
pht('Description'),
))
->setColumnClasses(array('', 'n'))
->setColumnVisibility(array($is_dir));
$content = array();
$content[] = id(new PHUIObjectBoxView())
->setHeaderText(pht('Lint Details'))
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setTable($table);
$crumbs = $this->buildCrumbs(
array(
'branch' => true,
'path' => true,
'view' => 'lint',
));
$pager_box = $this->renderTablePagerBox($pager);
+ $header = id(new PHUIHeaderView())
+ ->setHeader(pht('Lint: %s', $drequest->getRepository()->getDisplayName()))
+ ->setHeaderIcon('fa-code');
+
+ $view = id(new PHUITwoColumnView())
+ ->setHeader($header)
+ ->setFooter(array(
+ $content,
+ $pager_box,
+ ));
return $this->newPage()
->setTitle(
array(
pht('Lint'),
$drequest->getRepository()->getDisplayName(),
))
->setCrumbs($crumbs)
->appendChild(
array(
- $content,
- $pager_box,
+ $view,
));
}
private function loadLintMessages(
PhabricatorRepositoryBranch $branch,
$limit,
$offset) {
$drequest = $this->getDiffusionRequest();
if (!$branch) {
return array();
}
$conn = $branch->establishConnection('r');
$where = array(
qsprintf($conn, 'branchID = %d', $branch->getID()),
);
if ($drequest->getPath() != '') {
$path = '/'.$drequest->getPath();
$is_dir = (substr($path, -1) == '/');
$where[] = ($is_dir
? qsprintf($conn, 'path LIKE %>', $path)
: qsprintf($conn, 'path = %s', $path));
}
if ($drequest->getLint() != '') {
$where[] = qsprintf(
$conn,
'code = %s',
$drequest->getLint());
}
return queryfx_all(
$conn,
'SELECT *
FROM %T
WHERE %Q
ORDER BY path, code, line LIMIT %d OFFSET %d',
PhabricatorRepository::TABLE_LINTMESSAGE,
implode(' AND ', $where),
$limit,
$offset);
}
}
diff --git a/src/applications/diffusion/controller/DiffusionRepositoryController.php b/src/applications/diffusion/controller/DiffusionRepositoryController.php
index 6504ee50e1..792bcc4249 100644
--- a/src/applications/diffusion/controller/DiffusionRepositoryController.php
+++ b/src/applications/diffusion/controller/DiffusionRepositoryController.php
@@ -1,749 +1,780 @@
<?php
final class DiffusionRepositoryController extends DiffusionController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
$response = $this->loadDiffusionContext();
if ($response) {
return $response;
}
$viewer = $this->getViewer();
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
- $content = array();
-
$crumbs = $this->buildCrumbs();
+ $crumbs->setBorder(true);
- $content[] = $this->buildPropertiesTable($drequest->getRepository());
+ $header = $this->buildHeaderView($repository);
+ $curtain = $this->buildCurtain($repository);
+ $property_table = $this->buildPropertiesTable($repository);
+ $description = $this->buildDescriptionView($repository);
+ $locate_file = $this->buildLocateFile();
// Before we do any work, make sure we're looking at a some content: we're
// on a valid branch, and the repository is not empty.
$page_has_content = false;
$empty_title = null;
$empty_message = null;
// If this VCS supports branches, check that the selected branch actually
// exists.
if ($drequest->supportsBranches()) {
// NOTE: Mercurial may have multiple branch heads with the same name.
$ref_cursors = id(new PhabricatorRepositoryRefCursorQuery())
->setViewer($viewer)
->withRepositoryPHIDs(array($repository->getPHID()))
->withRefTypes(array(PhabricatorRepositoryRefCursor::TYPE_BRANCH))
->withRefNames(array($drequest->getBranch()))
->execute();
if ($ref_cursors) {
// This is a valid branch, so we necessarily have some content.
$page_has_content = true;
} else {
$empty_title = pht('No Such Branch');
$empty_message = pht(
'There is no branch named "%s" in this repository.',
$drequest->getBranch());
}
}
// If we didn't find any branches, check if there are any commits at all.
// This can tailor the message for empty repositories.
if (!$page_has_content) {
$any_commit = id(new DiffusionCommitQuery())
->setViewer($viewer)
->withRepository($repository)
->setLimit(1)
->execute();
if ($any_commit) {
if (!$drequest->supportsBranches()) {
$page_has_content = true;
}
} else {
$empty_title = pht('Empty Repository');
$empty_message = pht('This repository does not have any commits yet.');
}
}
if ($page_has_content) {
- $content[] = $this->buildNormalContent($drequest);
+ $content = $this->buildNormalContent($drequest);
} else {
- $content[] = id(new PHUIInfoView())
+ $content = id(new PHUIInfoView())
->setTitle($empty_title)
->setSeverity(PHUIInfoView::SEVERITY_WARNING)
->setErrors(array($empty_message));
}
+ $view = id(new PHUITwoColumnView())
+ ->setHeader($header)
+ ->setCurtain($curtain)
+ ->setMainColumn(array(
+ $property_table,
+ $description,
+ $locate_file,
+ ))
+ ->setFooter($content);
+
return $this->newPage()
->setTitle(
array(
$repository->getName(),
$repository->getDisplayName(),
))
->setCrumbs($crumbs)
- ->appendChild($content);
+ ->appendChild(array(
+ $view,
+ ));
}
private function buildNormalContent(DiffusionRequest $drequest) {
$request = $this->getRequest();
$repository = $drequest->getRepository();
$phids = array();
$content = array();
try {
$history_results = $this->callConduitWithDiffusionRequest(
'diffusion.historyquery',
array(
'commit' => $drequest->getCommit(),
'path' => $drequest->getPath(),
'offset' => 0,
'limit' => 15,
));
$history = DiffusionPathChange::newFromConduit(
$history_results['pathChanges']);
foreach ($history as $item) {
$data = $item->getCommitData();
if ($data) {
if ($data->getCommitDetail('authorPHID')) {
$phids[$data->getCommitDetail('authorPHID')] = true;
}
if ($data->getCommitDetail('committerPHID')) {
$phids[$data->getCommitDetail('committerPHID')] = true;
}
}
}
$history_exception = null;
} catch (Exception $ex) {
$history_results = null;
$history = null;
$history_exception = $ex;
}
$browse_pager = id(new PHUIPagerView())
->readFromRequest($request);
try {
$browse_results = DiffusionBrowseResultSet::newFromConduit(
$this->callConduitWithDiffusionRequest(
'diffusion.browsequery',
array(
'path' => $drequest->getPath(),
'commit' => $drequest->getCommit(),
'limit' => $browse_pager->getPageSize() + 1,
)));
$browse_paths = $browse_results->getPaths();
$browse_paths = $browse_pager->sliceResults($browse_paths);
foreach ($browse_paths as $item) {
$data = $item->getLastCommitData();
if ($data) {
if ($data->getCommitDetail('authorPHID')) {
$phids[$data->getCommitDetail('authorPHID')] = true;
}
if ($data->getCommitDetail('committerPHID')) {
$phids[$data->getCommitDetail('committerPHID')] = true;
}
}
}
$browse_exception = null;
} catch (Exception $ex) {
$browse_results = null;
$browse_paths = null;
$browse_exception = $ex;
}
$phids = array_keys($phids);
$handles = $this->loadViewerHandles($phids);
if ($browse_results) {
$readme = $this->renderDirectoryReadme($browse_results);
} else {
$readme = null;
}
$content[] = $this->buildBrowseTable(
$browse_results,
$browse_paths,
$browse_exception,
$handles,
$browse_pager);
$content[] = $this->buildHistoryTable(
$history_results,
$history,
$history_exception);
try {
$content[] = $this->buildTagListTable($drequest);
} catch (Exception $ex) {
if (!$repository->isImporting()) {
$content[] = $this->renderStatusMessage(
pht('Unable to Load Tags'),
$ex->getMessage());
}
}
try {
$content[] = $this->buildBranchListTable($drequest);
} catch (Exception $ex) {
if (!$repository->isImporting()) {
$content[] = $this->renderStatusMessage(
pht('Unable to Load Branches'),
$ex->getMessage());
}
}
if ($readme) {
$content[] = $readme;
}
return $content;
}
- private function buildPropertiesTable(PhabricatorRepository $repository) {
- $user = $this->getRequest()->getUser();
-
+ private function buildHeaderView(PhabricatorRepository $repository) {
+ $viewer = $this->getViewer();
$header = id(new PHUIHeaderView())
->setHeader($repository->getName())
- ->setUser($user)
- ->setPolicyObject($repository);
+ ->setUser($viewer)
+ ->setPolicyObject($repository)
+ ->setHeaderIcon('fa-code');
if (!$repository->isTracked()) {
$header->setStatus('fa-ban', 'dark', pht('Inactive'));
} else if ($repository->isImporting()) {
$ratio = $repository->loadImportProgress();
$percentage = sprintf('%.2f%%', 100 * $ratio);
$header->setStatus(
'fa-clock-o',
'indigo',
pht('Importing (%s)...', $percentage));
} else {
$header->setStatus('fa-check', 'bluegrey', pht('Active'));
}
+ return $header;
+ }
+
+ private function buildCurtain(PhabricatorRepository $repository) {
+ $viewer = $this->getViewer();
+
+ $edit_uri = $repository->getPathURI('edit/');
+ $curtain = $this->newCurtainView($repository);
+
+ $can_edit = PhabricatorPolicyFilter::hasCapability(
+ $viewer,
+ $repository,
+ PhabricatorPolicyCapability::CAN_EDIT);
+
+ $curtain->addAction(
+ id(new PhabricatorActionView())
+ ->setName(pht('Edit Repository'))
+ ->setIcon('fa-pencil')
+ ->setHref($edit_uri)
+ ->setWorkflow(!$can_edit)
+ ->setDisabled(!$can_edit));
+
+ if ($repository->isHosted()) {
+ $push_uri = $this->getApplicationURI(
+ 'pushlog/?repositories='.$repository->getMonogram());
- $actions = $this->buildActionList($repository);
+ $curtain->addAction(
+ id(new PhabricatorActionView())
+ ->setName(pht('View Push Logs'))
+ ->setIcon('fa-list-alt')
+ ->setHref($push_uri));
+ }
+ return $curtain;
+ }
+
+ private function buildDescriptionView(PhabricatorRepository $repository) {
+ $viewer = $this->getViewer();
$view = id(new PHUIPropertyListView())
- ->setObject($repository)
- ->setUser($user);
+ ->setUser($viewer);
+
+ $description = $repository->getDetail('description');
+ if (strlen($description)) {
+ $description = new PHUIRemarkupView($viewer, $description);
+ $view->addTextContent($description);
+ return id(new PHUIObjectBoxView())
+ ->setHeaderText(pht('DESCRIPTION'))
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
+ ->appendChild($view);
+ }
+ return null;
+ }
+
+ private function buildPropertiesTable(PhabricatorRepository $repository) {
+ $viewer = $this->getViewer();
+
+ $view = id(new PHUIPropertyListView())
+ ->setUser($viewer);
if ($repository->isHosted()) {
$ssh_uri = $repository->getSSHCloneURIObject();
if ($ssh_uri) {
$clone_uri = $this->renderCloneCommand(
$repository,
$ssh_uri,
$repository->getServeOverSSH(),
'/settings/panel/ssh/');
$view->addProperty(
$repository->isSVN()
? pht('Checkout (SSH)')
: pht('Clone (SSH)'),
$clone_uri);
}
$http_uri = $repository->getHTTPCloneURIObject();
if ($http_uri) {
$clone_uri = $this->renderCloneCommand(
$repository,
$http_uri,
$repository->getServeOverHTTP(),
PhabricatorEnv::getEnvConfig('diffusion.allow-http-auth')
? '/settings/panel/vcspassword/'
: null);
$view->addProperty(
$repository->isSVN()
? pht('Checkout (HTTP)')
: pht('Clone (HTTP)'),
$clone_uri);
}
} else {
switch ($repository->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
$view->addProperty(
pht('Clone'),
$this->renderCloneCommand(
$repository,
$repository->getPublicCloneURI()));
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
$view->addProperty(
pht('Checkout'),
$this->renderCloneCommand(
$repository,
$repository->getPublicCloneURI()));
break;
}
}
- $view->invokeWillRenderEvent();
-
- $description = $repository->getDetail('description');
- if (strlen($description)) {
- $description = new PHUIRemarkupView($user, $description);
- $view->addSectionHeader(
- pht('Description'), PHUIPropertyListView::ICON_SUMMARY);
- $view->addTextContent($description);
- }
-
- $view->setActionList($actions);
-
$box = id(new PHUIObjectBoxView())
- ->setHeader($header)
- ->addPropertyList($view);
+ ->setHeaderText(pht('DETAILS'))
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
+ ->appendChild($view);
$info = null;
$drequest = $this->getDiffusionRequest();
// Try to load alternatives. This may fail for repositories which have not
// cloned yet. If it does, just ignore it and continue.
try {
$alternatives = $drequest->getRefAlternatives();
} catch (ConduitClientException $ex) {
$alternatives = array();
}
if ($alternatives) {
$message = array(
pht(
'The ref "%s" is ambiguous in this repository.',
$drequest->getBranch()),
' ',
phutil_tag(
'a',
array(
'href' => $drequest->generateURI(
array(
'action' => 'refs',
)),
),
pht('View Alternatives')),
);
$messages = array($message);
$info = id(new PHUIInfoView())
->setSeverity(PHUIInfoView::SEVERITY_WARNING)
->setErrors(array($message));
$box->setInfoView($info);
}
return $box;
}
private function buildBranchListTable(DiffusionRequest $drequest) {
- $viewer = $this->getRequest()->getUser();
+ $viewer = $this->getViewer();
if ($drequest->getBranch() === null) {
return null;
}
$limit = 15;
$branches = $this->callConduitWithDiffusionRequest(
'diffusion.branchquery',
array(
'closed' => false,
'limit' => $limit + 1,
));
if (!$branches) {
return null;
}
$more_branches = (count($branches) > $limit);
$branches = array_slice($branches, 0, $limit);
$branches = DiffusionRepositoryRef::loadAllFromDictionaries($branches);
$commits = id(new DiffusionCommitQuery())
->setViewer($viewer)
->withIdentifiers(mpull($branches, 'getCommitIdentifier'))
->withRepository($drequest->getRepository())
->execute();
$table = id(new DiffusionBranchTableView())
->setUser($viewer)
->setDiffusionRequest($drequest)
->setBranches($branches)
->setCommits($commits);
- $panel = new PHUIObjectBoxView();
+ $panel = id(new PHUIObjectBoxView())
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY);
$header = new PHUIHeaderView();
$header->setHeader(pht('Branches'));
if ($more_branches) {
$header->setSubHeader(pht('Showing %d branches.', $limit));
}
$button = new PHUIButtonView();
- $button->setText(pht('Show All Branches'));
+ $button->setText(pht('Show All'));
$button->setTag('a');
$button->setIcon('fa-code-fork');
$button->setHref($drequest->generateURI(
array(
'action' => 'branches',
)));
$header->addActionLink($button);
$panel->setHeader($header);
$panel->setTable($table);
return $panel;
}
private function buildTagListTable(DiffusionRequest $drequest) {
- $viewer = $this->getRequest()->getUser();
+ $viewer = $this->getViewer();
$repository = $drequest->getRepository();
switch ($repository->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
// no tags in SVN
return null;
}
$tag_limit = 15;
$tags = array();
$tags = DiffusionRepositoryTag::newFromConduit(
$this->callConduitWithDiffusionRequest(
'diffusion.tagsquery',
array(
// On the home page, we want to find tags on any branch.
'commit' => null,
'limit' => $tag_limit + 1,
)));
if (!$tags) {
return null;
}
$more_tags = (count($tags) > $tag_limit);
$tags = array_slice($tags, 0, $tag_limit);
$commits = id(new DiffusionCommitQuery())
->setViewer($viewer)
->withIdentifiers(mpull($tags, 'getCommitIdentifier'))
->withRepository($repository)
->needCommitData(true)
->execute();
$view = id(new DiffusionTagListView())
->setUser($viewer)
->setDiffusionRequest($drequest)
->setTags($tags)
->setCommits($commits);
$phids = $view->getRequiredHandlePHIDs();
$handles = $this->loadViewerHandles($phids);
$view->setHandles($handles);
$panel = new PHUIObjectBoxView();
$header = new PHUIHeaderView();
$header->setHeader(pht('Tags'));
if ($more_tags) {
$header->setSubHeader(
pht('Showing the %d most recent tags.', $tag_limit));
}
$button = new PHUIButtonView();
$button->setText(pht('Show All Tags'));
$button->setTag('a');
$button->setIcon('fa-tag');
$button->setHref($drequest->generateURI(
array(
'action' => 'tags',
)));
$header->addActionLink($button);
$panel->setHeader($header);
$panel->setTable($view);
+ $panel->setBackground(PHUIObjectBoxView::BLUE_PROPERTY);
return $panel;
}
- private function buildActionList(PhabricatorRepository $repository) {
- $viewer = $this->getRequest()->getUser();
-
- $edit_uri = $repository->getPathURI('edit/');
-
- $view = id(new PhabricatorActionListView())
- ->setUser($viewer)
- ->setObject($repository);
-
- $can_edit = PhabricatorPolicyFilter::hasCapability(
- $viewer,
- $repository,
- PhabricatorPolicyCapability::CAN_EDIT);
-
- $view->addAction(
- id(new PhabricatorActionView())
- ->setName(pht('Edit Repository'))
- ->setIcon('fa-pencil')
- ->setHref($edit_uri)
- ->setWorkflow(!$can_edit)
- ->setDisabled(!$can_edit));
-
- if ($repository->isHosted()) {
- $push_uri = $this->getApplicationURI(
- 'pushlog/?repositories='.$repository->getMonogram());
-
- $view->addAction(
- id(new PhabricatorActionView())
- ->setName(pht('View Push Logs'))
- ->setIcon('fa-list-alt')
- ->setHref($push_uri));
- }
-
- return $view;
- }
-
private function buildHistoryTable(
$history_results,
$history,
$history_exception) {
$request = $this->getRequest();
$viewer = $request->getUser();
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
if ($history_exception) {
if ($repository->isImporting()) {
return $this->renderStatusMessage(
pht('Still Importing...'),
pht(
'This repository is still importing. History is not yet '.
'available.'));
} else {
return $this->renderStatusMessage(
pht('Unable to Retrieve History'),
$history_exception->getMessage());
}
}
$history_table = id(new DiffusionHistoryTableView())
->setUser($viewer)
->setDiffusionRequest($drequest)
->setHistory($history);
// TODO: Super sketchy.
$history_table->loadRevisions();
if ($history_results) {
$history_table->setParents($history_results['parents']);
}
$history_table->setIsHead(true);
$icon = id(new PHUIIconView())
->setIcon('fa-list-alt');
$button = id(new PHUIButtonView())
- ->setText(pht('View Full History'))
+ ->setText(pht('View History'))
->setHref($drequest->generateURI(
array(
'action' => 'history',
)))
->setTag('a')
->setIcon($icon);
- $panel = new PHUIObjectBoxView();
+ $panel = id(new PHUIObjectBoxView())
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY);
$header = id(new PHUIHeaderView())
->setHeader(pht('Recent Commits'))
->addActionLink($button);
$panel->setHeader($header);
$panel->setTable($history_table);
return $panel;
}
+ private function buildLocateFile() {
+ $request = $this->getRequest();
+ $viewer = $request->getUser();
+ $drequest = $this->getDiffusionRequest();
+ $repository = $drequest->getRepository();
+
+ $locate_panel = null;
+ if ($repository->canUsePathTree()) {
+ Javelin::initBehavior(
+ 'diffusion-locate-file',
+ array(
+ 'controlID' => 'locate-control',
+ 'inputID' => 'locate-input',
+ 'browseBaseURI' => (string)$drequest->generateURI(
+ array(
+ 'action' => 'browse',
+ )),
+ 'uri' => (string)$drequest->generateURI(
+ array(
+ 'action' => 'pathtree',
+ )),
+ ));
+
+ $form = id(new AphrontFormView())
+ ->setUser($viewer)
+ ->appendChild(
+ id(new AphrontFormTypeaheadControl())
+ ->setHardpointID('locate-control')
+ ->setID('locate-input')
+ ->setLabel(pht('Locate File')));
+ $form_box = id(new PHUIBoxView())
+ ->appendChild($form->buildLayoutView());
+ $locate_panel = id(new PHUIObjectBoxView())
+ ->setHeaderText(pht('Locate File'))
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
+ ->appendChild($form_box);
+ }
+ return $locate_panel;
+ }
+
private function buildBrowseTable(
$browse_results,
$browse_paths,
$browse_exception,
array $handles,
PHUIPagerView $pager) {
require_celerity_resource('diffusion-icons-css');
$request = $this->getRequest();
$viewer = $request->getUser();
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
if ($browse_exception) {
if ($repository->isImporting()) {
// The history table renders a useful message.
return null;
} else {
return $this->renderStatusMessage(
pht('Unable to Retrieve Paths'),
$browse_exception->getMessage());
}
}
$browse_table = id(new DiffusionBrowseTableView())
->setUser($viewer)
->setDiffusionRequest($drequest)
->setHandles($handles);
if ($browse_paths) {
$browse_table->setPaths($browse_paths);
} else {
$browse_table->setPaths(array());
}
$browse_uri = $drequest->generateURI(array('action' => 'browse'));
- $browse_panel = new PHUIObjectBoxView();
+ $browse_panel = id(new PHUIObjectBoxView())
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY);
$header = id(new PHUIHeaderView())
- ->setHeader(pht('Repository'));
+ ->setHeader($repository->getName());
$icon = id(new PHUIIconView())
->setIcon('fa-folder-open');
$button = new PHUIButtonView();
$button->setText(pht('Browse Repository'));
$button->setTag('a');
$button->setIcon($icon);
$button->setHref($browse_uri);
$header->addActionLink($button);
$browse_panel->setHeader($header);
-
- $locate_panel = null;
- if ($repository->canUsePathTree()) {
- Javelin::initBehavior(
- 'diffusion-locate-file',
- array(
- 'controlID' => 'locate-control',
- 'inputID' => 'locate-input',
- 'browseBaseURI' => (string)$drequest->generateURI(
- array(
- 'action' => 'browse',
- )),
- 'uri' => (string)$drequest->generateURI(
- array(
- 'action' => 'pathtree',
- )),
- ));
-
- $form = id(new AphrontFormView())
- ->setUser($viewer)
- ->appendChild(
- id(new AphrontFormTypeaheadControl())
- ->setHardpointID('locate-control')
- ->setID('locate-input')
- ->setLabel(pht('Locate File')));
- $form_box = id(new PHUIBoxView())
- ->appendChild($form->buildLayoutView());
- $locate_panel = id(new PHUIObjectBoxView())
- ->setHeaderText('Locate File')
- ->appendChild($form_box);
- }
-
$browse_panel->setTable($browse_table);
$pager->setURI($browse_uri, 'offset');
if ($pager->willShowPagingControls()) {
$pager_box = $this->renderTablePagerBox($pager);
} else {
$pager_box = null;
}
return array(
- $locate_panel,
$browse_panel,
$pager_box,
);
}
private function renderCloneCommand(
PhabricatorRepository $repository,
$uri,
$serve_mode = null,
$manage_uri = null) {
require_celerity_resource('diffusion-icons-css');
Javelin::initBehavior('select-on-click');
switch ($repository->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
$command = csprintf(
'git clone %R',
$uri);
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
$command = csprintf(
'hg clone %R',
$uri);
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
if ($repository->isHosted()) {
$command = csprintf(
'svn checkout %R %R',
$uri,
$repository->getCloneName());
} else {
$command = csprintf(
'svn checkout %R',
$uri);
}
break;
}
$input = javelin_tag(
'input',
array(
'type' => 'text',
'value' => (string)$command,
'class' => 'diffusion-clone-uri',
'sigil' => 'select-on-click',
'readonly' => 'true',
));
$extras = array();
if ($serve_mode) {
if ($serve_mode === PhabricatorRepository::SERVE_READONLY) {
$extras[] = pht('(Read Only)');
}
}
if ($manage_uri) {
if ($this->getRequest()->getUser()->isLoggedIn()) {
$extras[] = phutil_tag(
'a',
array(
'href' => $manage_uri,
),
pht('Manage Credentials'));
}
}
if ($extras) {
$extras = phutil_implode_html(' ', $extras);
$extras = phutil_tag(
'div',
array(
'class' => 'diffusion-clone-extras',
),
$extras);
}
return array($input, $extras);
}
}
diff --git a/src/applications/diffusion/controller/DiffusionRepositoryCreateController.php b/src/applications/diffusion/controller/DiffusionRepositoryCreateController.php
index a9113fee13..ae28bf3993 100644
--- a/src/applications/diffusion/controller/DiffusionRepositoryCreateController.php
+++ b/src/applications/diffusion/controller/DiffusionRepositoryCreateController.php
@@ -1,826 +1,842 @@
<?php
final class DiffusionRepositoryCreateController
extends DiffusionRepositoryEditController {
private $edit;
private $repository;
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getUser();
$this->edit = $request->getURIData('edit');
// NOTE: We can end up here via either "Create Repository", or via
// "Import Repository", or via "Edit Remote", or via "Edit Policies". In
// the latter two cases, we show only a few of the pages.
$repository = null;
$service = null;
switch ($this->edit) {
case 'remote':
case 'policy':
$response = $this->loadDiffusionContextForEdit();
if ($response) {
return $response;
}
$repository = $this->getDiffusionRequest()->getRepository();
// Make sure we have CAN_EDIT.
PhabricatorPolicyFilter::requireCapability(
$viewer,
$repository,
PhabricatorPolicyCapability::CAN_EDIT);
$this->setRepository($repository);
$cancel_uri = $this->getRepositoryControllerURI($repository, 'edit/');
break;
case 'import':
case 'create':
$this->requireApplicationCapability(
DiffusionCreateRepositoriesCapability::CAPABILITY);
// Pick a random open service to allocate this repository on, if any
// exist. If there are no services, we aren't in cluster mode and
// will allocate locally. If there are services but none permit
// allocations, we fail.
$services = id(new AlmanacServiceQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withServiceTypes(
array(
AlmanacClusterRepositoryServiceType::SERVICETYPE,
))
->needProperties(true)
->execute();
if ($services) {
// Filter out services which do not permit new allocations.
foreach ($services as $key => $possible_service) {
if ($possible_service->getAlmanacPropertyValue('closed')) {
unset($services[$key]);
}
}
if (!$services) {
throw new Exception(
pht(
'This install is configured in cluster mode, but all '.
'available repository cluster services are closed to new '.
'allocations. At least one service must be open to allow '.
'new allocations to take place.'));
}
shuffle($services);
$service = head($services);
}
$cancel_uri = $this->getApplicationURI('new/');
break;
default:
throw new Exception(pht('Invalid edit operation!'));
}
$form = id(new PHUIPagedFormView())
->setUser($viewer)
->setCancelURI($cancel_uri);
switch ($this->edit) {
case 'remote':
$title = pht('Edit Remote');
$form
->addPage('remote-uri', $this->buildRemoteURIPage())
->addPage('auth', $this->buildAuthPage());
break;
case 'policy':
$title = pht('Edit Policies');
$form
->addPage('policy', $this->buildPolicyPage());
break;
case 'create':
$title = pht('Create Repository');
$form
->addPage('vcs', $this->buildVCSPage())
->addPage('name', $this->buildNamePage())
->addPage('policy', $this->buildPolicyPage())
->addPage('done', $this->buildDonePage());
break;
case 'import':
$title = pht('Import Repository');
$form
->addPage('vcs', $this->buildVCSPage())
->addPage('name', $this->buildNamePage())
->addPage('remote-uri', $this->buildRemoteURIPage())
->addPage('auth', $this->buildAuthPage())
->addPage('policy', $this->buildPolicyPage())
->addPage('done', $this->buildDonePage());
break;
}
if ($request->isFormPost()) {
$form->readFromRequest($request);
if ($form->isComplete()) {
$is_create = ($this->edit === 'import' || $this->edit === 'create');
$is_auth = ($this->edit == 'import' || $this->edit == 'remote');
$is_policy = ($this->edit != 'remote');
$is_init = ($this->edit == 'create');
if ($is_create) {
$repository = PhabricatorRepository::initializeNewRepository(
$viewer);
}
$template = id(new PhabricatorRepositoryTransaction());
$type_name = PhabricatorRepositoryTransaction::TYPE_NAME;
$type_vcs = PhabricatorRepositoryTransaction::TYPE_VCS;
$type_activate = PhabricatorRepositoryTransaction::TYPE_ACTIVATE;
$type_remote_uri = PhabricatorRepositoryTransaction::TYPE_REMOTE_URI;
$type_hosting = PhabricatorRepositoryTransaction::TYPE_HOSTING;
$type_http = PhabricatorRepositoryTransaction::TYPE_PROTOCOL_HTTP;
$type_ssh = PhabricatorRepositoryTransaction::TYPE_PROTOCOL_SSH;
$type_credential = PhabricatorRepositoryTransaction::TYPE_CREDENTIAL;
$type_view = PhabricatorTransactions::TYPE_VIEW_POLICY;
$type_edit = PhabricatorTransactions::TYPE_EDIT_POLICY;
$type_space = PhabricatorTransactions::TYPE_SPACE;
$type_push = PhabricatorRepositoryTransaction::TYPE_PUSH_POLICY;
$type_service = PhabricatorRepositoryTransaction::TYPE_SERVICE;
$xactions = array();
// If we're creating a new repository, set all this core stuff.
if ($is_create) {
$xactions[] = id(clone $template)
->setTransactionType($type_name)
->setNewValue(
$form->getPage('name')->getControl('name')->getValue());
$xactions[] = id(clone $template)
->setTransactionType($type_vcs)
->setNewValue(
$form->getPage('vcs')->getControl('vcs')->getValue());
$activate = $form->getPage('done')
->getControl('activate')->getValue();
$xactions[] = id(clone $template)
->setTransactionType($type_activate)
->setNewValue(($activate == 'start'));
if ($service) {
$xactions[] = id(clone $template)
->setTransactionType($type_service)
->setNewValue($service->getPHID());
}
}
if ($is_init) {
$xactions[] = id(clone $template)
->setTransactionType($type_hosting)
->setNewValue(true);
$vcs = $form->getPage('vcs')->getControl('vcs')->getValue();
if ($vcs != PhabricatorRepositoryType::REPOSITORY_TYPE_SVN) {
if (PhabricatorEnv::getEnvConfig('diffusion.allow-http-auth')) {
$v_http_mode = PhabricatorRepository::SERVE_READWRITE;
} else {
$v_http_mode = PhabricatorRepository::SERVE_OFF;
}
$xactions[] = id(clone $template)
->setTransactionType($type_http)
->setNewValue($v_http_mode);
}
if (PhabricatorEnv::getEnvConfig('diffusion.ssh-user')) {
$v_ssh_mode = PhabricatorRepository::SERVE_READWRITE;
} else {
$v_ssh_mode = PhabricatorRepository::SERVE_OFF;
}
$xactions[] = id(clone $template)
->setTransactionType($type_ssh)
->setNewValue($v_ssh_mode);
}
if ($is_auth) {
$xactions[] = id(clone $template)
->setTransactionType($type_remote_uri)
->setNewValue(
$form->getPage('remote-uri')->getControl('remoteURI')
->getValue());
$xactions[] = id(clone $template)
->setTransactionType($type_credential)
->setNewValue(
$form->getPage('auth')->getControl('credential')->getValue());
}
if ($is_policy) {
$policy_page = $form->getPage('policy');
$xactions[] = id(clone $template)
->setTransactionType($type_view)
->setNewValue($policy_page->getControl('viewPolicy')->getValue());
$xactions[] = id(clone $template)
->setTransactionType($type_edit)
->setNewValue($policy_page->getControl('editPolicy')->getValue());
if ($is_init || $repository->isHosted()) {
$xactions[] = id(clone $template)
->setTransactionType($type_push)
->setNewValue($policy_page->getControl('pushPolicy')->getValue());
}
$xactions[] = id(clone $template)
->setTransactionType($type_space)
->setNewValue(
$policy_page->getControl('viewPolicy')->getSpacePHID());
}
id(new PhabricatorRepositoryEditor())
->setContinueOnNoEffect(true)
->setContentSourceFromRequest($request)
->setActor($viewer)
->applyTransactions($repository, $xactions);
$repo_uri = $this->getRepositoryControllerURI($repository, 'edit/');
return id(new AphrontRedirectResponse())->setURI($repo_uri);
}
} else {
$dict = array();
if ($repository) {
$dict = array(
'remoteURI' => $repository->getRemoteURI(),
'credential' => $repository->getCredentialPHID(),
'viewPolicy' => $repository->getViewPolicy(),
'editPolicy' => $repository->getEditPolicy(),
'pushPolicy' => $repository->getPushPolicy(),
'spacePHID' => $repository->getSpacePHID(),
);
}
$form->readFromObject($dict);
}
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb($title);
+ $header = id(new PHUIHeaderView())
+ ->setHeader($title)
+ ->setHeaderIcon('fa-pencil');
+
+ $form_box = id(new PHUIObjectBoxView())
+ ->setHeaderText($title)
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
+ ->setForm($form);
+
+ $view = id(new PHUITwoColumnView())
+ ->setHeader($header)
+ ->setFooter(array(
+ $form,
+ ));
+
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
- ->appendChild($form);
+ ->appendChild($view);
+
}
/* -( Page: VCS Type )----------------------------------------------------- */
private function buildVCSPage() {
$is_import = ($this->edit == 'import');
if ($is_import) {
$git_str = pht(
'Import a Git repository (for example, a repository hosted '.
'on GitHub).');
$hg_str = pht(
'Import a Mercurial repository (for example, a repository '.
'hosted on Bitbucket).');
$svn_str = pht('Import a Subversion repository.');
} else {
$git_str = pht('Create a new, empty Git repository.');
$hg_str = pht('Create a new, empty Mercurial repository.');
$svn_str = pht('Create a new, empty Subversion repository.');
}
$control = id(new AphrontFormRadioButtonControl())
->setName('vcs')
->setLabel(pht('Type'))
->addButton(
PhabricatorRepositoryType::REPOSITORY_TYPE_GIT,
pht('Git'),
$git_str)
->addButton(
PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL,
pht('Mercurial'),
$hg_str)
->addButton(
PhabricatorRepositoryType::REPOSITORY_TYPE_SVN,
pht('Subversion'),
$svn_str);
return id(new PHUIFormPageView())
->setPageName(pht('Repository Type'))
->setUser($this->getRequest()->getUser())
->setValidateFormPageCallback(array($this, 'validateVCSPage'))
->addControl($control);
}
public function validateVCSPage(PHUIFormPageView $page) {
$valid = array(
PhabricatorRepositoryType::REPOSITORY_TYPE_GIT => true,
PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL => true,
PhabricatorRepositoryType::REPOSITORY_TYPE_SVN => true,
);
$c_vcs = $page->getControl('vcs');
$v_vcs = $c_vcs->getValue();
if (!$v_vcs) {
$c_vcs->setError(pht('Required'));
$page->addPageError(
pht('You must select a version control system.'));
} else if (empty($valid[$v_vcs])) {
$c_vcs->setError(pht('Invalid'));
$page->addPageError(
pht('You must select a valid version control system.'));
}
return $c_vcs->isValid();
}
/* -( Page: Name )--------------------------------------------------------- */
private function buildNamePage() {
return id(new PHUIFormPageView())
->setUser($this->getRequest()->getUser())
->setPageName(pht('Repository Name and Location'))
->setValidateFormPageCallback(array($this, 'validateNamePage'))
->addRemarkupInstructions(
pht(
'**Choose a human-readable name for this repository**, like '.
'"CompanyName Mobile App" or "CompanyName Backend Server". You '.
'can change this later.'))
->addControl(
id(new AphrontFormTextControl())
->setName('name')
->setLabel(pht('Name')));
}
public function validateNamePage(PHUIFormPageView $page) {
$c_name = $page->getControl('name');
$v_name = $c_name->getValue();
if (!strlen($v_name)) {
$c_name->setError(pht('Required'));
$page->addPageError(
pht('You must choose a name for this repository.'));
}
return $c_name->isValid();
}
/* -( Page: Remote URI )--------------------------------------------------- */
private function buildRemoteURIPage() {
return id(new PHUIFormPageView())
->setUser($this->getRequest()->getUser())
->setPageName(pht('Repository Remote URI'))
->setValidateFormPageCallback(array($this, 'validateRemoteURIPage'))
->setAdjustFormPageCallback(array($this, 'adjustRemoteURIPage'))
->addControl(
id(new AphrontFormTextControl())
->setName('remoteURI'));
}
public function adjustRemoteURIPage(PHUIFormPageView $page) {
$form = $page->getForm();
$is_git = false;
$is_svn = false;
$is_mercurial = false;
if ($this->getRepository()) {
$vcs = $this->getRepository()->getVersionControlSystem();
} else {
$vcs = $form->getPage('vcs')->getControl('vcs')->getValue();
}
switch ($vcs) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
$is_git = true;
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
$is_svn = true;
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
$is_mercurial = true;
break;
default:
throw new Exception(pht('Unsupported VCS!'));
}
$has_local = ($is_git || $is_mercurial);
if ($is_git) {
$uri_label = pht('Remote URI');
$instructions = pht(
'Enter the URI to clone this Git repository from. It should usually '.
'look like one of these examples:'.
"\n\n".
"| Example Git Remote URIs |\n".
"| ----------------------- |\n".
"| `git@github.com:example/example.git` |\n".
"| `ssh://user@host.com/git/example.git` |\n".
"| `https://example.com/repository.git` |\n");
} else if ($is_mercurial) {
$uri_label = pht('Remote URI');
$instructions = pht(
'Enter the URI to clone this Mercurial repository from. It should '.
'usually look like one of these examples:'.
"\n\n".
"| Example Mercurial Remote URIs |\n".
"| ----------------------- |\n".
"| `ssh://hg@bitbucket.org/example/repository` |\n".
"| `https://bitbucket.org/example/repository` |\n");
} else if ($is_svn) {
$uri_label = pht('Repository Root');
$instructions = pht(
'Enter the **Repository Root** for this Subversion repository. '.
'You can figure this out by running `svn info` in a working copy '.
'and looking at the value in the `Repository Root` field. It '.
'should be a URI and will usually look like these:'.
"\n\n".
"| Example Subversion Repository Root URIs |\n".
"| ------------------------------ |\n".
"| `http://svn.example.org/svnroot/` |\n".
"| `svn+ssh://svn.example.com/svnroot/` |\n".
"| `svn://svn.example.net/svnroot/` |\n".
"\n\n".
"You **MUST** specify the root of the repository, not a ".
"subdirectory. (If you want to import only part of a Subversion ".
"repository, use the //Import Only// option at the end of this ".
"workflow.)");
} else {
throw new Exception(pht('Unsupported VCS!'));
}
$page->addRemarkupInstructions($instructions, 'remoteURI');
$page->getControl('remoteURI')->setLabel($uri_label);
}
public function validateRemoteURIPage(PHUIFormPageView $page) {
$c_remote = $page->getControl('remoteURI');
$v_remote = $c_remote->getValue();
if (!strlen($v_remote)) {
$c_remote->setError(pht('Required'));
$page->addPageError(
pht('You must specify a URI.'));
} else {
try {
PhabricatorRepository::assertValidRemoteURI($v_remote);
} catch (Exception $ex) {
$c_remote->setError(pht('Invalid'));
$page->addPageError($ex->getMessage());
}
}
return $c_remote->isValid();
}
/* -( Page: Authentication )----------------------------------------------- */
public function buildAuthPage() {
return id(new PHUIFormPageView())
->setPageName(pht('Authentication'))
->setUser($this->getRequest()->getUser())
->setAdjustFormPageCallback(array($this, 'adjustAuthPage'))
->addControl(
id(new PassphraseCredentialControl())
->setName('credential'));
}
public function adjustAuthPage($page) {
$form = $page->getForm();
if ($this->getRepository()) {
$vcs = $this->getRepository()->getVersionControlSystem();
} else {
$vcs = $form->getPage('vcs')->getControl('vcs')->getValue();
}
$remote_uri = $form->getPage('remote-uri')
->getControl('remoteURI')
->getValue();
$proto = PhabricatorRepository::getRemoteURIProtocol($remote_uri);
$remote_user = $this->getRemoteURIUser($remote_uri);
$c_credential = $page->getControl('credential');
$c_credential->setDefaultUsername($remote_user);
if ($this->isSSHProtocol($proto)) {
$c_credential->setLabel(pht('SSH Key'));
$c_credential->setCredentialType(
PassphraseSSHPrivateKeyTextCredentialType::CREDENTIAL_TYPE);
$provides_type = PassphraseSSHPrivateKeyCredentialType::PROVIDES_TYPE;
$page->addRemarkupInstructions(
pht(
'Choose or add the SSH credentials to use to connect to the '.
'repository hosted at:'.
"\n\n".
" lang=text\n".
" %s",
$remote_uri),
'credential');
} else if ($this->isUsernamePasswordProtocol($proto)) {
$c_credential->setLabel(pht('Password'));
$c_credential->setAllowNull(true);
$c_credential->setCredentialType(
PassphrasePasswordCredentialType::CREDENTIAL_TYPE);
$provides_type = PassphrasePasswordCredentialType::PROVIDES_TYPE;
$page->addRemarkupInstructions(
pht(
'Choose the username and password used to connect to the '.
'repository hosted at:'.
"\n\n".
" lang=text\n".
" %s".
"\n\n".
"If this repository does not require a username or password, ".
"you can continue to the next step.",
$remote_uri),
'credential');
} else {
throw new Exception(pht('Unknown URI protocol!'));
}
if ($provides_type) {
$viewer = $this->getRequest()->getUser();
$options = id(new PassphraseCredentialQuery())
->setViewer($viewer)
->withIsDestroyed(false)
->withProvidesTypes(array($provides_type))
->execute();
$c_credential->setOptions($options);
}
}
public function validateAuthPage(PHUIFormPageView $page) {
$form = $page->getForm();
$remote_uri = $form->getPage('remote')->getControl('remoteURI')->getValue();
$proto = $this->getRemoteURIProtocol($remote_uri);
$c_credential = $page->getControl('credential');
$v_credential = $c_credential->getValue();
// NOTE: We're using the omnipotent user here because the viewer might be
// editing a repository they're allowed to edit which uses a credential they
// are not allowed to see. This is fine, as long as they don't change it.
$credential = id(new PassphraseCredentialQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withPHIDs(array($v_credential))
->executeOne();
if ($this->isSSHProtocol($proto)) {
if (!$credential) {
$c_credential->setError(pht('Required'));
$page->addPageError(
pht('You must choose an SSH credential to connect over SSH.'));
}
$ssh_type = PassphraseSSHPrivateKeyCredentialType::PROVIDES_TYPE;
if ($credential->getProvidesType() !== $ssh_type) {
$c_credential->setError(pht('Invalid'));
$page->addPageError(
pht(
'You must choose an SSH credential, not some other type '.
'of credential.'));
}
} else if ($this->isUsernamePasswordProtocol($proto)) {
if ($credential) {
$password_type = PassphrasePasswordCredentialType::PROVIDES_TYPE;
if ($credential->getProvidesType() !== $password_type) {
$c_credential->setError(pht('Invalid'));
$page->addPageError(
pht(
'You must choose a username/password credential, not some other '.
'type of credential.'));
}
}
return $c_credential->isValid();
} else {
return true;
}
}
/* -( Page: Policy )------------------------------------------------------- */
private function buildPolicyPage() {
$viewer = $this->getRequest()->getUser();
if ($this->getRepository()) {
$repository = $this->getRepository();
} else {
$repository = PhabricatorRepository::initializeNewRepository($viewer);
}
$policies = id(new PhabricatorPolicyQuery())
->setViewer($viewer)
->setObject($repository)
->execute();
$view_policy = id(new AphrontFormPolicyControl())
->setUser($viewer)
->setCapability(PhabricatorPolicyCapability::CAN_VIEW)
->setPolicyObject($repository)
->setPolicies($policies)
->setName('viewPolicy');
$edit_policy = id(new AphrontFormPolicyControl())
->setUser($viewer)
->setCapability(PhabricatorPolicyCapability::CAN_EDIT)
->setPolicyObject($repository)
->setPolicies($policies)
->setName('editPolicy');
$push_policy = id(new AphrontFormPolicyControl())
->setUser($viewer)
->setCapability(DiffusionPushCapability::CAPABILITY)
->setPolicyObject($repository)
->setPolicies($policies)
->setName('pushPolicy');
return id(new PHUIFormPageView())
->setPageName(pht('Policies'))
->setValidateFormPageCallback(array($this, 'validatePolicyPage'))
->setAdjustFormPageCallback(array($this, 'adjustPolicyPage'))
->setUser($viewer)
->addRemarkupInstructions(
pht('Select access policies for this repository.'))
->addControl($view_policy)
->addControl($edit_policy)
->addControl($push_policy);
}
public function adjustPolicyPage(PHUIFormPageView $page) {
if ($this->getRepository()) {
$repository = $this->getRepository();
$show_push = $repository->isHosted();
} else {
$show_push = ($this->edit == 'create');
}
if (!$show_push) {
$c_push = $page->getControl('pushPolicy');
$c_push->setHidden(true);
}
}
public function validatePolicyPage(PHUIFormPageView $page) {
$form = $page->getForm();
$viewer = $this->getRequest()->getUser();
$c_view = $page->getControl('viewPolicy');
$c_edit = $page->getControl('editPolicy');
$c_push = $page->getControl('pushPolicy');
$v_view = $c_view->getValue();
$v_edit = $c_edit->getValue();
$v_push = $c_push->getValue();
if ($this->getRepository()) {
$repository = $this->getRepository();
} else {
$repository = PhabricatorRepository::initializeNewRepository($viewer);
}
$proxy = clone $repository;
$proxy->setViewPolicy($v_view);
$proxy->setEditPolicy($v_edit);
$can_view = PhabricatorPolicyFilter::hasCapability(
$viewer,
$proxy,
PhabricatorPolicyCapability::CAN_VIEW);
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
$proxy,
PhabricatorPolicyCapability::CAN_EDIT);
if (!$can_view) {
$c_view->setError(pht('Invalid'));
$page->addPageError(
pht(
'You can not use the selected policy, because you would be unable '.
'to see the repository.'));
}
if (!$can_edit) {
$c_edit->setError(pht('Invalid'));
$page->addPageError(
pht(
'You can not use the selected edit policy, because you would be '.
'unable to edit the repository.'));
}
return $c_view->isValid() &&
$c_edit->isValid();
}
/* -( Page: Done )--------------------------------------------------------- */
private function buildDonePage() {
$is_create = ($this->edit == 'create');
if ($is_create) {
$now_label = pht('Create Repository Now');
$now_caption = pht(
'Create the repository right away. This will create the repository '.
'using default settings.');
$wait_label = pht('Configure More Options First');
$wait_caption = pht(
'Configure more options before creating the repository. '.
'This will let you fine-tune settings. You can create the repository '.
'whenever you are ready.');
} else {
$now_label = pht('Start Import Now');
$now_caption = pht(
'Start importing the repository right away. This will import '.
'the entire repository using default settings.');
$wait_label = pht('Configure More Options First');
$wait_caption = pht(
'Configure more options before beginning the repository '.
'import. This will let you fine-tune settings. You can '.
'start the import whenever you are ready.');
}
return id(new PHUIFormPageView())
->setPageName(pht('Repository Ready!'))
->setValidateFormPageCallback(array($this, 'validateDonePage'))
->setUser($this->getRequest()->getUser())
->addControl(
id(new AphrontFormRadioButtonControl())
->setName('activate')
->setLabel(pht('Start Now'))
->addButton(
'start',
$now_label,
$now_caption)
->addButton(
'wait',
$wait_label,
$wait_caption));
}
public function validateDonePage(PHUIFormPageView $page) {
$c_activate = $page->getControl('activate');
$v_activate = $c_activate->getValue();
if ($v_activate != 'start' && $v_activate != 'wait') {
$c_activate->setError(pht('Required'));
$page->addPageError(
pht('Make a choice about repository activation.'));
}
return $c_activate->isValid();
}
/* -( Internal )----------------------------------------------------------- */
private function getRemoteURIUser($raw_uri) {
$uri = new PhutilURI($raw_uri);
if ($uri->getUser()) {
return $uri->getUser();
}
$git_uri = new PhutilGitURI($raw_uri);
if (strlen($git_uri->getDomain()) && strlen($git_uri->getPath())) {
return $git_uri->getUser();
}
return null;
}
private function isSSHProtocol($proto) {
return ($proto == 'git' || $proto == 'ssh' || $proto == 'svn+ssh');
}
private function isUsernamePasswordProtocol($proto) {
return ($proto == 'http' || $proto == 'https' || $proto == 'svn');
}
private function setRepository(PhabricatorRepository $repository) {
$this->repository = $repository;
return $this;
}
private function getRepository() {
return $this->repository;
}
}
diff --git a/src/applications/diffusion/controller/DiffusionRepositoryEditActionsController.php b/src/applications/diffusion/controller/DiffusionRepositoryEditActionsController.php
index 8459498374..b8f95f36fc 100644
--- a/src/applications/diffusion/controller/DiffusionRepositoryEditActionsController.php
+++ b/src/applications/diffusion/controller/DiffusionRepositoryEditActionsController.php
@@ -1,109 +1,121 @@
<?php
final class DiffusionRepositoryEditActionsController
extends DiffusionRepositoryEditController {
public function handleRequest(AphrontRequest $request) {
$response = $this->loadDiffusionContextForEdit();
if ($response) {
return $response;
}
$viewer = $this->getViewer();
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$edit_uri = $this->getRepositoryControllerURI($repository, 'edit/');
// NOTE: We're inverting these here, because the storage is silly.
$v_notify = !$repository->getHumanReadableDetail('herald-disabled');
$v_autoclose = !$repository->getHumanReadableDetail('disable-autoclose');
if ($request->isFormPost()) {
$v_notify = $request->getBool('notify');
$v_autoclose = $request->getBool('autoclose');
$xactions = array();
$template = id(new PhabricatorRepositoryTransaction());
$type_notify = PhabricatorRepositoryTransaction::TYPE_NOTIFY;
$type_autoclose = PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE;
$xactions[] = id(clone $template)
->setTransactionType($type_notify)
->setNewValue($v_notify);
$xactions[] = id(clone $template)
->setTransactionType($type_autoclose)
->setNewValue($v_autoclose);
id(new PhabricatorRepositoryEditor())
->setContinueOnNoEffect(true)
->setContentSourceFromRequest($request)
->setActor($viewer)
->applyTransactions($repository, $xactions);
return id(new AphrontRedirectResponse())->setURI($edit_uri);
}
$content = array();
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(pht('Edit Actions'));
$title = pht('Edit Actions (%s)', $repository->getName());
+ $header = id(new PHUIHeaderView())
+ ->setHeader($title)
+ ->setHeaderIcon('fa-pencil');
+
$policies = id(new PhabricatorPolicyQuery())
->setViewer($viewer)
->setObject($repository)
->execute();
$form = id(new AphrontFormView())
->setUser($viewer)
->appendRemarkupInstructions(
pht(
"Normally, Phabricator publishes notifications when it discovers ".
"new commits. You can disable publishing for this repository by ".
"turning off **Notify/Publish**. This will disable notifications, ".
"feed, and Herald (including audits and build plans) for this ".
"repository.\n\n".
"When Phabricator discovers a new commit, it can automatically ".
"close associated revisions and tasks. If you don't want ".
"Phabricator to close objects when it discovers new commits in ".
"this repository, you can disable **Autoclose**."))
->appendChild(
id(new AphrontFormSelectControl())
->setName('notify')
->setLabel(pht('Notify/Publish'))
->setValue((int)$v_notify)
->setOptions(
array(
1 => pht('Enable Notifications, Feed and Herald'),
0 => pht('Disable Notifications, Feed and Herald'),
)))
->appendChild(
id(new AphrontFormSelectControl())
->setName('autoclose')
->setLabel(pht('Autoclose'))
->setValue((int)$v_autoclose)
->setOptions(
array(
1 => pht('Enable Autoclose'),
0 => pht('Disable Autoclose'),
)))
->appendChild(
id(new AphrontFormSubmitControl())
->setValue(pht('Save Actions'))
->addCancelButton($edit_uri));
$form_box = id(new PHUIObjectBoxView())
- ->setHeaderText($title)
+ ->setHeaderText(pht('Actions'))
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setForm($form);
+ $view = id(new PHUITwoColumnView())
+ ->setHeader($header)
+ ->setFooter(array(
+ $form_box,
+ ));
+
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
- ->appendChild($form_box);
+ ->appendChild($view);
+
}
}
diff --git a/src/applications/diffusion/controller/DiffusionRepositoryEditAutomationController.php b/src/applications/diffusion/controller/DiffusionRepositoryEditAutomationController.php
index e47bde3902..038cc0f0cd 100644
--- a/src/applications/diffusion/controller/DiffusionRepositoryEditAutomationController.php
+++ b/src/applications/diffusion/controller/DiffusionRepositoryEditAutomationController.php
@@ -1,82 +1,93 @@
<?php
final class DiffusionRepositoryEditAutomationController
extends DiffusionRepositoryEditController {
public function handleRequest(AphrontRequest $request) {
$response = $this->loadDiffusionContextForEdit();
if ($response) {
return $response;
}
$viewer = $this->getViewer();
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
if (!$repository->supportsAutomation()) {
return new Aphront404Response();
}
$edit_uri = $this->getRepositoryControllerURI($repository, 'edit/');
$v_blueprints = $repository->getHumanReadableDetail(
'automation.blueprintPHIDs');
if ($request->isFormPost()) {
$v_blueprints = $request->getArr('blueprintPHIDs');
$xactions = array();
$template = id(new PhabricatorRepositoryTransaction());
$type_blueprints =
PhabricatorRepositoryTransaction::TYPE_AUTOMATION_BLUEPRINTS;
$xactions[] = id(clone $template)
->setTransactionType($type_blueprints)
->setNewValue($v_blueprints);
id(new PhabricatorRepositoryEditor())
->setContinueOnNoEffect(true)
->setContentSourceFromRequest($request)
->setActor($viewer)
->applyTransactions($repository, $xactions);
return id(new AphrontRedirectResponse())->setURI($edit_uri);
}
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(pht('Edit Automation'));
$title = pht('Edit %s', $repository->getName());
+ $header = id(new PHUIHeaderView())
+ ->setHeader($title)
+ ->setHeaderIcon('fa-pencil');
+
$form = id(new AphrontFormView())
->setUser($viewer)
->appendRemarkupInstructions(
pht(
"Configure **Repository Automation** to allow Phabricator to ".
"write to this repository.".
"\n\n".
"IMPORTANT: This feature is new, experimental, and not supported. ".
"Use it at your own risk."))
->appendControl(
id(new AphrontFormTokenizerControl())
->setLabel(pht('Use Blueprints'))
->setName('blueprintPHIDs')
->setValue($v_blueprints)
->setDatasource(new DrydockBlueprintDatasource()))
->appendChild(
id(new AphrontFormSubmitControl())
->setValue(pht('Save'))
->addCancelButton($edit_uri));
- $object_box = id(new PHUIObjectBoxView())
- ->setHeaderText($title)
+ $form_box = id(new PHUIObjectBoxView())
+ ->setHeaderText(pht('Automation'))
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setForm($form);
+ $view = id(new PHUITwoColumnView())
+ ->setHeader($header)
+ ->setFooter(array(
+ $form_box,
+ ));
+
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
- ->appendChild($object_box);
+ ->appendChild($view);
}
}
diff --git a/src/applications/diffusion/controller/DiffusionRepositoryEditBasicController.php b/src/applications/diffusion/controller/DiffusionRepositoryEditBasicController.php
index e23a57e655..10f4b13ef9 100644
--- a/src/applications/diffusion/controller/DiffusionRepositoryEditBasicController.php
+++ b/src/applications/diffusion/controller/DiffusionRepositoryEditBasicController.php
@@ -1,182 +1,193 @@
<?php
final class DiffusionRepositoryEditBasicController
extends DiffusionRepositoryEditController {
public function handleRequest(AphrontRequest $request) {
$response = $this->loadDiffusionContextForEdit();
if ($response) {
return $response;
}
$viewer = $request->getUser();
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$edit_uri = $this->getRepositoryControllerURI($repository, 'edit/');
$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;
if ($request->isFormPost()) {
$v_name = $request->getStr('name');
$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');
$errors[] = pht('Repository name is required.');
} else {
$e_name = null;
}
if (!$errors) {
$xactions = array();
$template = id(new PhabricatorRepositoryTransaction());
$type_name = PhabricatorRepositoryTransaction::TYPE_NAME;
$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)
->setNewValue($v_name);
$xactions[] = id(clone $template)
->setTransactionType($type_desc)
->setNewValue($v_desc);
$xactions[] = id(clone $template)
->setTransactionType($type_slug)
->setNewValue($v_slug);
$xactions[] = id(clone $template)
->setTransactionType($type_callsign)
->setNewValue($v_callsign);
$xactions[] = id(clone $template)
->setTransactionType($type_edge)
->setMetadataValue(
'edge:type',
PhabricatorProjectObjectHasProjectEdgeType::EDGECONST)
->setNewValue(
array(
'=' => array_fuse($v_projects),
));
$editor = id(new PhabricatorRepositoryEditor())
->setContinueOnNoEffect(true)
->setContentSourceFromRequest($request)
->setActor($viewer);
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);
}
}
}
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(pht('Edit Basics'));
$title = pht('Edit %s', $repository->getName());
+ $header = id(new PHUIHeaderView())
+ ->setHeader($title)
+ ->setHeaderIcon('fa-pencil');
+
$form = id(new AphrontFormView())
->setUser($viewer)
->appendChild(
id(new AphrontFormTextControl())
->setName('name')
->setLabel(pht('Name'))
->setValue($v_name)
->setError($e_name))
->appendChild(
id(new AphrontFormTextControl())
->setName('slug')
->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)
->setName('description')
->setLabel(pht('Description'))
->setValue($v_desc))
->appendControl(
id(new AphrontFormTokenizerControl())
->setDatasource(new PhabricatorProjectDatasource())
->setName('projectPHIDs')
->setLabel(pht('Projects'))
->setValue($v_projects))
->appendChild(
id(new AphrontFormSubmitControl())
->setValue(pht('Save'))
->addCancelButton($edit_uri))
->appendChild(id(new PHUIFormDividerControl()))
->appendRemarkupInstructions($this->getReadmeInstructions());
- $object_box = id(new PHUIObjectBoxView())
- ->setHeaderText($title)
+ $form_box = id(new PHUIObjectBoxView())
+ ->setHeaderText(pht('Basic Information'))
->setValidationException($validation_exception)
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setForm($form)
->setFormErrors($errors);
+ $view = id(new PHUITwoColumnView())
+ ->setHeader($header)
+ ->setFooter(array(
+ $form_box,
+ ));
+
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
- ->appendChild($object_box);
+ ->appendChild($view);
}
private function getReadmeInstructions() {
return pht(<<<EOTEXT
You can also create a `%s` file at the repository root (or in any
subdirectory) to provide information about the repository. These formats are
supported:
| File Name | Rendered As... |
|-----------|-----------------|
| `%s` | Plain Text |
| `%s` | Plain Text |
| `%s` | Remarkup |
| `%s` | Remarkup |
| `%s` | \xC2\xA1Fiesta! |
EOTEXT
,
'README',
'README',
'README.txt',
'README.remarkup',
'README.md',
'README.rainbow');
}
}
diff --git a/src/applications/diffusion/controller/DiffusionRepositoryEditBranchesController.php b/src/applications/diffusion/controller/DiffusionRepositoryEditBranchesController.php
index c256336ec2..927af295d4 100644
--- a/src/applications/diffusion/controller/DiffusionRepositoryEditBranchesController.php
+++ b/src/applications/diffusion/controller/DiffusionRepositoryEditBranchesController.php
@@ -1,238 +1,248 @@
<?php
final class DiffusionRepositoryEditBranchesController
extends DiffusionRepositoryEditController {
public function handleRequest(AphrontRequest $request) {
$response = $this->loadDiffusionContextForEdit();
if ($response) {
return $response;
}
$viewer = $this->getViewer();
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$is_git = false;
$is_hg = false;
switch ($repository->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
$is_git = true;
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
$is_hg = true;
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
throw new Exception(
pht('Subversion does not support branches!'));
default:
throw new Exception(
pht('Repository has unknown version control system!'));
}
$edit_uri = $this->getRepositoryControllerURI($repository, 'edit/');
$v_default = $repository->getHumanReadableDetail('default-branch');
$v_track = $repository->getDetail(
'branch-filter',
array());
$v_track = array_keys($v_track);
$v_autoclose = $repository->getDetail(
'close-commits-filter',
array());
$v_autoclose = array_keys($v_autoclose);
$e_track = null;
$e_autoclose = null;
$validation_exception = null;
if ($request->isFormPost()) {
$v_default = $request->getStr('default');
$v_track = $this->processBranches($request->getStr('track'));
if (!$is_hg) {
$v_autoclose = $this->processBranches($request->getStr('autoclose'));
}
$xactions = array();
$template = id(new PhabricatorRepositoryTransaction());
$type_default = PhabricatorRepositoryTransaction::TYPE_DEFAULT_BRANCH;
$type_track = PhabricatorRepositoryTransaction::TYPE_TRACK_ONLY;
$type_autoclose = PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE_ONLY;
$xactions[] = id(clone $template)
->setTransactionType($type_default)
->setNewValue($v_default);
$xactions[] = id(clone $template)
->setTransactionType($type_track)
->setNewValue($v_track);
if (!$is_hg) {
$xactions[] = id(clone $template)
->setTransactionType($type_autoclose)
->setNewValue($v_autoclose);
}
$editor = id(new PhabricatorRepositoryEditor())
->setContinueOnNoEffect(true)
->setContentSourceFromRequest($request)
->setActor($viewer);
try {
$editor->applyTransactions($repository, $xactions);
return id(new AphrontRedirectResponse())->setURI($edit_uri);
} catch (PhabricatorApplicationTransactionValidationException $ex) {
$validation_exception = $ex;
$e_track = $validation_exception->getShortMessage($type_track);
$e_autoclose = $validation_exception->getShortMessage($type_autoclose);
}
}
$content = array();
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(pht('Edit Branches'));
$title = pht('Edit Branches (%s)', $repository->getName());
+ $header = id(new PHUIHeaderView())
+ ->setHeader($title)
+ ->setHeaderIcon('fa-pencil');
$policies = id(new PhabricatorPolicyQuery())
->setViewer($viewer)
->setObject($repository)
->execute();
$rows = array();
$rows[] = array(
array(
'master',
),
pht('Select only master.'),
);
$rows[] = array(
array(
'master',
'develop',
'release',
),
pht('Select %s, %s, and %s.', 'master', 'develop', 'release'),
);
$rows[] = array(
array(
'master',
'regexp(/^release-/)',
),
pht('Select master, and all branches which start with "%s".', 'release-'),
);
$rows[] = array(
array(
'regexp(/^(?!temp-)/)',
),
pht('Select all branches which do not start with "%s".', 'temp-'),
);
foreach ($rows as $k => $row) {
$rows[$k][0] = phutil_tag(
'pre',
array(),
implode("\n", $row[0]));
}
$example_table = id(new AphrontTableView($rows))
->setHeaders(
array(
pht('Example'),
pht('Effect'),
))
->setColumnClasses(
array(
'',
'wide',
));
$v_track = implode("\n", $v_track);
$v_autoclose = implode("\n", $v_autoclose);
$form = id(new AphrontFormView())
->setUser($viewer)
->appendRemarkupInstructions(
pht('You can choose a **Default Branch** for viewing this repository.'))
->appendChild(
id(new AphrontFormTextControl())
->setName('default')
->setLabel(pht('Default Branch'))
->setValue($v_default))
->appendRemarkupInstructions(
pht(
'If you want to import only some branches into Diffusion, you can '.
'list them in **Track Only**. Other branches will be ignored. If '.
'you do not specify any branches, all branches are tracked.'));
if (!$is_hg) {
$form->appendRemarkupInstructions(
pht(
'If you have **Autoclose** enabled for this repository, Phabricator '.
'can close tasks and revisions when corresponding commits are '.
'pushed to the repository. If you want to autoclose objects only '.
'when commits appear on specific branches, you can list those '.
'branches in **Autoclose Only**. By default, all tracked branches '.
'will autoclose objects.'));
}
$form
->appendRemarkupInstructions(
pht(
'When specifying branches, you should enter one branch name per '.
'line. You can use regular expressions to match branches by '.
'wrapping an expression in `%s`. For example:',
'regexp(...)'))
->appendChild(
id(new AphrontFormMarkupControl())
->setValue($example_table))
->appendChild(
id(new AphrontFormTextAreaControl())
->setName('track')
->setLabel(pht('Track Only'))
->setError($e_track)
->setValue($v_track));
if (!$is_hg) {
$form->appendChild(
id(new AphrontFormTextAreaControl())
->setName('autoclose')
->setLabel(pht('Autoclose Only'))
->setError($e_autoclose)
->setValue($v_autoclose));
}
$form->appendChild(
id(new AphrontFormSubmitControl())
->setValue(pht('Save Branches'))
->addCancelButton($edit_uri));
$form_box = id(new PHUIObjectBoxView())
+ ->setHeaderText(pht('Branches'))
->setValidationException($validation_exception)
- ->setHeaderText($title)
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setForm($form);
+ $view = id(new PHUITwoColumnView())
+ ->setHeader($header)
+ ->setFooter(array(
+ $form_box,
+ ));
+
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
- ->appendChild($form_box);
+ ->appendChild($view);
}
private function processBranches($string) {
$lines = phutil_split_lines($string, $retain_endings = false);
foreach ($lines as $key => $line) {
$lines[$key] = trim($line);
if (!strlen($lines[$key])) {
unset($lines[$key]);
}
}
return array_values($lines);
}
}
diff --git a/src/applications/diffusion/controller/DiffusionRepositoryEditController.php b/src/applications/diffusion/controller/DiffusionRepositoryEditController.php
index 1e3cb553da..714568f187 100644
--- a/src/applications/diffusion/controller/DiffusionRepositoryEditController.php
+++ b/src/applications/diffusion/controller/DiffusionRepositoryEditController.php
@@ -1,27 +1,28 @@
<?php
abstract class DiffusionRepositoryEditController
extends DiffusionController {
protected function buildApplicationCrumbs($is_main = false) {
$crumbs = parent::buildApplicationCrumbs();
if ($this->hasDiffusionRequest()) {
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$repo_uri = $repository->getURI();
$edit_uri = $this->getRepositoryControllerURI($repository, 'edit/');
$crumbs->addTextCrumb($repository->getDisplayname(), $repo_uri);
if ($is_main) {
$crumbs->addTextCrumb(pht('Edit Repository'));
} else {
$crumbs->addTextCrumb(pht('Edit'), $edit_uri);
}
}
+ $crumbs->setBorder(true);
return $crumbs;
}
}
diff --git a/src/applications/diffusion/controller/DiffusionRepositoryEditEncodingController.php b/src/applications/diffusion/controller/DiffusionRepositoryEditEncodingController.php
index 0059c9d6c0..256e69ac59 100644
--- a/src/applications/diffusion/controller/DiffusionRepositoryEditEncodingController.php
+++ b/src/applications/diffusion/controller/DiffusionRepositoryEditEncodingController.php
@@ -1,97 +1,107 @@
<?php
final class DiffusionRepositoryEditEncodingController
extends DiffusionRepositoryEditController {
public function handleRequest(AphrontRequest $request) {
$response = $this->loadDiffusionContextForEdit();
if ($response) {
return $response;
}
$user = $this->getViewer();
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$edit_uri = $this->getRepositoryControllerURI($repository, 'edit/');
$v_encoding = $repository->getDetail('encoding');
$e_encoding = null;
$errors = array();
if ($request->isFormPost()) {
$v_encoding = $request->getStr('encoding');
if (!$errors) {
$xactions = array();
$template = id(new PhabricatorRepositoryTransaction());
$type_encoding = PhabricatorRepositoryTransaction::TYPE_ENCODING;
$xactions[] = id(clone $template)
->setTransactionType($type_encoding)
->setNewValue($v_encoding);
try {
id(new PhabricatorRepositoryEditor())
->setContinueOnNoEffect(true)
->setContentSourceFromRequest($request)
->setActor($user)
->applyTransactions($repository, $xactions);
return id(new AphrontRedirectResponse())->setURI($edit_uri);
} catch (Exception $ex) {
$errors[] = $ex->getMessage();
}
}
}
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(pht('Edit Encoding'));
$title = pht('Edit %s', $repository->getName());
+ $header = id(new PHUIHeaderView())
+ ->setHeader($title)
+ ->setHeaderIcon('fa-pencil');
$form = id(new AphrontFormView())
->setUser($user)
->appendRemarkupInstructions($this->getEncodingInstructions())
->appendChild(
id(new AphrontFormTextControl())
->setName('encoding')
->setLabel(pht('Text Encoding'))
->setValue($v_encoding)
->setError($e_encoding))
->appendChild(
id(new AphrontFormSubmitControl())
->setValue(pht('Save Encoding'))
->addCancelButton($edit_uri));
- $object_box = id(new PHUIObjectBoxView())
- ->setHeaderText($title)
+ $form_box = id(new PHUIObjectBoxView())
+ ->setHeaderText(pht('Encoding'))
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setForm($form)
->setFormErrors($errors);
+ $view = id(new PHUITwoColumnView())
+ ->setHeader($header)
+ ->setFooter(array(
+ $form_box,
+ ));
+
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
- ->appendChild($object_box);
+ ->appendChild($view);
}
private function getEncodingInstructions() {
return pht(<<<EOT
If source code in this repository uses a character encoding other than UTF-8
(for example, `ISO-8859-1`), specify it here.
**Normally, you can leave this field blank.** If your source code is written in
ASCII or UTF-8, everything will work correctly.
Source files will be translated from the specified encoding to UTF-8 when they
are read from the repository, before they are displayed in Diffusion.
See [[%s | UTF-8 and Character Encoding]] for more information on how
Phabricator handles text encodings.
EOT
,
PhabricatorEnv::getDoclink('User Guide: UTF-8 and Character Encoding'));
}
}
diff --git a/src/applications/diffusion/controller/DiffusionRepositoryEditHostingController.php b/src/applications/diffusion/controller/DiffusionRepositoryEditHostingController.php
index be40b794b3..0c759eba59 100644
--- a/src/applications/diffusion/controller/DiffusionRepositoryEditHostingController.php
+++ b/src/applications/diffusion/controller/DiffusionRepositoryEditHostingController.php
@@ -1,269 +1,288 @@
<?php
final class DiffusionRepositoryEditHostingController
extends DiffusionRepositoryEditController {
private $serve;
public function handleRequest(AphrontRequest $request) {
$response = $this->loadDiffusionContextForEdit();
if ($response) {
return $response;
}
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$this->serve = $request->getURIData('serve');
if (!$this->serve) {
return $this->handleHosting($repository);
} else {
return $this->handleProtocols($repository);
}
}
public function handleHosting(PhabricatorRepository $repository) {
$request = $this->getRequest();
$user = $request->getUser();
$v_hosting = $repository->isHosted();
$edit_uri = $this->getRepositoryControllerURI($repository, 'edit/');
$next_uri = $this->getRepositoryControllerURI($repository, 'edit/serve/');
if ($request->isFormPost()) {
$v_hosting = $request->getBool('hosting');
$xactions = array();
$template = id(new PhabricatorRepositoryTransaction());
$type_hosting = PhabricatorRepositoryTransaction::TYPE_HOSTING;
$xactions[] = id(clone $template)
->setTransactionType($type_hosting)
->setNewValue($v_hosting);
id(new PhabricatorRepositoryEditor())
->setContinueOnNoEffect(true)
->setContentSourceFromRequest($request)
->setActor($user)
->applyTransactions($repository, $xactions);
return id(new AphrontRedirectResponse())->setURI($next_uri);
}
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(pht('Edit Hosting'));
$title = pht('Edit Hosting (%s)', $repository->getName());
+ $header = id(new PHUIHeaderView())
+ ->setHeader($title)
+ ->setHeaderIcon('fa-pencil');
$hosted_control = id(new AphrontFormRadioButtonControl())
->setName('hosting')
->setLabel(pht('Hosting'))
->addButton(
true,
pht('Host Repository on Phabricator'),
pht(
'Phabricator will host this repository. Users will be able to '.
'push commits to Phabricator. Phabricator will not pull '.
'changes from elsewhere.'))
->addButton(
false,
pht('Host Repository Elsewhere'),
pht(
'Phabricator will pull updates to this repository from a master '.
'repository elsewhere (for example, on GitHub or Bitbucket). '.
'Users will not be able to push commits to this repository.'))
->setValue($v_hosting);
$doc_href = PhabricatorEnv::getDoclink(
'Diffusion User Guide: Repository Hosting');
$form = id(new AphrontFormView())
->setUser($user)
->appendRemarkupInstructions(
pht(
'Phabricator can host repositories, or it can track repositories '.
'hosted elsewhere (like on GitHub or Bitbucket). For information '.
'on configuring hosting, see [[ %s | Diffusion User Guide: '.
'Repository Hosting]]',
$doc_href))
->appendChild($hosted_control)
->appendChild(
id(new AphrontFormSubmitControl())
->setValue(pht('Save and Continue'))
->addCancelButton($edit_uri));
- $object_box = id(new PHUIObjectBoxView())
- ->setHeaderText($title)
+ $form_box = id(new PHUIObjectBoxView())
+ ->setHeaderText(pht('Hosting'))
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setForm($form);
+ $view = id(new PHUITwoColumnView())
+ ->setHeader($header)
+ ->setFooter(array(
+ $form_box,
+ ));
+
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
- ->appendChild($object_box);
+ ->appendChild($view);
}
public function handleProtocols(PhabricatorRepository $repository) {
$request = $this->getRequest();
$user = $request->getUser();
$type = $repository->getVersionControlSystem();
$is_svn = ($type == PhabricatorRepositoryType::REPOSITORY_TYPE_SVN);
$v_http_mode = $repository->getDetail(
'serve-over-http',
PhabricatorRepository::SERVE_OFF);
$v_ssh_mode = $repository->getDetail(
'serve-over-ssh',
PhabricatorRepository::SERVE_OFF);
$edit_uri = $this->getRepositoryControllerURI($repository, 'edit/');
$prev_uri = $this->getRepositoryControllerURI($repository, 'edit/hosting/');
if ($request->isFormPost()) {
$v_http_mode = $request->getStr('http');
$v_ssh_mode = $request->getStr('ssh');
$xactions = array();
$template = id(new PhabricatorRepositoryTransaction());
$type_http = PhabricatorRepositoryTransaction::TYPE_PROTOCOL_HTTP;
$type_ssh = PhabricatorRepositoryTransaction::TYPE_PROTOCOL_SSH;
if (!$is_svn) {
$xactions[] = id(clone $template)
->setTransactionType($type_http)
->setNewValue($v_http_mode);
}
$xactions[] = id(clone $template)
->setTransactionType($type_ssh)
->setNewValue($v_ssh_mode);
id(new PhabricatorRepositoryEditor())
->setContinueOnNoEffect(true)
->setContentSourceFromRequest($request)
->setActor($user)
->applyTransactions($repository, $xactions);
return id(new AphrontRedirectResponse())->setURI($edit_uri);
}
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(pht('Edit Protocols'));
$title = pht('Edit Protocols (%s)', $repository->getName());
-
+ $header = id(new PHUIHeaderView())
+ ->setHeader($title)
+ ->setHeaderIcon('fa-pencil');
$rw_message = pht(
'Phabricator will serve a read-write copy of this repository.');
if (!$repository->isHosted()) {
$rw_message = array(
$rw_message,
phutil_tag('br'),
phutil_tag('br'),
pht(
'%s: This repository is hosted elsewhere, so Phabricator can not '.
'perform writes. This mode will act like "Read Only" for '.
'repositories hosted elsewhere.',
phutil_tag('strong', array(), pht('WARNING'))),
);
}
$ssh_control =
id(new AphrontFormRadioButtonControl())
->setName('ssh')
->setLabel(pht('SSH'))
->setValue($v_ssh_mode)
->addButton(
PhabricatorRepository::SERVE_OFF,
PhabricatorRepository::getProtocolAvailabilityName(
PhabricatorRepository::SERVE_OFF),
pht('Phabricator will not serve this repository over SSH.'))
->addButton(
PhabricatorRepository::SERVE_READONLY,
PhabricatorRepository::getProtocolAvailabilityName(
PhabricatorRepository::SERVE_READONLY),
pht(
'Phabricator will serve a read-only copy of this repository '.
'over SSH.'))
->addButton(
PhabricatorRepository::SERVE_READWRITE,
PhabricatorRepository::getProtocolAvailabilityName(
PhabricatorRepository::SERVE_READWRITE),
$rw_message);
$http_control =
id(new AphrontFormRadioButtonControl())
->setName('http')
->setLabel(pht('HTTP'))
->setValue($v_http_mode)
->addButton(
PhabricatorRepository::SERVE_OFF,
PhabricatorRepository::getProtocolAvailabilityName(
PhabricatorRepository::SERVE_OFF),
pht('Phabricator will not serve this repository over HTTP.'))
->addButton(
PhabricatorRepository::SERVE_READONLY,
PhabricatorRepository::getProtocolAvailabilityName(
PhabricatorRepository::SERVE_READONLY),
pht(
'Phabricator will serve a read-only copy of this repository '.
'over HTTP.'))
->addButton(
PhabricatorRepository::SERVE_READWRITE,
PhabricatorRepository::getProtocolAvailabilityName(
PhabricatorRepository::SERVE_READWRITE),
$rw_message);
if ($is_svn) {
$http_control = id(new AphrontFormMarkupControl())
->setLabel(pht('HTTP'))
->setValue(
phutil_tag(
'em',
array(),
pht(
'Phabricator does not currently support HTTP access to '.
'Subversion repositories.')));
}
$form = id(new AphrontFormView())
->setUser($user)
->appendRemarkupInstructions(
pht(
'Phabricator can serve repositories over various protocols. You can '.
'configure server protocols here.'))
->appendChild($ssh_control);
if (!PhabricatorEnv::getEnvConfig('diffusion.allow-http-auth')) {
$form->appendRemarkupInstructions(
pht(
'NOTE: The configuration setting [[ %s | %s ]] is currently '.
'disabled. You must enable it to activate authenticated access '.
'to repositories over HTTP.',
'/config/edit/diffusion.allow-http-auth/',
'diffusion.allow-http-auth'));
}
$form
->appendChild($http_control)
->appendChild(
id(new AphrontFormSubmitControl())
->setValue(pht('Save Changes'))
->addCancelButton($prev_uri, pht('Back')));
- $object_box = id(new PHUIObjectBoxView())
- ->setHeaderText($title)
+ $form_box = id(new PHUIObjectBoxView())
+ ->setHeaderText(pht('Protocols'))
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setForm($form);
+ $view = id(new PHUITwoColumnView())
+ ->setHeader($header)
+ ->setFooter(array(
+ $form_box,
+ ));
+
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
- ->appendChild($object_box);
+ ->appendChild($view);
}
}
diff --git a/src/applications/diffusion/controller/DiffusionRepositoryEditMainController.php b/src/applications/diffusion/controller/DiffusionRepositoryEditMainController.php
index 0ec8cdd6b8..d8a4cf40ba 100644
--- a/src/applications/diffusion/controller/DiffusionRepositoryEditMainController.php
+++ b/src/applications/diffusion/controller/DiffusionRepositoryEditMainController.php
@@ -1,1324 +1,1338 @@
<?php
final class DiffusionRepositoryEditMainController
extends DiffusionRepositoryEditController {
public function handleRequest(AphrontRequest $request) {
$response = $this->loadDiffusionContextForEdit();
if ($response) {
return $response;
}
$viewer = $this->getViewer();
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$is_svn = false;
$is_git = false;
$is_hg = false;
switch ($repository->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
$is_git = true;
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
$is_svn = true;
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
$is_hg = true;
break;
}
$has_branches = ($is_git || $is_hg);
$has_local = $repository->usesLocalWorkingCopy();
$supports_staging = $repository->supportsStaging();
$supports_automation = $repository->supportsAutomation();
$crumbs = $this->buildApplicationCrumbs($is_main = true);
$title = pht('Edit %s', $repository->getName());
$header = id(new PHUIHeaderView())
- ->setHeader($title);
+ ->setHeader($title)
+ ->setHeaderIcon('fa-pencil');
if ($repository->isTracked()) {
$header->setStatus('fa-check', 'bluegrey', pht('Active'));
} else {
$header->setStatus('fa-ban', 'dark', pht('Inactive'));
}
- $basic_actions = $this->buildBasicActions($repository);
- $basic_properties =
- $this->buildBasicProperties($repository, $basic_actions);
+ $curtain = $this->buildCurtain($repository);
+ $basic_properties = $this->buildBasicProperties($repository);
$policy_actions = $this->buildPolicyActions($repository);
$policy_properties =
$this->buildPolicyProperties($repository, $policy_actions);
$remote_properties = null;
if (!$repository->isHosted()) {
$remote_properties = $this->buildRemoteProperties(
$repository,
$this->buildRemoteActions($repository));
}
$encoding_actions = $this->buildEncodingActions($repository);
$encoding_properties =
$this->buildEncodingProperties($repository, $encoding_actions);
$symbols_actions = $this->buildSymbolsActions($repository);
$symbols_properties =
$this->buildSymbolsProperties($repository, $symbols_actions);
$hosting_properties = $this->buildHostingProperties(
$repository,
$this->buildHostingActions($repository));
$branches_properties = null;
if ($has_branches) {
$branches_properties = $this->buildBranchesProperties(
$repository,
$this->buildBranchesActions($repository));
}
$subversion_properties = null;
if ($is_svn) {
$subversion_properties = $this->buildSubversionProperties(
$repository,
$this->buildSubversionActions($repository));
}
$storage_properties = null;
if ($has_local) {
$storage_properties = $this->buildStorageProperties(
$repository,
$this->buildStorageActions($repository));
}
$staging_properties = null;
if ($supports_staging) {
$staging_properties = $this->buildStagingProperties(
$repository,
$this->buildStagingActions($repository));
}
$automation_properties = null;
if ($supports_automation) {
$automation_properties = $this->buildAutomationProperties(
$repository,
$this->buildAutomationActions($repository));
}
$actions_properties = $this->buildActionsProperties(
$repository,
$this->buildActionsActions($repository));
$timeline = $this->buildTransactionTimeline(
$repository,
new PhabricatorRepositoryTransactionQuery());
$timeline->setShouldTerminate(true);
$boxes = array();
- $boxes[] = id(new PHUIObjectBoxView())
- ->setHeader($header)
- ->addPropertyList($basic_properties);
-
$boxes[] = id(new PHUIObjectBoxView())
->setHeaderText(pht('Policies'))
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addPropertyList($policy_properties);
$boxes[] = id(new PHUIObjectBoxView())
->setHeaderText(pht('Hosting'))
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addPropertyList($hosting_properties);
if ($repository->canMirror()) {
$mirror_actions = $this->buildMirrorActions($repository);
$mirror_properties = $this->buildMirrorProperties(
$repository,
$mirror_actions);
$mirrors = id(new PhabricatorRepositoryMirrorQuery())
->setViewer($viewer)
->withRepositoryPHIDs(array($repository->getPHID()))
->execute();
$mirror_list = $this->buildMirrorList($repository, $mirrors);
$boxes[] = id(new PhabricatorAnchorView())->setAnchorName('mirrors');
$mirror_info = array();
if (PhabricatorEnv::getEnvConfig('phabricator.silent')) {
$mirror_info[] = pht(
'Phabricator is running in silent mode, so changes will not '.
'be pushed to mirrors.');
}
$boxes[] = id(new PHUIObjectBoxView())
->setFormErrors($mirror_info)
->setHeaderText(pht('Mirrors'))
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addPropertyList($mirror_properties);
$boxes[] = $mirror_list;
}
if ($remote_properties) {
$boxes[] = id(new PHUIObjectBoxView())
->setHeaderText(pht('Remote'))
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addPropertyList($remote_properties);
}
if ($storage_properties) {
$boxes[] = id(new PHUIObjectBoxView())
->setHeaderText(pht('Storage'))
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addPropertyList($storage_properties);
}
if ($staging_properties) {
$boxes[] = id(new PHUIObjectBoxView())
->setHeaderText(pht('Staging'))
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addPropertyList($staging_properties);
}
if ($automation_properties) {
$boxes[] = id(new PHUIObjectBoxView())
->setHeaderText(pht('Automation'))
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addPropertyList($automation_properties);
}
$boxes[] = id(new PHUIObjectBoxView())
->setHeaderText(pht('Text Encoding'))
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addPropertyList($encoding_properties);
$boxes[] = id(new PHUIObjectBoxView())
->setHeaderText(pht('Symbols'))
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addPropertyList($symbols_properties);
if ($branches_properties) {
$boxes[] = id(new PHUIObjectBoxView())
->setHeaderText(pht('Branches'))
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addPropertyList($branches_properties);
}
if ($subversion_properties) {
$boxes[] = id(new PHUIObjectBoxView())
->setHeaderText(pht('Subversion'))
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addPropertyList($subversion_properties);
}
$boxes[] = id(new PHUIObjectBoxView())
->setHeaderText(pht('Actions'))
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addPropertyList($actions_properties);
- return $this->buildApplicationPage(
- array(
- $crumbs,
+ $crumbs->setBorder(true);
+
+ $view = id(new PHUITwoColumnView())
+ ->setHeader($header)
+ ->setCurtain($curtain)
+ ->addPropertySection(pht('Properties'), $basic_properties)
+ ->setMainColumn(array(
$boxes,
$timeline,
- ),
- array(
- 'title' => $title,
));
+
+ return $this->newPage()
+ ->setTitle($title)
+ ->setCrumbs($crumbs)
+ ->appendChild($view);
+
}
- private function buildBasicActions(PhabricatorRepository $repository) {
- $viewer = $this->getRequest()->getUser();
+ private function buildCurtain(PhabricatorRepository $repository) {
+ $viewer = $this->getViewer();
- $view = id(new PhabricatorActionListView())
- ->setUser($viewer);
+ $curtain = $this->newCurtainView($repository);
$edit = id(new PhabricatorActionView())
->setIcon('fa-pencil')
->setName(pht('Edit Basic Information'))
->setHref($this->getRepositoryControllerURI($repository, 'edit/basic/'));
- $view->addAction($edit);
+ $curtain->addAction($edit);
$edit = id(new PhabricatorActionView())
->setIcon('fa-refresh')
->setName(pht('Update Now'))
->setWorkflow(true)
->setHref(
$this->getRepositoryControllerURI($repository, 'edit/update/'));
- $view->addAction($edit);
+ $curtain->addAction($edit);
$activate = id(new PhabricatorActionView())
->setHref(
$this->getRepositoryControllerURI($repository, 'edit/activate/'))
->setWorkflow(true);
if ($repository->isTracked()) {
$activate
->setIcon('fa-pause')
->setName(pht('Deactivate Repository'));
} else {
$activate
->setIcon('fa-play')
->setName(pht('Activate Repository'));
}
- $view->addAction($activate);
+ $curtain->addAction($activate);
- $view->addAction(
+ $curtain->addAction(
id(new PhabricatorActionView())
->setName(pht('Delete Repository'))
->setIcon('fa-times')
->setHref(
$this->getRepositoryControllerURI($repository, 'edit/delete/'))
->setDisabled(true)
->setWorkflow(true));
- return $view;
+ return $curtain;
}
private function buildBasicProperties(
- PhabricatorRepository $repository,
- PhabricatorActionListView $actions) {
+ PhabricatorRepository $repository) {
- $viewer = $this->getRequest()->getUser();
+ $viewer = $this->getViewer();
$view = id(new PHUIPropertyListView())
- ->setUser($viewer)
- ->setObject($repository)
- ->setActionList($actions);
+ ->setUser($viewer);
$type = PhabricatorRepositoryType::getNameForRepositoryType(
$repository->getVersionControlSystem());
$view->addProperty(pht('Type'), $type);
$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) {
$short_name = $repository->getCloneName();
$short_name = phutil_tag('em', array(), $short_name);
}
$view->addProperty(pht('Short Name'), $short_name);
$view->invokeWillRenderEvent();
$view->addProperty(
pht('Status'),
$this->buildRepositoryStatus($repository));
$view->addProperty(
pht('Update Frequency'),
$this->buildRepositoryUpdateInterval($repository));
$description = $repository->getDetail('description');
$view->addSectionHeader(
pht('Description'), PHUIPropertyListView::ICON_SUMMARY);
if (!strlen($description)) {
$description = phutil_tag('em', array(), pht('No description provided.'));
} else {
$description = new PHUIRemarkupView($viewer, $description);
}
$view->addTextContent($description);
return $view;
}
private function buildEncodingActions(PhabricatorRepository $repository) {
- $viewer = $this->getRequest()->getUser();
+ $viewer = $this->getViewer();
$view = id(new PhabricatorActionListView())
->setUser($viewer);
$edit = id(new PhabricatorActionView())
->setIcon('fa-pencil')
->setName(pht('Edit Text Encoding'))
->setHref(
$this->getRepositoryControllerURI($repository, 'edit/encoding/'));
$view->addAction($edit);
return $view;
}
private function buildEncodingProperties(
PhabricatorRepository $repository,
PhabricatorActionListView $actions) {
- $viewer = $this->getRequest()->getUser();
+ $viewer = $this->getViewer();
$view = id(new PHUIPropertyListView())
->setUser($viewer)
->setActionList($actions);
$encoding = $repository->getDetail('encoding');
if (!$encoding) {
$encoding = phutil_tag('em', array(), pht('Use Default (UTF-8)'));
}
$view->addProperty(pht('Encoding'), $encoding);
return $view;
}
private function buildPolicyActions(PhabricatorRepository $repository) {
- $viewer = $this->getRequest()->getUser();
+ $viewer = $this->getViewer();
$view = id(new PhabricatorActionListView())
->setUser($viewer);
$edit = id(new PhabricatorActionView())
->setIcon('fa-pencil')
->setName(pht('Edit Policies'))
->setHref(
$this->getRepositoryControllerURI($repository, 'edit/policy/'));
$view->addAction($edit);
return $view;
}
private function buildPolicyProperties(
PhabricatorRepository $repository,
PhabricatorActionListView $actions) {
- $viewer = $this->getRequest()->getUser();
+ $viewer = $this->getViewer();
$view = id(new PHUIPropertyListView())
->setUser($viewer)
->setActionList($actions);
$descriptions = PhabricatorPolicyQuery::renderPolicyDescriptions(
$viewer,
$repository);
$view_parts = array();
if (PhabricatorSpacesNamespaceQuery::getViewerSpacesExist($viewer)) {
$space_phid = PhabricatorSpacesNamespaceQuery::getObjectSpacePHID(
$repository);
$view_parts[] = $viewer->renderHandle($space_phid);
}
$view_parts[] = $descriptions[PhabricatorPolicyCapability::CAN_VIEW];
$view->addProperty(
pht('Visible To'),
phutil_implode_html(" \xC2\xB7 ", $view_parts));
$view->addProperty(
pht('Editable By'),
$descriptions[PhabricatorPolicyCapability::CAN_EDIT]);
$pushable = $repository->isHosted()
? $descriptions[DiffusionPushCapability::CAPABILITY]
: phutil_tag('em', array(), pht('Not a Hosted Repository'));
$view->addProperty(pht('Pushable By'), $pushable);
return $view;
}
private function buildBranchesActions(PhabricatorRepository $repository) {
- $viewer = $this->getRequest()->getUser();
+ $viewer = $this->getViewer();
$view = id(new PhabricatorActionListView())
->setUser($viewer);
$edit = id(new PhabricatorActionView())
->setIcon('fa-pencil')
->setName(pht('Edit Branches'))
->setHref(
$this->getRepositoryControllerURI($repository, 'edit/branches/'));
$view->addAction($edit);
return $view;
}
private function buildBranchesProperties(
PhabricatorRepository $repository,
PhabricatorActionListView $actions) {
- $viewer = $this->getRequest()->getUser();
+ $viewer = $this->getViewer();
$view = id(new PHUIPropertyListView())
->setUser($viewer)
->setActionList($actions);
$default_branch = nonempty(
$repository->getHumanReadableDetail('default-branch'),
phutil_tag('em', array(), $repository->getDefaultBranch()));
$view->addProperty(pht('Default Branch'), $default_branch);
$track_only = nonempty(
$repository->getHumanReadableDetail('branch-filter', array()),
phutil_tag('em', array(), pht('Track All Branches')));
$view->addProperty(pht('Track Only'), $track_only);
$autoclose_only = nonempty(
$repository->getHumanReadableDetail('close-commits-filter', array()),
phutil_tag('em', array(), pht('Autoclose On All Branches')));
if ($repository->getDetail('disable-autoclose')) {
$autoclose_only = phutil_tag('em', array(), pht('Disabled'));
}
$view->addProperty(pht('Autoclose Only'), $autoclose_only);
return $view;
}
private function buildSubversionActions(PhabricatorRepository $repository) {
- $viewer = $this->getRequest()->getUser();
+ $viewer = $this->getViewer();
$view = id(new PhabricatorActionListView())
->setUser($viewer);
$edit = id(new PhabricatorActionView())
->setIcon('fa-pencil')
->setName(pht('Edit Subversion Info'))
->setHref(
$this->getRepositoryControllerURI($repository, 'edit/subversion/'));
$view->addAction($edit);
return $view;
}
private function buildSubversionProperties(
PhabricatorRepository $repository,
PhabricatorActionListView $actions) {
- $viewer = $this->getRequest()->getUser();
+ $viewer = $this->getViewer();
$view = id(new PHUIPropertyListView())
->setUser($viewer)
->setActionList($actions);
$svn_uuid = nonempty(
$repository->getUUID(),
phutil_tag('em', array(), pht('Not Configured')));
$view->addProperty(pht('Subversion UUID'), $svn_uuid);
$svn_subpath = nonempty(
$repository->getHumanReadableDetail('svn-subpath'),
phutil_tag('em', array(), pht('Import Entire Repository')));
$view->addProperty(pht('Import Only'), $svn_subpath);
return $view;
}
private function buildActionsActions(PhabricatorRepository $repository) {
- $viewer = $this->getRequest()->getUser();
+ $viewer = $this->getViewer();
$view = id(new PhabricatorActionListView())
->setUser($viewer);
$edit = id(new PhabricatorActionView())
->setIcon('fa-pencil')
->setName(pht('Edit Actions'))
->setHref(
$this->getRepositoryControllerURI($repository, 'edit/actions/'));
$view->addAction($edit);
return $view;
}
private function buildActionsProperties(
PhabricatorRepository $repository,
PhabricatorActionListView $actions) {
- $viewer = $this->getRequest()->getUser();
+ $viewer = $this->getViewer();
$view = id(new PHUIPropertyListView())
->setUser($viewer)
->setActionList($actions);
$notify = $repository->getDetail('herald-disabled')
? pht('Off')
: pht('On');
$notify = phutil_tag('em', array(), $notify);
$view->addProperty(pht('Publish/Notify'), $notify);
$autoclose = $repository->getDetail('disable-autoclose')
? pht('Off')
: pht('On');
$autoclose = phutil_tag('em', array(), $autoclose);
$view->addProperty(pht('Autoclose'), $autoclose);
return $view;
}
private function buildRemoteActions(PhabricatorRepository $repository) {
- $viewer = $this->getRequest()->getUser();
+ $viewer = $this->getViewer();
$view = id(new PhabricatorActionListView())
->setUser($viewer);
$edit = id(new PhabricatorActionView())
->setIcon('fa-pencil')
->setName(pht('Edit Remote'))
->setHref(
$this->getRepositoryControllerURI($repository, 'edit/remote/'));
$view->addAction($edit);
return $view;
}
private function buildRemoteProperties(
PhabricatorRepository $repository,
PhabricatorActionListView $actions) {
- $viewer = $this->getRequest()->getUser();
+ $viewer = $this->getViewer();
$view = id(new PHUIPropertyListView())
->setUser($viewer)
->setActionList($actions);
$view->addProperty(
pht('Remote URI'),
$repository->getHumanReadableDetail('remote-uri'));
$credential_phid = $repository->getCredentialPHID();
if ($credential_phid) {
$view->addProperty(
pht('Credential'),
$viewer->renderHandle($credential_phid));
}
return $view;
}
private function buildStorageActions(PhabricatorRepository $repository) {
- $viewer = $this->getRequest()->getUser();
+ $viewer = $this->getViewer();
$view = id(new PhabricatorActionListView())
->setUser($viewer);
$edit = id(new PhabricatorActionView())
->setIcon('fa-pencil')
->setName(pht('Edit Storage'))
->setHref(
$this->getRepositoryControllerURI($repository, 'edit/storage/'));
$view->addAction($edit);
return $view;
}
private function buildStorageProperties(
PhabricatorRepository $repository,
PhabricatorActionListView $actions) {
- $viewer = $this->getRequest()->getUser();
+ $viewer = $this->getViewer();
$view = id(new PHUIPropertyListView())
->setUser($viewer)
->setActionList($actions);
$service_phid = $repository->getAlmanacServicePHID();
if ($service_phid) {
$v_service = $viewer->renderHandle($service_phid);
} else {
$v_service = phutil_tag(
'em',
array(),
pht('Local'));
}
$view->addProperty(
pht('Storage Service'),
$v_service);
$view->addProperty(
pht('Storage Path'),
$repository->getHumanReadableDetail('local-path'));
return $view;
}
private function buildStagingActions(PhabricatorRepository $repository) {
$viewer = $this->getViewer();
$view = id(new PhabricatorActionListView())
->setUser($viewer);
$edit = id(new PhabricatorActionView())
->setIcon('fa-pencil')
->setName(pht('Edit Staging'))
->setHref(
$this->getRepositoryControllerURI($repository, 'edit/staging/'));
$view->addAction($edit);
return $view;
}
private function buildStagingProperties(
PhabricatorRepository $repository,
PhabricatorActionListView $actions) {
$viewer = $this->getViewer();
$view = id(new PHUIPropertyListView())
->setUser($viewer)
->setActionList($actions);
$staging_uri = $repository->getStagingURI();
if (!$staging_uri) {
$staging_uri = phutil_tag('em', array(), pht('No Staging Area'));
}
$view->addProperty(
pht('Staging Area'),
$staging_uri);
return $view;
}
private function buildAutomationActions(PhabricatorRepository $repository) {
$viewer = $this->getViewer();
$view = id(new PhabricatorActionListView())
->setUser($viewer);
$edit = id(new PhabricatorActionView())
->setIcon('fa-pencil')
->setName(pht('Edit Automation'))
->setHref(
$this->getRepositoryControllerURI($repository, 'edit/automation/'));
$view->addAction($edit);
$can_test = $repository->canPerformAutomation();
$test = id(new PhabricatorActionView())
->setIcon('fa-gamepad')
->setName(pht('Test Configuration'))
->setWorkflow(true)
->setDisabled(!$can_test)
->setHref(
$this->getRepositoryControllerURI(
$repository,
'edit/testautomation/'));
$view->addAction($test);
return $view;
}
private function buildAutomationProperties(
PhabricatorRepository $repository,
PhabricatorActionListView $actions) {
$viewer = $this->getViewer();
$view = id(new PHUIPropertyListView())
->setUser($viewer)
->setActionList($actions);
$blueprint_phids = $repository->getAutomationBlueprintPHIDs();
if (!$blueprint_phids) {
$blueprint_view = phutil_tag('em', array(), pht('Not Configured'));
} else {
$blueprint_view = id(new DrydockObjectAuthorizationView())
->setUser($viewer)
->setObjectPHID($repository->getPHID())
->setBlueprintPHIDs($blueprint_phids);
}
$view->addProperty(pht('Automation'), $blueprint_view);
return $view;
}
private function buildHostingActions(PhabricatorRepository $repository) {
$user = $this->getRequest()->getUser();
$view = id(new PhabricatorActionListView())
->setUser($user);
$edit = id(new PhabricatorActionView())
->setIcon('fa-pencil')
->setName(pht('Edit Hosting'))
->setHref(
$this->getRepositoryControllerURI($repository, 'edit/hosting/'));
$view->addAction($edit);
if ($repository->canAllowDangerousChanges()) {
if ($repository->shouldAllowDangerousChanges()) {
$changes = id(new PhabricatorActionView())
->setIcon('fa-shield')
->setName(pht('Prevent Dangerous Changes'))
->setHref(
$this->getRepositoryControllerURI($repository, 'edit/dangerous/'))
->setWorkflow(true);
} else {
$changes = id(new PhabricatorActionView())
->setIcon('fa-bullseye')
->setName(pht('Allow Dangerous Changes'))
->setHref(
$this->getRepositoryControllerURI($repository, 'edit/dangerous/'))
->setWorkflow(true);
}
$view->addAction($changes);
}
return $view;
}
private function buildHostingProperties(
PhabricatorRepository $repository,
PhabricatorActionListView $actions) {
$user = $this->getRequest()->getUser();
$view = id(new PHUIPropertyListView())
->setUser($user)
->setActionList($actions);
$hosting = $repository->isHosted()
? pht('Hosted on Phabricator')
: pht('Hosted Elsewhere');
$view->addProperty(pht('Hosting'), phutil_tag('em', array(), $hosting));
$view->addProperty(
pht('Serve over HTTP'),
phutil_tag(
'em',
array(),
PhabricatorRepository::getProtocolAvailabilityName(
$repository->getServeOverHTTP())));
$view->addProperty(
pht('Serve over SSH'),
phutil_tag(
'em',
array(),
PhabricatorRepository::getProtocolAvailabilityName(
$repository->getServeOverSSH())));
if ($repository->canAllowDangerousChanges()) {
if ($repository->shouldAllowDangerousChanges()) {
$description = pht('Allowed');
} else {
$description = pht('Not Allowed');
}
$view->addProperty(
pht('Dangerous Changes'),
$description);
}
return $view;
}
private function buildRepositoryStatus(
PhabricatorRepository $repository) {
- $viewer = $this->getRequest()->getUser();
+ $viewer = $this->getViewer();
$is_cluster = $repository->getAlmanacServicePHID();
$view = new PHUIStatusListView();
$messages = id(new PhabricatorRepositoryStatusMessage())
->loadAllWhere('repositoryID = %d', $repository->getID());
$messages = mpull($messages, null, 'getStatusType');
if ($repository->isTracked()) {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')
->setTarget(pht('Repository Active')));
} else {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_WARNING, 'bluegrey')
->setTarget(pht('Repository Inactive'))
->setNote(
pht('Activate this repository to begin or resume import.')));
return $view;
}
$binaries = array();
$svnlook_check = false;
switch ($repository->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
$binaries[] = 'git';
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
$binaries[] = 'svn';
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
$binaries[] = 'hg';
break;
}
if ($repository->isHosted()) {
if ($repository->getServeOverHTTP() != PhabricatorRepository::SERVE_OFF) {
switch ($repository->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
$binaries[] = 'git-http-backend';
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
$binaries[] = 'svnserve';
$binaries[] = 'svnadmin';
$binaries[] = 'svnlook';
$svnlook_check = true;
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
$binaries[] = 'hg';
break;
}
}
if ($repository->getServeOverSSH() != PhabricatorRepository::SERVE_OFF) {
switch ($repository->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
$binaries[] = 'git-receive-pack';
$binaries[] = 'git-upload-pack';
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
$binaries[] = 'svnserve';
$binaries[] = 'svnadmin';
$binaries[] = 'svnlook';
$svnlook_check = true;
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
$binaries[] = 'hg';
break;
}
}
}
$binaries = array_unique($binaries);
if (!$is_cluster) {
// We're only checking for binaries if we aren't running with a cluster
// configuration. In theory, we could check for binaries on the
// repository host machine, but we'd need to make this more complicated
// to do that.
foreach ($binaries as $binary) {
$where = Filesystem::resolveBinary($binary);
if (!$where) {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')
->setTarget(
pht('Missing Binary %s', phutil_tag('tt', array(), $binary)))
->setNote(pht(
"Unable to find this binary in the webserver's PATH. You may ".
"need to configure %s.",
$this->getEnvConfigLink())));
} else {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')
->setTarget(
pht('Found Binary %s', phutil_tag('tt', array(), $binary)))
->setNote(phutil_tag('tt', array(), $where)));
}
}
// This gets checked generically above. However, for svn commit hooks, we
// need this to be in environment.append-paths because subversion strips
// PATH.
if ($svnlook_check) {
$where = Filesystem::resolveBinary('svnlook');
if ($where) {
$path = substr($where, 0, strlen($where) - strlen('svnlook'));
$dirs = PhabricatorEnv::getEnvConfig('environment.append-paths');
$in_path = false;
foreach ($dirs as $dir) {
if (Filesystem::isDescendant($path, $dir)) {
$in_path = true;
break;
}
}
if (!$in_path) {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')
->setTarget(
pht('Missing Binary %s', phutil_tag('tt', array(), $binary)))
->setNote(pht(
'Unable to find this binary in `%s`. '.
'You need to configure %s and include %s.',
'environment.append-paths',
$this->getEnvConfigLink(),
$path)));
}
}
}
}
$doc_href = PhabricatorEnv::getDocLink('Managing Daemons with phd');
$daemon_instructions = pht(
'Use %s to start daemons. See %s.',
phutil_tag('tt', array(), 'bin/phd start'),
phutil_tag(
'a',
array(
'href' => $doc_href,
),
pht('Managing Daemons with phd')));
$pull_daemon = id(new PhabricatorDaemonLogQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withStatus(PhabricatorDaemonLogQuery::STATUS_ALIVE)
->withDaemonClasses(array('PhabricatorRepositoryPullLocalDaemon'))
->setLimit(1)
->execute();
if ($pull_daemon) {
// TODO: In a cluster environment, we need a daemon on this repository's
// host, specifically, and we aren't checking for that right now. This
// is a reasonable proxy for things being more-or-less correctly set up,
// though.
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')
->setTarget(pht('Pull Daemon Running')));
} else {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')
->setTarget(pht('Pull Daemon Not Running'))
->setNote($daemon_instructions));
}
$task_daemon = id(new PhabricatorDaemonLogQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withStatus(PhabricatorDaemonLogQuery::STATUS_ALIVE)
->withDaemonClasses(array('PhabricatorTaskmasterDaemon'))
->setLimit(1)
->execute();
if ($task_daemon) {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')
->setTarget(pht('Task Daemon Running')));
} else {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')
->setTarget(pht('Task Daemon Not Running'))
->setNote($daemon_instructions));
}
if ($is_cluster) {
// Just omit this status check for now in cluster environments. We
// could make a service call and pull it from the repository host
// eventually.
} else if ($repository->usesLocalWorkingCopy()) {
$local_parent = dirname($repository->getLocalPath());
if (Filesystem::pathExists($local_parent)) {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')
->setTarget(pht('Storage Directory OK'))
->setNote(phutil_tag('tt', array(), $local_parent)));
} else {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')
->setTarget(pht('No Storage Directory'))
->setNote(
pht(
'Storage directory %s does not exist, or is not readable by '.
'the webserver. Create this directory or make it readable.',
phutil_tag('tt', array(), $local_parent))));
return $view;
}
$local_path = $repository->getLocalPath();
$message = idx($messages, PhabricatorRepositoryStatusMessage::TYPE_INIT);
if ($message) {
switch ($message->getStatusCode()) {
case PhabricatorRepositoryStatusMessage::CODE_ERROR:
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')
->setTarget(pht('Initialization Error'))
->setNote($message->getParameter('message')));
return $view;
case PhabricatorRepositoryStatusMessage::CODE_OKAY:
if (Filesystem::pathExists($local_path)) {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')
->setTarget(pht('Working Copy OK'))
->setNote(phutil_tag('tt', array(), $local_path)));
} else {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')
->setTarget(pht('Working Copy Error'))
->setNote(
pht(
'Working copy %s has been deleted, or is not '.
'readable by the webserver. Make this directory '.
'readable. If it has been deleted, the daemons should '.
'restore it automatically.',
phutil_tag('tt', array(), $local_path))));
return $view;
}
break;
case PhabricatorRepositoryStatusMessage::CODE_WORKING:
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_CLOCK, 'green')
->setTarget(pht('Initializing Working Copy'))
->setNote(pht('Daemons are initializing the working copy.')));
return $view;
default:
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')
->setTarget(pht('Unknown Init Status'))
->setNote($message->getStatusCode()));
return $view;
}
} else {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_CLOCK, 'orange')
->setTarget(pht('No Working Copy Yet'))
->setNote(
pht('Waiting for daemons to build a working copy.')));
return $view;
}
}
$message = idx($messages, PhabricatorRepositoryStatusMessage::TYPE_FETCH);
if ($message) {
switch ($message->getStatusCode()) {
case PhabricatorRepositoryStatusMessage::CODE_ERROR:
$message = $message->getParameter('message');
$suggestion = null;
if (preg_match('/Permission denied \(publickey\)./', $message)) {
$suggestion = pht(
'Public Key Error: This error usually indicates that the '.
'keypair you have configured does not have permission to '.
'access the repository.');
}
$message = phutil_escape_html_newlines($message);
if ($suggestion !== null) {
$message = array(
phutil_tag('strong', array(), $suggestion),
phutil_tag('br'),
phutil_tag('br'),
phutil_tag('em', array(), pht('Raw Error')),
phutil_tag('br'),
$message,
);
}
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')
->setTarget(pht('Update Error'))
->setNote($message));
return $view;
case PhabricatorRepositoryStatusMessage::CODE_OKAY:
$ago = (PhabricatorTime::getNow() - $message->getEpoch());
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')
->setTarget(pht('Updates OK'))
->setNote(
pht(
'Last updated %s (%s ago).',
phabricator_datetime($message->getEpoch(), $viewer),
phutil_format_relative_time_detailed($ago))));
break;
}
} else {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_CLOCK, 'orange')
->setTarget(pht('Waiting For Update'))
->setNote(
pht('Waiting for daemons to read updates.')));
}
if ($repository->isImporting()) {
$ratio = $repository->loadImportProgress();
$percentage = sprintf('%.2f%%', 100 * $ratio);
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_CLOCK, 'green')
->setTarget(pht('Importing'))
->setNote(
pht('%s Complete', $percentage)));
} else {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')
->setTarget(pht('Fully Imported')));
}
if (idx($messages, PhabricatorRepositoryStatusMessage::TYPE_NEEDS_UPDATE)) {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_UP, 'indigo')
->setTarget(pht('Prioritized'))
->setNote(pht('This repository will be updated soon!')));
}
return $view;
}
private function buildRepositoryUpdateInterval(
PhabricatorRepository $repository) {
$smart_wait = $repository->loadUpdateInterval();
$doc_href = PhabricatorEnv::getDoclink(
'Diffusion User Guide: Repository Updates');
return array(
phutil_format_relative_time_detailed($smart_wait),
" \xC2\xB7 ",
phutil_tag(
'a',
array(
'href' => $doc_href,
'target' => '_blank',
),
pht('Learn More')),
);
}
private function buildMirrorActions(
PhabricatorRepository $repository) {
- $viewer = $this->getRequest()->getUser();
+ $viewer = $this->getViewer();
$mirror_actions = id(new PhabricatorActionListView())
->setUser($viewer);
$new_mirror_uri = $this->getRepositoryControllerURI(
$repository,
'mirror/edit/');
$mirror_actions->addAction(
id(new PhabricatorActionView())
->setName(pht('Add Mirror'))
->setIcon('fa-plus')
->setHref($new_mirror_uri)
->setWorkflow(true));
return $mirror_actions;
}
private function buildMirrorProperties(
PhabricatorRepository $repository,
PhabricatorActionListView $actions) {
- $viewer = $this->getRequest()->getUser();
+ $viewer = $this->getViewer();
$mirror_properties = id(new PHUIPropertyListView())
->setUser($viewer)
->setActionList($actions);
$mirror_properties->addProperty(
'',
phutil_tag(
'em',
array(),
pht('Automatically push changes into other remotes.')));
return $mirror_properties;
}
private function buildMirrorList(
PhabricatorRepository $repository,
array $mirrors) {
assert_instances_of($mirrors, 'PhabricatorRepositoryMirror');
$mirror_list = id(new PHUIObjectItemListView())
->setNoDataString(pht('This repository has no configured mirrors.'));
foreach ($mirrors as $mirror) {
$item = id(new PHUIObjectItemView())
->setHeader($mirror->getRemoteURI());
$edit_uri = $this->getRepositoryControllerURI(
$repository,
'mirror/edit/'.$mirror->getID().'/');
$delete_uri = $this->getRepositoryControllerURI(
$repository,
'mirror/delete/'.$mirror->getID().'/');
$item->addAction(
id(new PHUIListItemView())
->setIcon('fa-pencil')
->setHref($edit_uri)
->setWorkflow(true));
$item->addAction(
id(new PHUIListItemView())
->setIcon('fa-times')
->setHref($delete_uri)
->setWorkflow(true));
$mirror_list->addItem($item);
}
- return $mirror_list;
+ return id(new PHUIObjectBoxView())
+ ->setHeaderText(pht('Configured Mirrors'))
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
+ ->setObjectList($mirror_list);
}
private function buildSymbolsActions(PhabricatorRepository $repository) {
- $viewer = $this->getRequest()->getUser();
+ $viewer = $this->getViewer();
$view = id(new PhabricatorActionListView())
->setUser($viewer);
$edit = id(new PhabricatorActionView())
->setIcon('fa-pencil')
->setName(pht('Edit Symbols'))
->setHref(
$this->getRepositoryControllerURI($repository, 'edit/symbol/'));
$view->addAction($edit);
return $view;
}
private function buildSymbolsProperties(
PhabricatorRepository $repository,
PhabricatorActionListView $actions) {
- $viewer = $this->getRequest()->getUser();
+ $viewer = $this->getViewer();
$view = id(new PHUIPropertyListView())
->setUser($viewer)
->setActionList($actions);
$languages = $repository->getSymbolLanguages();
if ($languages) {
$languages = implode(', ', $languages);
} else {
$languages = phutil_tag('em', array(), pht('Any'));
}
$view->addProperty(pht('Languages'), $languages);
$sources = $repository->getSymbolSources();
if ($sources) {
$handles = $viewer->loadHandles($sources);
$sources = $handles->renderList();
} else {
$sources = phutil_tag('em', array(), pht('This Repository Only'));
}
$view->addProperty(pht('Use Symbols From'), $sources);
return $view;
}
private function getEnvConfigLink() {
$config_href = '/config/edit/environment.append-paths/';
return phutil_tag(
'a',
array(
'href' => $config_href,
),
'environment.append-paths');
}
}
diff --git a/src/applications/diffusion/controller/DiffusionRepositoryEditStagingController.php b/src/applications/diffusion/controller/DiffusionRepositoryEditStagingController.php
index deb8fad669..2d158e61ea 100644
--- a/src/applications/diffusion/controller/DiffusionRepositoryEditStagingController.php
+++ b/src/applications/diffusion/controller/DiffusionRepositoryEditStagingController.php
@@ -1,81 +1,91 @@
<?php
final class DiffusionRepositoryEditStagingController
extends DiffusionRepositoryEditController {
public function handleRequest(AphrontRequest $request) {
$response = $this->loadDiffusionContextForEdit();
if ($response) {
return $response;
}
$viewer = $this->getViewer();
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
if (!$repository->supportsStaging()) {
return new Aphront404Response();
}
$edit_uri = $this->getRepositoryControllerURI($repository, 'edit/');
$v_area = $repository->getHumanReadableDetail('staging-uri');
if ($request->isFormPost()) {
$v_area = $request->getStr('area');
$xactions = array();
$template = id(new PhabricatorRepositoryTransaction());
$type_encoding = PhabricatorRepositoryTransaction::TYPE_STAGING_URI;
$xactions[] = id(clone $template)
->setTransactionType($type_encoding)
->setNewValue($v_area);
id(new PhabricatorRepositoryEditor())
->setContinueOnNoEffect(true)
->setContentSourceFromRequest($request)
->setActor($viewer)
->applyTransactions($repository, $xactions);
return id(new AphrontRedirectResponse())->setURI($edit_uri);
}
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(pht('Edit Staging'));
- $title = pht('Edit %s', $repository->getName());
+ $title = pht('Edit Staging (%s)', $repository->getName());
+ $header = id(new PHUIHeaderView())
+ ->setHeader($title)
+ ->setHeaderIcon('fa-pencil');
$form = id(new AphrontFormView())
->setUser($viewer)
->appendRemarkupInstructions(
pht(
"To make it easier to run integration tests and builds on code ".
"under review, you can configure a **Staging Area**. When `arc` ".
"creates a diff, it will push a copy of the changes to the ".
"configured staging area with a corresponding tag.".
"\n\n".
"IMPORTANT: This feature is new, experimental, and not supported. ".
"Use it at your own risk."))
->appendChild(
id(new AphrontFormTextControl())
->setLabel(pht('Staging Area URI'))
->setName('area')
->setValue($v_area))
->appendChild(
id(new AphrontFormSubmitControl())
->setValue(pht('Save'))
->addCancelButton($edit_uri));
- $object_box = id(new PHUIObjectBoxView())
- ->setHeaderText($title)
+ $form_box = id(new PHUIObjectBoxView())
+ ->setHeaderText(pht('Staging'))
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setForm($form);
+ $view = id(new PHUITwoColumnView())
+ ->setHeader($header)
+ ->setFooter(array(
+ $form_box,
+ ));
+
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
- ->appendChild($object_box);
+ ->appendChild($view);
}
}
diff --git a/src/applications/diffusion/controller/DiffusionRepositoryEditStorageController.php b/src/applications/diffusion/controller/DiffusionRepositoryEditStorageController.php
index 711844188a..f3a492e3b3 100644
--- a/src/applications/diffusion/controller/DiffusionRepositoryEditStorageController.php
+++ b/src/applications/diffusion/controller/DiffusionRepositoryEditStorageController.php
@@ -1,71 +1,80 @@
<?php
final class DiffusionRepositoryEditStorageController
extends DiffusionRepositoryEditController {
public function handleRequest(AphrontRequest $request) {
$response = $this->loadDiffusionContextForEdit();
if ($response) {
return $response;
}
$viewer = $this->getViewer();
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$edit_uri = $this->getRepositoryControllerURI($repository, 'edit/');
$v_local = $repository->getHumanReadableDetail('local-path');
$errors = array();
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(pht('Edit Storage'));
$title = pht('Edit %s', $repository->getName());
+ $header = id(new PHUIHeaderView())
+ ->setHeader($title)
+ ->setHeaderIcon('fa-pencil');
$service_phid = $repository->getAlmanacServicePHID();
if ($service_phid) {
$handles = $this->loadViewerHandles(array($service_phid));
$v_service = $handles[$service_phid]->renderLink();
} else {
$v_service = phutil_tag(
'em',
array(),
pht('Local'));
}
$form = id(new AphrontFormView())
->setUser($viewer)
->appendChild(
id(new AphrontFormMarkupControl())
->setLabel(pht('Storage Service'))
->setValue($v_service))
->appendChild(
id(new AphrontFormMarkupControl())
->setName('local')
->setLabel(pht('Storage Path'))
->setValue($v_local))
->appendRemarkupInstructions(
pht(
"You can not adjust the local path for this repository from the ".
"web interface. To edit it, run this command:\n\n %s",
sprintf(
'phabricator/ $ ./bin/repository edit %s --as %s --local-path ...',
$repository->getMonogram(),
$viewer->getUsername())))
->appendChild(
id(new AphrontFormSubmitControl())
->addCancelButton($edit_uri, pht('Done')));
- $object_box = id(new PHUIObjectBoxView())
- ->setHeaderText($title)
- ->setForm($form)
- ->setFormErrors($errors);
+ $form_box = id(new PHUIObjectBoxView())
+ ->setHeaderText(pht('Storage'))
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
+ ->setForm($form);
+
+ $view = id(new PHUITwoColumnView())
+ ->setHeader($header)
+ ->setFooter(array(
+ $form_box,
+ ));
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
- ->appendChild($object_box);
+ ->appendChild($view);
}
}
diff --git a/src/applications/diffusion/controller/DiffusionRepositoryEditSubversionController.php b/src/applications/diffusion/controller/DiffusionRepositoryEditSubversionController.php
index 93b9193f14..6fcc316135 100644
--- a/src/applications/diffusion/controller/DiffusionRepositoryEditSubversionController.php
+++ b/src/applications/diffusion/controller/DiffusionRepositoryEditSubversionController.php
@@ -1,108 +1,118 @@
<?php
final class DiffusionRepositoryEditSubversionController
extends DiffusionRepositoryEditController {
public function handleRequest(AphrontRequest $request) {
$response = $this->loadDiffusionContextForEdit();
if ($response) {
return $response;
}
$viewer = $this->getViewer();
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
switch ($repository->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
throw new Exception(
pht('Git and Mercurial do not support editing SVN properties!'));
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
break;
default:
throw new Exception(
pht('Repository has unknown version control system!'));
}
$edit_uri = $this->getRepositoryControllerURI($repository, 'edit/');
$v_subpath = $repository->getHumanReadableDetail('svn-subpath');
$v_uuid = $repository->getUUID();
if ($request->isFormPost()) {
$v_subpath = $request->getStr('subpath');
$v_uuid = $request->getStr('uuid');
$xactions = array();
$template = id(new PhabricatorRepositoryTransaction());
$type_subpath = PhabricatorRepositoryTransaction::TYPE_SVN_SUBPATH;
$type_uuid = PhabricatorRepositoryTransaction::TYPE_UUID;
$xactions[] = id(clone $template)
->setTransactionType($type_subpath)
->setNewValue($v_subpath);
$xactions[] = id(clone $template)
->setTransactionType($type_uuid)
->setNewValue($v_uuid);
id(new PhabricatorRepositoryEditor())
->setContinueOnNoEffect(true)
->setContentSourceFromRequest($request)
->setActor($viewer)
->applyTransactions($repository, $xactions);
return id(new AphrontRedirectResponse())->setURI($edit_uri);
}
$content = array();
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(pht('Edit Subversion Info'));
$title = pht('Edit Subversion Info (%s)', $repository->getName());
+ $header = id(new PHUIHeaderView())
+ ->setHeader($title)
+ ->setHeaderIcon('fa-pencil');
$policies = id(new PhabricatorPolicyQuery())
->setViewer($viewer)
->setObject($repository)
->execute();
$form = id(new AphrontFormView())
->setUser($viewer)
->appendRemarkupInstructions(
pht(
"You can set the **Repository UUID**, which will help Phabriactor ".
"provide better context in some cases. You can find the UUID of a ".
"repository by running `%s`.\n\n".
"If you want to import only part of a repository, like `trunk/`, ".
"you can set a path in **Import Only**. Phabricator will ignore ".
"commits which do not affect this path.",
'svn info'))
->appendChild(
id(new AphrontFormTextControl())
->setName('uuid')
->setLabel(pht('Repository UUID'))
->setValue($v_uuid))
->appendChild(
id(new AphrontFormTextControl())
->setName('subpath')
->setLabel(pht('Import Only'))
->setValue($v_subpath))
->appendChild(
id(new AphrontFormSubmitControl())
->setValue(pht('Save Subversion Info'))
->addCancelButton($edit_uri));
$form_box = id(new PHUIObjectBoxView())
- ->setHeaderText($title)
+ ->setHeaderText(pht('Subversion'))
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setForm($form);
+ $view = id(new PHUITwoColumnView())
+ ->setHeader($header)
+ ->setFooter(array(
+ $form_box,
+ ));
+
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
- ->appendChild($form_box);
+ ->appendChild($view);
}
}
diff --git a/src/applications/diffusion/controller/DiffusionRepositorySymbolsController.php b/src/applications/diffusion/controller/DiffusionRepositorySymbolsController.php
index 6076d2df65..06ce23032a 100644
--- a/src/applications/diffusion/controller/DiffusionRepositorySymbolsController.php
+++ b/src/applications/diffusion/controller/DiffusionRepositorySymbolsController.php
@@ -1,110 +1,120 @@
<?php
final class DiffusionRepositorySymbolsController
extends DiffusionRepositoryEditController {
public function handleRequest(AphrontRequest $request) {
$response = $this->loadDiffusionContextForEdit();
if ($response) {
return $response;
}
$viewer = $this->getViewer();
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$edit_uri = $this->getRepositoryControllerURI($repository, 'edit/');
$v_sources = $repository->getSymbolSources();
$v_languages = $repository->getSymbolLanguages();
if ($v_languages) {
$v_languages = implode(', ', $v_languages);
}
$errors = array();
if ($request->isFormPost()) {
$v_sources = $request->getArr('sources');
$v_languages = $request->getStrList('languages');
$v_languages = array_map('phutil_utf8_strtolower', $v_languages);
if (!$errors) {
$xactions = array();
$template = id(new PhabricatorRepositoryTransaction());
$type_sources = PhabricatorRepositoryTransaction::TYPE_SYMBOLS_SOURCES;
$type_lang = PhabricatorRepositoryTransaction::TYPE_SYMBOLS_LANGUAGE;
$xactions[] = id(clone $template)
->setTransactionType($type_sources)
->setNewValue($v_sources);
$xactions[] = id(clone $template)
->setTransactionType($type_lang)
->setNewValue($v_languages);
try {
id(new PhabricatorRepositoryEditor())
->setContinueOnNoEffect(true)
->setContentSourceFromRequest($request)
->setActor($viewer)
->applyTransactions($repository, $xactions);
return id(new AphrontRedirectResponse())->setURI($edit_uri);
} catch (Exception $ex) {
$errors[] = $ex->getMessage();
}
}
}
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(pht('Edit Symbols'));
- $title = pht('Edit %s', $repository->getName());
+ $title = pht('Edit Symbols (%s)', $repository->getName());
+ $header = id(new PHUIHeaderView())
+ ->setHeader($title)
+ ->setHeaderIcon('fa-pencil');
$form = id(new AphrontFormView())
->setUser($viewer)
->appendRemarkupInstructions($this->getInstructions())
->appendChild(
id(new AphrontFormTextControl())
->setName('languages')
->setLabel(pht('Indexed Languages'))
->setCaption(pht(
'File extensions, separate with commas, for example: php, py. '.
'Leave blank for "any".'))
->setValue($v_languages))
->appendControl(
id(new AphrontFormTokenizerControl())
->setName('sources')
->setLabel(pht('Uses Symbols From'))
->setDatasource(new DiffusionRepositoryDatasource())
->setValue($v_sources))
->appendChild(
id(new AphrontFormSubmitControl())
->setValue(pht('Save'))
->addCancelButton($edit_uri));
- $object_box = id(new PHUIObjectBoxView())
- ->setHeaderText($title)
+ $form_box = id(new PHUIObjectBoxView())
+ ->setHeaderText(pht('Symbols'))
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setForm($form)
->setFormErrors($errors);
+ $view = id(new PHUITwoColumnView())
+ ->setHeader($header)
+ ->setFooter(array(
+ $form_box,
+ ));
+
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
- ->appendChild($object_box);
+ ->appendChild($view);
}
private function getInstructions() {
return pht(<<<EOT
Configure Symbols for this repository.
See [[%s | Symbol Indexes]] for more information on using symbols.
EOT
,
PhabricatorEnv::getDoclink(
'Diffusion User Guide: Symbol Indexes'));
}
}
diff --git a/src/applications/diffusion/controller/DiffusionSymbolController.php b/src/applications/diffusion/controller/DiffusionSymbolController.php
index defe09d58c..3aaccffd22 100644
--- a/src/applications/diffusion/controller/DiffusionSymbolController.php
+++ b/src/applications/diffusion/controller/DiffusionSymbolController.php
@@ -1,150 +1,157 @@
<?php
final class DiffusionSymbolController extends DiffusionController {
public function handleRequest(AphrontRequest $request) {
$viewer = $this->getViewer();
$name = $request->getURIData('name');
$query = id(new DiffusionSymbolQuery())
->setViewer($viewer)
->setName($name);
if ($request->getStr('context')) {
$query->setContext($request->getStr('context'));
}
if ($request->getStr('type')) {
$query->setType($request->getStr('type'));
}
if ($request->getStr('lang')) {
$query->setLanguage($request->getStr('lang'));
}
if ($request->getStr('repositories')) {
$phids = $request->getStr('repositories');
$phids = explode(',', $phids);
$phids = array_filter($phids);
if ($phids) {
$repos = id(new PhabricatorRepositoryQuery())
->setViewer($request->getUser())
->withPHIDs($phids)
->execute();
$repos = mpull($repos, 'getPHID');
if ($repos) {
$query->withRepositoryPHIDs($repos);
}
}
}
$query->needPaths(true);
$query->needRepositories(true);
$symbols = $query->execute();
$external_query = id(new DiffusionExternalSymbolQuery())
->withNames(array($name));
if ($request->getStr('context')) {
$external_query->withContexts(array($request->getStr('context')));
}
if ($request->getStr('type')) {
$external_query->withTypes(array($request->getStr('type')));
}
if ($request->getStr('lang')) {
$external_query->withLanguages(array($request->getStr('lang')));
}
$external_sources = id(new PhutilClassMapQuery())
->setAncestorClass('DiffusionExternalSymbolsSource')
->execute();
$results = array($symbols);
foreach ($external_sources as $source) {
$results[] = $source->executeQuery($external_query);
}
$symbols = array_mergev($results);
if ($request->getBool('jump') && count($symbols) == 1) {
// If this is a clickthrough from Differential, just jump them
// straight to the target if we got a single hit.
$symbol = head($symbols);
return id(new AphrontRedirectResponse())
->setIsExternal($symbol->isExternal())
->setURI($symbol->getURI());
}
$rows = array();
foreach ($symbols as $symbol) {
$href = $symbol->getURI();
if ($symbol->isExternal()) {
$source = $symbol->getSource();
$location = $symbol->getLocation();
} else {
$repo = $symbol->getRepository();
$file = $symbol->getPath();
$line = $symbol->getLineNumber();
$source = $repo->getMonogram();
$location = $file.':'.$line;
}
$location = phutil_tag(
'a',
array(
'href' => $href,
),
$location);
$rows[] = array(
$symbol->getSymbolType(),
$symbol->getSymbolContext(),
$symbol->getSymbolName(),
$symbol->getSymbolLanguage(),
$source,
$location,
);
}
$table = new AphrontTableView($rows);
$table->setHeaders(
array(
pht('Type'),
pht('Context'),
pht('Name'),
pht('Language'),
pht('Source'),
pht('Location'),
));
$table->setColumnClasses(
array(
'',
'',
'pri',
'',
'',
'',
));
$table->setNoDataString(
pht('No matching symbol could be found in any indexed repository.'));
- $panel = id(new PHUIObjectBoxView())
- ->setHeaderText(pht('Similar Symbols'))
- ->setTable($table);
+ $header = id(new PHUIHeaderView())
+ ->setHeader(pht('Similar Symbols'))
+ ->setHeaderIcon('fa-bullseye');
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(pht('Find Symbol'));
+ $crumbs->setBorder(true);
+
+ $view = id(new PHUITwoColumnView())
+ ->setHeader($header)
+ ->setFooter(array(
+ $table,
+ ));
return $this->newPage()
->setTitle(pht('Find Symbol'))
->setCrumbs($crumbs)
- ->appendChild($panel);
+ ->appendChild($view);
}
}
diff --git a/src/applications/diffusion/controller/DiffusionTagListController.php b/src/applications/diffusion/controller/DiffusionTagListController.php
index 4749675bbb..5abd93c37d 100644
--- a/src/applications/diffusion/controller/DiffusionTagListController.php
+++ b/src/applications/diffusion/controller/DiffusionTagListController.php
@@ -1,101 +1,111 @@
<?php
final class DiffusionTagListController extends DiffusionController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
$response = $this->loadDiffusionContext();
if ($response) {
return $response;
}
$viewer = $this->getViewer();
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$pager = id(new PHUIPagerView())
->readFromRequest($request);
$params = array(
'limit' => $pager->getPageSize() + 1,
'offset' => $pager->getOffset(),
);
if (strlen($drequest->getSymbolicCommit())) {
$is_commit = true;
$params['commit'] = $drequest->getSymbolicCommit();
} else {
$is_commit = false;
}
switch ($repository->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
$tags = array();
break;
default:
$conduit_result = $this->callConduitWithDiffusionRequest(
'diffusion.tagsquery',
$params);
$tags = DiffusionRepositoryTag::newFromConduit($conduit_result);
break;
}
$tags = $pager->sliceResults($tags);
$content = null;
+
+ $header = id(new PHUIHeaderView())
+ ->setHeader(pht('Tags'))
+ ->setHeaderIcon('fa-tags');
+
if (!$tags) {
$content = $this->renderStatusMessage(
pht('No Tags'),
$is_commit
? pht('This commit has no tags.')
: pht('This repository has no tags.'));
} else {
$commits = id(new DiffusionCommitQuery())
->setViewer($viewer)
->withRepository($repository)
->withIdentifiers(mpull($tags, 'getCommitIdentifier'))
->needCommitData(true)
->execute();
$view = id(new DiffusionTagListView())
->setTags($tags)
->setUser($viewer)
->setCommits($commits)
->setDiffusionRequest($drequest);
$phids = $view->getRequiredHandlePHIDs();
$handles = $this->loadViewerHandles($phids);
$view->setHandles($handles);
- $panel = id(new PHUIObjectBoxView())
- ->setHeaderText(pht('Tags'))
- ->appendChild($view);
-
- $content = $panel;
+ $content = $view;
}
$crumbs = $this->buildCrumbs(
array(
'tags' => true,
'commit' => $drequest->getSymbolicCommit(),
));
+ $crumbs->setBorder(true);
+
+ $box = id(new PHUIObjectBoxView())
+ ->setHeaderText($repository->getDisplayName())
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
+ ->setTable($view);
$pager_box = $this->renderTablePagerBox($pager);
+ $view = id(new PHUITwoColumnView())
+ ->setHeader($header)
+ ->setFooter(array(
+ $box,
+ $pager_box,
+ ));
+
return $this->newPage()
->setTitle(
array(
pht('Tags'),
$repository->getDisplayName(),
))
->setCrumbs($crumbs)
- ->appendChild(
- array(
- $content,
- $pager_box,
- ));
+ ->appendChild($view);
}
}
diff --git a/src/applications/diffusion/view/DiffusionBrowseTableView.php b/src/applications/diffusion/view/DiffusionBrowseTableView.php
index 6354c5dc5e..fa5342ad9d 100644
--- a/src/applications/diffusion/view/DiffusionBrowseTableView.php
+++ b/src/applications/diffusion/view/DiffusionBrowseTableView.php
@@ -1,163 +1,158 @@
<?php
final class DiffusionBrowseTableView extends DiffusionView {
private $paths;
private $handles = array();
public function setPaths(array $paths) {
assert_instances_of($paths, 'DiffusionRepositoryPath');
$this->paths = $paths;
return $this;
}
public function setHandles(array $handles) {
assert_instances_of($handles, 'PhabricatorObjectHandle');
$this->handles = $handles;
return $this;
}
public function render() {
$request = $this->getDiffusionRequest();
$repository = $request->getRepository();
$base_path = trim($request->getPath(), '/');
if ($base_path) {
$base_path = $base_path.'/';
}
$need_pull = array();
$rows = array();
$show_edit = false;
foreach ($this->paths as $path) {
$full_path = $base_path.$path->getPath();
$dir_slash = null;
$file_type = $path->getFileType();
if ($file_type == DifferentialChangeType::FILE_DIRECTORY) {
$browse_text = $path->getPath().'/';
$dir_slash = '/';
$browse_link = phutil_tag('strong', array(), $this->linkBrowse(
$full_path.$dir_slash,
array(
'type' => $file_type,
'name' => $browse_text,
)));
$history_path = $full_path.'/';
} else if ($file_type == DifferentialChangeType::FILE_SUBMODULE) {
$browse_text = $path->getPath().'/';
$browse_link = phutil_tag('strong', array(), $this->linkBrowse(
null,
array(
'type' => $file_type,
'name' => $browse_text,
'hash' => $path->getHash(),
'external' => $path->getExternalURI(),
)));
$history_path = $full_path.'/';
} else {
$browse_text = $path->getPath();
$browse_link = $this->linkBrowse(
$full_path,
array(
'type' => $file_type,
'name' => $browse_text,
));
$history_path = $full_path;
}
$history_link = $this->linkHistory($history_path);
$dict = array(
'lint' => celerity_generate_unique_node_id(),
'commit' => celerity_generate_unique_node_id(),
'date' => celerity_generate_unique_node_id(),
'author' => celerity_generate_unique_node_id(),
'details' => celerity_generate_unique_node_id(),
);
$need_pull[$full_path.$dir_slash] = $dict;
foreach ($dict as $k => $uniq) {
$dict[$k] = phutil_tag('span', array('id' => $uniq), '');
}
$rows[] = array(
$history_link,
$browse_link,
idx($dict, 'lint'),
$dict['commit'],
- $dict['author'],
$dict['details'],
$dict['date'],
);
}
if ($need_pull) {
Javelin::initBehavior(
'diffusion-pull-lastmodified',
array(
'uri' => (string)$request->generateURI(
array(
'action' => 'lastmodified',
'stable' => true,
)),
'map' => $need_pull,
));
}
$branch = $this->getDiffusionRequest()->loadBranch();
$show_lint = ($branch && $branch->getLintCommit());
$lint = $request->getLint();
$view = new AphrontTableView($rows);
$view->setHeaders(
array(
null,
pht('Path'),
($lint ? $lint : pht('Lint')),
pht('Modified'),
- pht('Author/Committer'),
pht('Details'),
pht('Committed'),
));
$view->setColumnClasses(
array(
'nudgeright',
'',
'',
'',
- '',
'wide',
'',
));
$view->setColumnVisibility(
array(
true,
true,
$show_lint,
true,
true,
true,
- true,
));
$view->setDeviceVisibility(
array(
true,
true,
false,
- true,
false,
true,
false,
));
return $view->render();
}
}
diff --git a/src/applications/diffusion/view/DiffusionView.php b/src/applications/diffusion/view/DiffusionView.php
index 331c172866..5aa1fad33c 100644
--- a/src/applications/diffusion/view/DiffusionView.php
+++ b/src/applications/diffusion/view/DiffusionView.php
@@ -1,232 +1,234 @@
<?php
abstract class DiffusionView extends AphrontView {
private $diffusionRequest;
final public function setDiffusionRequest(DiffusionRequest $request) {
$this->diffusionRequest = $request;
return $this;
}
final public function getDiffusionRequest() {
return $this->diffusionRequest;
}
final public function linkHistory($path) {
$href = $this->getDiffusionRequest()->generateURI(
array(
'action' => 'history',
'path' => $path,
));
return $this->renderHistoryLink($href);
}
final public function linkBranchHistory($branch) {
$href = $this->getDiffusionRequest()->generateURI(
array(
'action' => 'history',
'branch' => $branch,
));
return $this->renderHistoryLink($href);
}
final public function linkTagHistory($tag) {
$href = $this->getDiffusionRequest()->generateURI(
array(
'action' => 'history',
'commit' => $tag,
));
return $this->renderHistoryLink($href);
}
private function renderHistoryLink($href) {
return javelin_tag(
'a',
array(
'href' => $href,
'class' => 'diffusion-link-icon',
'sigil' => 'has-tooltip',
'meta' => array(
'tip' => pht('History'),
'align' => 'E',
),
),
id(new PHUIIconView())->setIcon('fa-history bluegrey'));
}
final public function linkBrowse($path, array $details = array()) {
require_celerity_resource('diffusion-icons-css');
Javelin::initBehavior('phabricator-tooltips');
$file_type = idx($details, 'type');
unset($details['type']);
$display_name = idx($details, 'name');
unset($details['name']);
if (strlen($display_name)) {
$display_name = phutil_tag(
'span',
array(
'class' => 'diffusion-browse-name',
),
$display_name);
}
if (isset($details['external'])) {
$href = id(new PhutilURI('/diffusion/external/'))
->setQueryParams(
array(
'uri' => idx($details, 'external'),
'id' => idx($details, 'hash'),
));
$tip = pht('Browse External');
} else {
$href = $this->getDiffusionRequest()->generateURI(
$details + array(
'action' => 'browse',
'path' => $path,
));
$tip = pht('Browse');
}
$icon = DifferentialChangeType::getIconForFileType($file_type);
- $icon_view = id(new PHUIIconView())->setIcon($icon);
+ $color = DifferentialChangeType::getIconColorForFileType($file_type);
+ $icon_view = id(new PHUIIconView())
+ ->setIcon($icon.' '.$color);
// If we're rendering a file or directory name, don't show the tooltip.
if ($display_name !== null) {
$sigil = null;
$meta = null;
} else {
$sigil = 'has-tooltip';
$meta = array(
'tip' => $tip,
'align' => 'E',
);
}
return javelin_tag(
'a',
array(
'href' => $href,
'class' => 'diffusion-link-icon',
'sigil' => $sigil,
'meta' => $meta,
),
array(
$icon_view,
$display_name,
));
}
final public static function linkCommit(
PhabricatorRepository $repository,
$commit,
$summary = '') {
$commit_name = $repository->formatCommitName($commit, $local = true);
if (strlen($summary)) {
$commit_name .= ': '.$summary;
}
return phutil_tag(
'a',
array(
'href' => $repository->getCommitURI($commit),
),
$commit_name);
}
final public static function linkRevision($id) {
if (!$id) {
return null;
}
return phutil_tag(
'a',
array(
'href' => "/D{$id}",
),
"D{$id}");
}
final public static function renderName($name) {
$email = new PhutilEmailAddress($name);
if ($email->getDisplayName() && $email->getDomainName()) {
Javelin::initBehavior('phabricator-tooltips', array());
require_celerity_resource('aphront-tooltip-css');
return javelin_tag(
'span',
array(
'sigil' => 'has-tooltip',
'meta' => array(
'tip' => $email->getAddress(),
'align' => 'E',
'size' => 'auto',
),
),
$email->getDisplayName());
}
return hsprintf('%s', $name);
}
final protected function renderBuildable(HarbormasterBuildable $buildable) {
$status = $buildable->getBuildableStatus();
$icon = HarbormasterBuildable::getBuildableStatusIcon($status);
$color = HarbormasterBuildable::getBuildableStatusColor($status);
$name = HarbormasterBuildable::getBuildableStatusName($status);
$icon_view = id(new PHUIIconView())
->setIcon($icon.' '.$color);
$tooltip_view = javelin_tag(
'span',
array(
'sigil' => 'has-tooltip',
'meta' => array('tip' => $name),
),
$icon_view);
Javelin::initBehavior('phabricator-tooltips');
return phutil_tag(
'a',
array('href' => '/'.$buildable->getMonogram()),
$tooltip_view);
}
final protected function loadBuildables(array $commits) {
assert_instances_of($commits, 'PhabricatorRepositoryCommit');
if (!$commits) {
return array();
}
$viewer = $this->getUser();
$harbormaster_app = 'PhabricatorHarbormasterApplication';
$have_harbormaster = PhabricatorApplication::isClassInstalledForViewer(
$harbormaster_app,
$viewer);
if ($have_harbormaster) {
$buildables = id(new HarbormasterBuildableQuery())
->setViewer($viewer)
->withBuildablePHIDs(mpull($commits, 'getPHID'))
->withManualBuildables(false)
->execute();
$buildables = mpull($buildables, null, 'getBuildablePHID');
} else {
$buildables = array();
}
return $buildables;
}
}
diff --git a/src/view/form/PHUIInfoView.php b/src/view/form/PHUIInfoView.php
index 0da471574c..92481bc614 100644
--- a/src/view/form/PHUIInfoView.php
+++ b/src/view/form/PHUIInfoView.php
@@ -1,130 +1,139 @@
<?php
final class PHUIInfoView extends AphrontView {
const SEVERITY_ERROR = 'error';
const SEVERITY_WARNING = 'warning';
const SEVERITY_NOTICE = 'notice';
const SEVERITY_NODATA = 'nodata';
const SEVERITY_SUCCESS = 'success';
private $title;
private $errors;
private $severity;
private $id;
private $buttons = array();
private $isHidden;
+ private $flush;
public function setTitle($title) {
$this->title = $title;
return $this;
}
public function setSeverity($severity) {
$this->severity = $severity;
return $this;
}
public function setErrors(array $errors) {
$this->errors = $errors;
return $this;
}
public function setID($id) {
$this->id = $id;
return $this;
}
public function setIsHidden($bool) {
$this->isHidden = $bool;
return $this;
}
+ public function setFlush($flush) {
+ $this->flush = $flush;
+ return $this;
+ }
+
public function addButton(PHUIButtonView $button) {
$this->buttons[] = $button;
return $this;
}
public function render() {
require_celerity_resource('phui-info-view-css');
$errors = $this->errors;
if (count($errors) > 1) {
$list = array();
foreach ($errors as $error) {
$list[] = phutil_tag(
'li',
array(),
$error);
}
$list = phutil_tag(
'ul',
array(
'class' => 'phui-info-view-list',
),
$list);
} else if (count($errors) == 1) {
$list = $this->errors[0];
} else {
$list = null;
}
$title = $this->title;
if (strlen($title)) {
$title = phutil_tag(
'h1',
array(
'class' => 'phui-info-view-head',
),
$title);
} else {
$title = null;
}
$this->severity = nonempty($this->severity, self::SEVERITY_ERROR);
$classes = array();
$classes[] = 'phui-info-view';
$classes[] = 'phui-info-severity-'.$this->severity;
$classes[] = 'grouped';
+ if ($this->flush) {
+ $classes[] = 'phui-info-view-flush';
+ }
$classes = implode(' ', $classes);
$children = $this->renderChildren();
if ($list) {
$children[] = $list;
}
$body = null;
if (!empty($children)) {
$body = phutil_tag(
'div',
array(
'class' => 'phui-info-view-body',
),
$children);
}
$buttons = null;
if (!empty($this->buttons)) {
$buttons = phutil_tag(
'div',
array(
'class' => 'phui-info-view-actions',
),
$this->buttons);
}
return phutil_tag(
'div',
array(
'id' => $this->id,
'class' => $classes,
'style' => $this->isHidden ? 'display: none;' : null,
),
array(
$buttons,
$title,
$body,
));
}
}
diff --git a/src/view/form/PHUIPagedFormView.php b/src/view/form/PHUIPagedFormView.php
index b5f6ad7066..cfd18add58 100644
--- a/src/view/form/PHUIPagedFormView.php
+++ b/src/view/form/PHUIPagedFormView.php
@@ -1,278 +1,279 @@
<?php
/**
* @task page Managing Pages
*/
final class PHUIPagedFormView extends AphrontView {
private $name = 'pages';
private $pages = array();
private $selectedPage;
private $choosePage;
private $nextPage;
private $prevPage;
private $complete;
private $cancelURI;
protected function canAppendChild() {
return false;
}
/* -( Managing Pages )----------------------------------------------------- */
/**
* @task page
*/
public function addPage($key, PHUIFormPageView $page) {
if (isset($this->pages[$key])) {
throw new Exception(pht("Duplicate page with key '%s'!", $key));
}
$this->pages[$key] = $page;
$page->setPagedFormView($this, $key);
$this->selectedPage = null;
$this->complete = null;
return $this;
}
/**
* @task page
*/
public function getPage($key) {
if (!$this->pageExists($key)) {
throw new Exception(pht("No page '%s' exists!", $key));
}
return $this->pages[$key];
}
/**
* @task page
*/
public function pageExists($key) {
return isset($this->pages[$key]);
}
/**
* @task page
*/
protected function getPageIndex($key) {
$page = $this->getPage($key);
$index = 0;
foreach ($this->pages as $target_page) {
if ($page === $target_page) {
break;
}
$index++;
}
return $index;
}
/**
* @task page
*/
protected function getPageByIndex($index) {
foreach ($this->pages as $page) {
if (!$index) {
return $page;
}
$index--;
}
throw new Exception(pht("Requesting out-of-bounds page '%s'.", $index));
}
protected function getLastIndex() {
return count($this->pages) - 1;
}
protected function isFirstPage(PHUIFormPageView $page) {
return ($this->getPageIndex($page->getKey()) === 0);
}
protected function isLastPage(PHUIFormPageView $page) {
return ($this->getPageIndex($page->getKey()) === (count($this->pages) - 1));
}
public function getSelectedPage() {
return $this->selectedPage;
}
public function readFromObject($object) {
return $this->processForm($is_request = false, $object);
}
public function writeToResponse($response) {
foreach ($this->pages as $page) {
$page->validateResponseType($response);
$response = $page->writeToResponse($page);
}
return $response;
}
public function readFromRequest(AphrontRequest $request) {
$this->choosePage = $request->getStr($this->getRequestKey('page'));
$this->nextPage = $request->getStr('__submit__');
$this->prevPage = $request->getStr('__back__');
return $this->processForm($is_request = true, $request);
}
public function setName($name) {
$this->name = $name;
return $this;
}
public function getValue($page, $key, $default = null) {
return $this->getPage($page)->getValue($key, $default);
}
public function setValue($page, $key, $value) {
$this->getPage($page)->setValue($key, $value);
return $this;
}
private function processForm($is_request, $source) {
if ($this->pageExists($this->choosePage)) {
$selected = $this->getPage($this->choosePage);
} else {
$selected = $this->getPageByIndex(0);
}
$is_attempt_complete = false;
if ($this->prevPage) {
$prev_index = $this->getPageIndex($selected->getKey()) - 1;
$index = max(0, $prev_index);
$selected = $this->getPageByIndex($index);
} else if ($this->nextPage) {
$next_index = $this->getPageIndex($selected->getKey()) + 1;
if ($next_index > $this->getLastIndex()) {
$is_attempt_complete = true;
}
$index = min($this->getLastIndex(), $next_index);
$selected = $this->getPageByIndex($index);
}
$validation_error = false;
$found_selected = false;
foreach ($this->pages as $key => $page) {
if ($is_request) {
if ($key === $this->choosePage) {
$page->readFromRequest($source);
} else {
$page->readSerializedValues($source);
}
} else {
$page->readFromObject($source);
}
if (!$found_selected) {
$page->adjustFormPage();
}
if ($page === $selected) {
$found_selected = true;
}
if (!$found_selected || $is_attempt_complete) {
if (!$page->isValid()) {
$selected = $page;
$validation_error = true;
break;
}
}
}
if ($is_attempt_complete && !$validation_error) {
$this->complete = true;
} else {
$this->selectedPage = $selected;
}
return $this;
}
public function isComplete() {
return $this->complete;
}
public function getRequestKey($key) {
return $this->name.':'.$key;
}
public function setCancelURI($cancel_uri) {
$this->cancelURI = $cancel_uri;
return $this;
}
public function getCancelURI() {
return $this->cancelURI;
}
public function render() {
$form = id(new AphrontFormView())
->setUser($this->getUser());
$selected_page = $this->getSelectedPage();
if (!$selected_page) {
throw new Exception(pht('No selected page!'));
}
$form->addHiddenInput(
$this->getRequestKey('page'),
$selected_page->getKey());
$errors = array();
foreach ($this->pages as $page) {
if ($page == $selected_page) {
$errors = $page->getPageErrors();
continue;
}
foreach ($page->getSerializedValues() as $key => $value) {
$form->addHiddenInput($key, $value);
}
}
$submit = id(new PHUIFormMultiSubmitControl());
if (!$this->isFirstPage($selected_page)) {
$submit->addBackButton();
} else if ($this->getCancelURI()) {
$submit->addCancelButton($this->getCancelURI());
}
if ($this->isLastPage($selected_page)) {
$submit->addSubmitButton(pht('Save'));
} else {
$submit->addSubmitButton(pht('Continue')." \xC2\xBB");
}
$form->appendChild($selected_page);
$form->appendChild($submit);
$box = id(new PHUIObjectBoxView())
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setFormErrors($errors)
->setForm($form);
if ($selected_page->getPageName()) {
$header = id(new PHUIHeaderView())
->setHeader($selected_page->getPageName());
$box->setHeader($header);
}
return $box;
}
}
diff --git a/src/view/phui/PHUIHeadThingView.php b/src/view/phui/PHUIHeadThingView.php
index 4ff0290578..dd788399d4 100644
--- a/src/view/phui/PHUIHeadThingView.php
+++ b/src/view/phui/PHUIHeadThingView.php
@@ -1,65 +1,71 @@
<?php
final class PHUIHeadThingView extends AphrontTagView {
private $image;
private $imageHref;
private $content;
private $size;
const SMALL = 'head-thing-small';
const MEDIUM = 'head-thing-medium';
public function setImageHref($href) {
$this->imageHref = $href;
return $this;
}
public function setImage($image) {
$this->image = $image;
return $this;
}
public function setContent($content) {
$this->content = $content;
return $this;
}
public function setSize($size) {
$this->size = $size;
return $this;
}
protected function getTagAttributes() {
require_celerity_resource('phui-head-thing-view-css');
$classes = array();
$classes[] = 'phui-head-thing-view';
+ if ($this->image) {
+ $classes[] = 'phui-head-has-image';
+ }
if ($this->size) {
$classes[] = $this->size;
} else {
$classes[] = self::SMALL;
}
return array(
'class' => $classes,
);
}
protected function getTagContent() {
$image = phutil_tag(
'a',
array(
'class' => 'phui-head-thing-image',
'style' => 'background-image: url('.$this->image.');',
'href' => $this->imageHref,
));
- return array($image, $this->content);
-
+ if ($this->image) {
+ return array($image, $this->content);
+ } else {
+ return $this->content;
+ }
}
}
diff --git a/webroot/rsrc/css/application/diffusion/diffusion-icons.css b/webroot/rsrc/css/application/diffusion/diffusion-icons.css
index 087ce9362e..c735e3d842 100644
--- a/webroot/rsrc/css/application/diffusion/diffusion-icons.css
+++ b/webroot/rsrc/css/application/diffusion/diffusion-icons.css
@@ -1,22 +1,30 @@
/**
* @provides diffusion-icons-css
*/
input.diffusion-clone-uri {
display: block;
width: 100%;
}
.diffusion-clone-extras {
font-size: 11px;
text-align: right;
color: {$lightgreytext};
}
.diffusion-browse-name {
margin-left: 8px;
}
.diffusion-link-icon + .diffusion-link-icon {
margin-left: 6px;
}
+
+.diffusion-search-boxen {
+ padding: 16px;
+}
+
+.diffusion-search-boxen .phui-form-view {
+ padding: 0;
+}
diff --git a/webroot/rsrc/css/application/diffusion/diffusion-source.css b/webroot/rsrc/css/application/diffusion/diffusion-source.css
index ca52d53a79..7f404e3b9b 100644
--- a/webroot/rsrc/css/application/diffusion/diffusion-source.css
+++ b/webroot/rsrc/css/application/diffusion/diffusion-source.css
@@ -1,82 +1,80 @@
/**
* @provides diffusion-source-css
*/
.diffusion-source {
width: 100%;
- font: 10px/13px "Menlo", "Consolas", "Monaco", monospace;
background: #fff;
}
.diffusion-source tr.phabricator-source-highlight {
background: {$sh-yellowbackground};
}
.diffusion-source th {
text-align: right;
vertical-align: top;
background: {$lightgreybackground};
color: {$bluetext};
border-right: 1px solid {$thinblueborder};
}
.diffusion-source td {
- letter-spacing: 0.0083334px;
- vertical-align: top;
- white-space: pre-wrap;
- padding-bottom: 1px;
- padding-left: 8px;
- line-height: 16px;
- width: 100%;
+ vertical-align: top;
+ white-space: pre-wrap;
+ padding-top: 1px;
+ padding-bottom: 1px;
+ padding-left: 8px;
+ width: 100%;
}
.diffusion-browse-type-form {
float: right;
}
.diffusion-blame-link,
.diffusion-rev-link {
white-space: nowrap;
}
.diffusion-blame-link {
min-width: 28px;
}
.diffusion-source th.diffusion-rev-link {
text-align: left;
min-width: 130px;
}
.diffusion-blame-link a,
.diffusion-rev-link a,
.diffusion-line-link a {
color: {$darkbluetext};
}
.diffusion-rev-link a,
.diffusion-rev-link span {
margin: 2px 8px 0;
display: inline-block;
}
.diffusion-rev-link span {
margin-right: -4px;
margin-left: -4px;
color: {$lightgreytext};
}
.diffusion-blame-link a,
.diffusion-line-link a {
/* Give the user a larger click target. */
display: block;
padding: 2px 8px;
}
.diffusion-line-link {
-moz-user-select: -moz-none;
-khtml-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
}
diff --git a/webroot/rsrc/css/phui/phui-box.css b/webroot/rsrc/css/phui/phui-box.css
index ea825db3be..35f5067fec 100644
--- a/webroot/rsrc/css/phui/phui-box.css
+++ b/webroot/rsrc/css/phui/phui-box.css
@@ -1,100 +1,115 @@
/**
* @provides phui-box-css
*/
.phui-box-border {
border: 1px solid {$lightblueborder};
background-color: #fff;
border-radius: 3px;
}
.phui-box.focus {
box-shadow: 0 0 5px 5px rgba(255, 255, 0, 0.90);
}
.phui-box-grey {
background-color: #F7F7F9;
border-radius: 3px;
border-color: rgba({$alphagrey},.2);
}
.phui-box-blue {
background-color: {$bluebackground};
border-radius: 3px;
border-color: {$thinblueborder};
}
.phui-box-blue .phui-object-item,
.phui-box-grey .phui-object-item {
background: transparent;
}
.phui-box-blue .phui-object-item-link,
.phui-box-grey .phui-object-item-link {
color: {$darkbluetext};
}
.phui-box-blue .phui-object-item-list-view,
.phui-box-grey .phui-object-item-list-view {
background-color: #fff;
}
.phui-box-blue .phui-header-shell {
border-color: {$thinblueborder};
}
.phui-box-grey .phui-header-shell {
border-color: rgba({$alphagrey},.1);
}
.phui-object-box.phui-box-blue div.phui-info-severity-nodata,
.phui-object-box.phui-box-grey div.phui-info-severity-nodata {
background: transparent;
padding: 20px 4px 24px;
text-align: center;
border: none;
color: {$greytext};
}
/* Property Boxes */
.phui-box.phui-box-blue-property {
border-radius: 3px;
border-color: {$lightblueborder};
margin: 0;
padding: 0;
}
.phui-box.phui-box-blue-property .phui-header-header .phui-header-icon {
margin-right: 6px;
}
.phui-box.phui-box-blue-property .phui-header-action-link {
margin-top: 0;
margin-bottom: 0;
}
.device .phui-box.phui-box-blue-property {
padding: 0;
}
.phui-box.phui-object-box.phui-box-blue-property .phui-header-shell {
background-color: #eff3fc;
border-top-right-radius: 3px;
border-top-left-radius: 3px;
padding: 6px 16px;
}
-.device .phui-box.phui-box-blue-property .phui-header-shell {
- padding: 6px 12px;
+.device .phui-box.phui-box-blue-property .phui-header-shell,
+.device .phui-box-blue-property.phui-object-box.phui-object-box-collapsed
+ .phui-header-shell {
+ padding: 6px 12px;
}
.phui-box.phui-box-blue-property .phui-header-header {
font-size: 13px;
color: {$bluetext};
}
.phui-box-blue-property .phui-object-item-list-view.phui-object-list-flush {
padding: 2px 8px;
}
+
+body .phui-box-blue-property.phui-object-box.phui-object-box-collapsed {
+ padding: 0;
+}
+
+body .phui-box-blue-property .phui-header-shell + .phui-object-box {
+ margin-bottom: 0;
+}
+
+.phui-box-blue-property .phui-header-shell + .phui-object-box
+ .phui-header-shell {
+ background: #fff;
+}
diff --git a/webroot/rsrc/css/phui/phui-head-thing.css b/webroot/rsrc/css/phui/phui-head-thing.css
index b82c9321a3..bf491c4f1f 100644
--- a/webroot/rsrc/css/phui/phui-head-thing.css
+++ b/webroot/rsrc/css/phui/phui-head-thing.css
@@ -1,33 +1,36 @@
/**
* @provides phui-head-thing-view-css
*/
.phui-head-thing-view {
height: 24px;
line-height: 22px;
color: {$greytext};
+}
+
+.phui-head-thing-view.phui-head-has-image {
position: relative;
padding-left: 32px;
}
.device-phone .phui-two-column-subheader .phui-head-thing-view {
min-height: 24px;
height: auto;
line-height: inherit;
}
.phui-head-thing-view a {
color: {$darkgreytext};
}
.phui-head-thing-image {
height: 24px;
width: 24px;
background-size: 100%;
margin-right: 8px;
border-radius: 3px;
display: inline-block;
position: absolute;
top: 0;
left: 0;
}
diff --git a/webroot/rsrc/css/phui/phui-header-view.css b/webroot/rsrc/css/phui/phui-header-view.css
index a61a73fc88..2a1731eb61 100644
--- a/webroot/rsrc/css/phui/phui-header-view.css
+++ b/webroot/rsrc/css/phui/phui-header-view.css
@@ -1,326 +1,330 @@
/**
* @provides phui-header-view-css
*/
.phui-header-shell {
border-bottom: 1px solid {$thinblueborder};
overflow: hidden;
padding: 0 4px 12px;
}
.phui-header-view {
display: table;
width: 100%
}
.phui-header-row {
display: table-row;
}
.phui-header-col1 {
display: table-cell;
vertical-align: middle;
width: 62px;
}
.phui-header-col2 {
display: table-cell;
vertical-align: middle;
word-break: break-word;
}
.phui-header-col3 {
display: table-cell;
vertical-align: middle;
}
.device-phone .phui-header-col3 {
vertical-align: top;
}
body .phui-header-shell.phui-header-no-backgound {
background-color: transparent;
border: none;
}
body .phui-header-shell.phui-bleed-header {
background-color: #fff;
border-bottom: 1px solid {$thinblueborder};
width: auto;
margin: 16px;
}
body .phui-header-shell.phui-bleed-header
.phui-header-view {
padding: 8px 24px 8px 0;
color: {$darkbluetext};
}
.phui-header-shell + .phabricator-form-view {
border-top-width: 0;
}
.phui-property-list-view + .diviner-document-section {
margin-top: -1px;
}
.phui-header-view {
position: relative;
font-size: {$normalfontsize};
}
.phui-header-header {
font-size: 16px;
line-height: 24px;
color: {$darkbluetext};
}
.phui-header-header .phui-header-icon {
margin-right: 8px;
color: {$lightbluetext};
}
.phui-object-box .phui-header-tall .phui-header-header,
.phui-document-view .phui-header-tall .phui-header-header {
font-size: 18px;
}
.phui-header-view .phui-header-header a {
color: {$darkbluetext};
}
.device-desktop .phui-header-view .phui-header-header a:hover {
text-decoration: none;
color: {$blue};
}
.phui-header-view .phui-header-action-links {
float: right;
}
.phui-object-box .phui-header-view .phui-header-action-links {
margin-right: 4px;
font-size: {$normalfontsize};
}
.phui-header-action-link {
margin-bottom: 4px;
margin-top: 4px;
float: right;
}
.device-phone .phui-header-action-link .phui-button-text {
visibility: hidden;
width: 0;
margin-left: 8px;
}
.device-phone .phui-header-action-link.button .phui-icon-view {
width: 12px;
text-align: center;
}
.phui-header-divider {
margin: 0 4px;
font-weight: normal;
color: {$lightbluetext};
}
.phui-header-tags {
margin-left: 12px;
font-size: {$normalfontsize};
}
.phui-header-tags .phui-tag-view {
margin-left: 4px;
}
.phui-header-image {
display: inline-block;
background-repeat: no-repeat;
background-size: 100%;
width: 50px;
height: 50px;
border-radius: 3px;
}
.phui-header-image-href {
position: relative;
display: block;
}
.phui-header-image-edit {
display: none;
}
.device-desktop .phui-header-image-href:hover .phui-header-image-edit {
display: block;
position: absolute;
left: 0;
background: rgba({$alphablack},0.4);
color: #fff;
font-weight: normal;
bottom: 4px;
padding: 4px 8px;
font-size: 12px;
}
.device-desktop .phui-header-image-edit:hover {
text-decoration: underline;
}
.phui-header-subheader {
font-weight: normal;
font-size: {$biggerfontsize};
margin-top: 8px;
}
.phui-header-subheader .phui-icon-view {
margin-right: 4px;
}
.phui-header-subheader .phui-tag-view .phui-icon-view,
.phui-header-subheader .policy-header-callout .phui-icon-view {
display: inline-block;
margin: -2px 4px -2px 0;
font-size: 15px;
}
.phui-header-subheader,
.phui-header-subheader .policy-link {
color: {$darkbluetext};
}
.policy-header-callout,
.phui-header-subheader .phui-tag-core {
padding: 3px 9px;
border-radius: 3px;
background: rgba({$alphablue}, 0.1);
margin-right: 8px;
-webkit-font-smoothing: auto;
border-color: transparent;
}
.phui-header-subheader .phui-tag-view,
.phui-header-subheader .phui-tag-type-shade .phui-tag-core {
border: none;
font-weight: normal;
-webkit-font-smoothing: auto;
}
.policy-header-callout.policy-adjusted-weaker {
background: {$sh-greenbackground};
}
.policy-header-callout.policy-adjusted-weaker .policy-link,
.policy-header-callout.policy-adjusted-weaker .phui-icon-view {
color: {$sh-greentext};
}
.policy-header-callout.policy-adjusted-stronger {
background: {$sh-redbackground};
}
.policy-header-callout.policy-adjusted-stronger .policy-link,
.policy-header-callout.policy-adjusted-stronger .phui-icon-view {
color: {$sh-redtext};
}
.policy-header-callout.policy-adjusted-different {
background: {$sh-orangebackground};
}
.policy-header-callout.policy-adjusted-different .policy-link,
.policy-header-callout.policy-adjusted-different .phui-icon-view {
color: {$sh-orangetext};
}
.phui-header-action-links .phui-mobile-menu {
display: none;
}
.device .phui-header-action-links .phui-mobile-menu {
display: inline-block;
}
.phui-header-action-list {
float: right;
}
.phui-header-action-list li {
margin: 0 0 0 8px;
float: right;
}
.phui-header-action-list .phui-header-action-item .phui-icon-view {
height: 18px;
width: 16px;
font-size: 16px;
line-height: 20px;
display: block;
}
.spaces-name {
color: {$lightbluetext};
}
.phui-object-box .phui-header-tall .spaces-name {
font-size: 18px;
}
.spaces-name .phui-handle,
.spaces-name a.phui-handle {
color: {$sh-redtext};
}
.device-desktop .spaces-name a.phui-handle:hover {
color: {$sh-redtext};
text-decoration: underline;
}
.phui-header-subheader .phui-badge-flex-view {
display: inline;
margin-right: 4px;
}
.phui-header-subheader .phui-badge-flex-view:after {
display: inline;
}
/*** Profile Header ***********************************************************/
.phui-profile-header {
padding: 24px 20px 20px 24px;
}
.device-phone .phui-profile-header {
padding: 12px;
}
.phui-profile-header.phui-header-shell {
margin: 0;
border: none;
}
.phui-profile-header .phui-header-image {
height: 80px;
width: 80px;
}
.phui-profile-header .phui-header-col1 {
width: 96px;
}
.phui-profile-header .phui-header-subheader {
margin-top: 12px;
}
.phui-profile-header.phui-header-shell .phui-header-header {
font-family: 'Aleo', {$fontfamily};
font-size: 24px;
}
.phui-profile-header .phui-header-col3 {
vertical-align: top;
}
+
+.phui-header-view .phui-tag-shade-indigo a {
+ color: {$sh-indigotext};
+}
diff --git a/webroot/rsrc/css/phui/phui-info-view.css b/webroot/rsrc/css/phui/phui-info-view.css
index 59405995a5..d3b12dd4fe 100644
--- a/webroot/rsrc/css/phui/phui-info-view.css
+++ b/webroot/rsrc/css/phui/phui-info-view.css
@@ -1,121 +1,125 @@
/**
* @provides phui-info-view-css
*/
.phui-info-view {
border-style: solid;
border-width: 1px;
margin: 16px;
padding: 12px;
border-radius: 3px;
}
+.phui-info-view.phui-info-view-flush {
+ margin: 0 0 20px 0;
+}
+
.device .phui-info-view {
margin: 8px;
}
.phui-info-view .phui-form-view {
padding: 0;
}
.phui-info-view-body {
line-height: 1.6em;
}
.phui-info-view-body tt {
padding: 0 2px;
background-color: rgba({$alphagrey},.1);
}
.phui-info-view-actions {
margin-top: -3px;
margin-bottom: -4px;
float: right;
}
.phui-info-view-actions .button {
margin-left: 4px;
}
.phui-info-view-head + .phui-info-view-body {
padding-top: 4px;
}
h1.phui-info-view-head {
font-weight: bold;
font-size: {$biggerfontsize};
line-height: 1.2em;
}
.phui-info-view-list {
margin: 0 0 0 16px;
list-style: disc;
line-height: 1.5em;
}
.phui-info-view .phui-info-view-actions .button:hover {
background: #fff;
box-shadow: none;
}
.phui-info-severity-error,
.phui-info-severity-error a.button {
border-color: {$sh-redborder};
background: {$sh-redbackground};
}
.phui-info-severity-error a.button {
color: {$sh-redtext};
}
.phui-info-severity-warning,
.phui-info-severity-warning a.button {
border-color: {$sh-yellowborder};
background: {$sh-yellowbackground};
}
.phui-info-severity-warning a.button {
color: {$sh-yellowtext};
}
.phui-info-severity-notice,
.phui-info-severity-notice a.button {
border-color: {$sh-blueborder};
background: {$sh-bluebackground};
}
.phui-info-severity-notice a.button {
color: {$sh-bluetext};
}
.phui-info-severity-nodata,
.phui-info-severity-nodata a.button {
border-color: {$lightgreyborder};
background: #fff;
}
.phui-info-severity-nodata a.button {
color: {$greytext};
}
.phui-info-severity-success,
.phui-info-severity-success a.button {
border-color: {$sh-greenborder};
background: {$sh-greenbackground};
}
.phui-info-severity-success a.button {
color: {$sh-greentext};
}
.aphront-dialog-body .phui-info-view {
margin: 0 0 8px 0;
}
.phui-crumbs-view + .phui-info-view {
margin-top: 0;
}
.phui-crumbs-view.phui-crumbs-border + .phui-info-view {
margin-top: 16px;
}
diff --git a/webroot/rsrc/css/phui/phui-property-list-view.css b/webroot/rsrc/css/phui/phui-property-list-view.css
index 52e3ee0944..ab250a3cc5 100644
--- a/webroot/rsrc/css/phui/phui-property-list-view.css
+++ b/webroot/rsrc/css/phui/phui-property-list-view.css
@@ -1,215 +1,214 @@
/**
* @provides phui-property-list-view-css
*/
.phui-property-list-view .keyboard-shortcuts-available {
float: right;
height: 16px;
margin: 12px 10px -28px 0px;
padding: 0px 20px 0px 0px;
vertical-align: middle;
color: {$greytext};
text-align: right;
font-size: {$smallestfontsize};
background:
url('/rsrc/image/icon/fatcow/key_question.png') right center no-repeat;
}
.device .keyboard-shortcuts-available {
display: none;
}
.phui-property-group-noninitial,
.phui-property-list-section-noninitial {
border-color: {$thinblueborder};
border-style: solid;
border-width: 1px 0 0;
}
.device-desktop .phui-property-list-container {
padding: 12px 0 12px 0;
width: 100%;
}
.device .phui-property-list-container {
padding: 12px 0 4px 0;
}
.phui-property-list-key {
color: {$bluetext};
font-weight: bold;
overflow: hidden;
white-space: nowrap;
}
.device-desktop .phui-property-list-key {
width: 12%;
margin-left: 1%;
text-align: right;
float: left;
clear: left;
margin-bottom: 4px;
}
.device-desktop .phui-property-list-has-actions .phui-property-list-key {
width: 18%;
}
.phui-property-list-properties-wrap.phui-property-list-stacked {
width: auto;
float: none;
}
.device .phui-property-list-key,
.phui-property-list-stacked .phui-property-list-properties
.phui-property-list-key {
padding-left: 4px;
text-align: left;
margin-left: 0;
width: auto;
float: none;
}
.phui-property-list-value {
color: {$darkgreytext};
}
.device-desktop .phui-property-list-value {
width: 84%;
margin-left: 1%;
float: left;
margin-bottom: 4px;
}
.device-desktop .phui-property-list-has-actions .phui-property-list-value {
width: 78%;
}
.device .phui-property-list-value,
.phui-property-list-stacked .phui-property-list-properties
.phui-property-list-value {
padding: 0 8px;
margin-bottom: 8px;
width: auto;
word-break: break-word;
float: none;
}
.phui-property-list-section-header {
color: {$bluetext};
padding: 16px 4px 0px;
text-transform: uppercase;
font-weight: 700;
border-color: {$thinblueborder};
border-style: solid;
border-width: 1px 0 0;
}
.phui-property-list-container + .phui-property-list-text-content {
border-color: {$thinblueborder};
border-style: solid;
border-width: 1px 0 0;
}
.phui-property-list-section-noninitial .phui-property-list-section-header {
border-top: none;
}
.device .phui-property-list-section-header {
padding-left: 4px;
}
.phui-property-list-section-header-icon .phui-icon-view {
display: inline-block;
margin: -2px 4px -2px 0;
}
.phui-property-list-text-content {
padding: 16px 4px;
overflow: hidden;
}
.phui-property-list-raw-content {
padding: 0px;
overflow: hidden;
}
/* In the common case where we immediately follow a header, move back up 30px
so we snuggle next to the header. */
.device-desktop .phui-header-view
+ .phabricator-action-list-view {
margin-top: -30px;
}
.device-desktop .phui-header-view
+ .phabricator-action-list-view
+ .phui-property-list-view {
margin-top: 0px;
}
.phui-property-list-image {
margin: auto;
max-width: 95%;
}
.phui-property-list-audio {
display: block;
margin: 16px auto;
width: 50%;
min-width: 240px;
}
/* When tags appear in property lists, give them a little more vertical
spacing. */
.phui-property-list-view .phui-tag-view {
margin: 2px 0;
}
.phui-property-list-has-actions .phui-property-list-properties-wrap {
float: left;
width: 78%;
}
.device .phui-property-list-properties-wrap {
width: auto;
border: none;
float: none;
overflow: auto;
}
.phui-property-list-actions {
width: 20%;
float: right;
margin-right: 12px;
border-left: 1px solid {$thinblueborder};
}
!print .phui-property-list-actions {
display: none;
}
.device .phui-property-list-actions {
float: none;
width: auto;
margin: -12px 0 12px 0;
border: none;
}
.phui-property-list-image-content img {
margin: 20px auto;
background: url('/rsrc/image/checker_light.png');
- border: 1px solid {$lightblueborder};
}
.device-desktop .phui-property-list-image-content img:hover {
background: url('/rsrc/image/checker_dark.png');
}
/* - Dashboards ------------------------------------------------------------ */
.dashboard-panel .phui-property-list-section {
border-left: 1px solid {$lightblueborder};
border-right: 1px solid {$lightblueborder};
border-bottom: 1px solid {$blueborder};
}
diff --git a/webroot/rsrc/css/phui/phui-two-column-view.css b/webroot/rsrc/css/phui/phui-two-column-view.css
index a4ee2c4d3f..1496a3b0f2 100644
--- a/webroot/rsrc/css/phui/phui-two-column-view.css
+++ b/webroot/rsrc/css/phui/phui-two-column-view.css
@@ -1,193 +1,198 @@
/**
* @provides phui-two-column-view-css
*/
.phui-two-column-view .phui-two-column-header {
background-color: #fff;
border-bottom: 1px solid rgba({$alphagrey}, .12);
margin-bottom: 24px;
}
.device .phui-two-column-view .phui-two-column-header {
margin-bottom: 12px;
}
.phui-two-column-view.with-subheader .phui-two-column-header {
margin-bottom: 0;
}
.phui-two-column-header .phui-header-header {
font-size: 20px;
font-family: 'Aleo', {$fontfamily};
color: #000;
}
.device-phone .phui-two-column-header .phui-header-header {
font-size: 18px;
}
.phui-two-column-view .phui-two-column-header .phui-header-shell {
padding: 24px 32px 28px;
border: none;
}
.phui-two-column-view .phui-two-column-header
.phui-profile-header.phui-header-shell {
padding-bottom: 20px;
}
.device .phui-two-column-view .phui-two-column-header .phui-header-shell {
padding: 12px 12px 16px;
}
.phui-two-column-header .phui-header-subheader {
margin-top: 12px;
}
.phui-two-column-subheader {
padding: 12px 32px;
}
.device .phui-two-column-subheader {
padding: 12px 16px;
}
.device-desktop .phui-two-column-content {
padding: 0 32px;
}
.device .phui-two-column-content {
padding: 0 12px;
}
.device-desktop .phui-two-column-view .phui-main-column {
float: left;
width: calc(100% - 320px);
}
.device-desktop .phui-two-column-view .phui-side-column {
float: right;
width: 300px;
}
.device .phui-side-column {
margin-bottom: 20px;
}
.phui-two-column-view .phui-two-column-content
.phui-object-box {
margin: 0 0 20px 0;
}
-.phui-two-column-view .phui-object-box.phui-object-box-collapsed {
- padding: 0;
-}
-
/* Timeline */
.phui-two-column-view .phui-timeline-view {
padding: 0;
background-position: 80px;
}
.phui-two-column-view .phui-main-column .phui-object-box + .phui-timeline-view {
margin-top: -20px;
}
.device .phui-two-column-view .phui-timeline-view {
background-position: 16px;
padding: 0;
}
.device-phone .phui-two-column-view .phui-timeline-event-view {
margin: 0;
}
.phui-main-column > .phui-timeline-view:first-child {
border-top: 1px solid {$thinblueborder};
}
.device-phone .phui-main-column .phui-timeline-older-transactions-are-hidden {
margin: 0;
}
/* Main Column Properties */
.device-desktop .phui-main-column .phui-property-list-key {
margin-left: 0;
- width: 140px;
+ width: 160px;
}
.device-desktop .phui-main-column .phui-property-list-value {
margin-left: 8px;
- width: calc(100% - 180px);
+ width: calc(100% - 200px);
}
/* Property / Action List */
.phui-two-column-properties .phabricator-action-list-view {
padding-top: 4px;
padding-bottom: 12px;
}
.device-desktop .phui-two-column-view .phui-property-list-container {
- padding: 12px 16px;
+ padding: 16px 0;
}
.device .phui-two-column-view .phui-property-list-container {
padding: 12px 8px;
}
+.phui-two-column-view .phui-property-list-container
+ .keyboard-shortcuts-available {
+ display: none;
+}
+
.phui-two-column-properties.phui-object-box {
border: 1px solid rgba({$alphablue}, .2);
}
.device .phui-two-column-content .phui-two-column-properties.phui-object-box {
padding: 0 12px;
}
.phui-two-column-properties .phabricator-action-view-icon {
top: 8px;
left: 8px;
}
.phabricator-action-view button.phabricator-action-view-item,
.phabricator-action-view-item {
padding: 5px 4px 5px 28px;
}
.device-desktop .phui-two-column-properties .phabricator-action-view:hover
.phabricator-action-view-item {
text-decoration: none;
background-color: rgba({$alphablue}, .08);
color: {$sky};
border-radius: 3px;
}
.device-desktop .phui-two-column-properties .phabricator-action-view:hover
.phabricator-action-view-icon {
color: {$sky};
}
.phui-two-column-view .phui-property-list-section-header,
.phui-two-column-view .phui-property-list-text-content {
margin: 0 16px;
}
.device .phui-two-column-view .phui-property-list-section-header,
.device .phui-two-column-view .phui-property-list-text-content {
margin: 0 8px;
}
/* Info View */
.phui-two-column-view .phui-two-column-row .phui-info-view {
margin: 0 0 20px 0;
padding: 16px;
}
.phui-two-column-view .phui-two-column-row .phui-object-box
.phui-info-view {
margin: 0;
}
+
+.phui-two-column-view .phui-object-box .phui-header-shell + .phui-info-view {
+ margin: 16px 16px 0 16px;
+}

File Metadata

Mime Type
text/x-diff
Expires
Tue, Mar 17, 1:16 AM (16 h, 11 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
964029
Default Alt Text
(454 KB)

Event Timeline