mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-28 01:32:42 +01:00
(stable) Promote 2016 Week 34
This commit is contained in:
commit
b88348a55e
51 changed files with 1451 additions and 432 deletions
|
@ -7,7 +7,7 @@
|
||||||
*/
|
*/
|
||||||
return array(
|
return array(
|
||||||
'names' => array(
|
'names' => array(
|
||||||
'core.pkg.css' => '340c5b75',
|
'core.pkg.css' => 'ed7ae7bb',
|
||||||
'core.pkg.js' => 'b562c3db',
|
'core.pkg.js' => 'b562c3db',
|
||||||
'darkconsole.pkg.js' => 'e7393ebb',
|
'darkconsole.pkg.js' => 'e7393ebb',
|
||||||
'differential.pkg.css' => '3fb7f532',
|
'differential.pkg.css' => '3fb7f532',
|
||||||
|
@ -70,6 +70,7 @@ return array(
|
||||||
'rsrc/css/application/feed/feed.css' => 'ecd4ec57',
|
'rsrc/css/application/feed/feed.css' => 'ecd4ec57',
|
||||||
'rsrc/css/application/files/global-drag-and-drop.css' => '5c1b47c2',
|
'rsrc/css/application/files/global-drag-and-drop.css' => '5c1b47c2',
|
||||||
'rsrc/css/application/flag/flag.css' => '5337623f',
|
'rsrc/css/application/flag/flag.css' => '5337623f',
|
||||||
|
'rsrc/css/application/guides/guides.css' => '1d5414e5',
|
||||||
'rsrc/css/application/harbormaster/harbormaster.css' => 'f491c9f4',
|
'rsrc/css/application/harbormaster/harbormaster.css' => 'f491c9f4',
|
||||||
'rsrc/css/application/herald/herald-test.css' => 'a52e323e',
|
'rsrc/css/application/herald/herald-test.css' => 'a52e323e',
|
||||||
'rsrc/css/application/herald/herald.css' => 'dc31f6e9',
|
'rsrc/css/application/herald/herald.css' => 'dc31f6e9',
|
||||||
|
@ -112,7 +113,7 @@ return array(
|
||||||
'rsrc/css/font/font-aleo.css' => '8bdb2835',
|
'rsrc/css/font/font-aleo.css' => '8bdb2835',
|
||||||
'rsrc/css/font/font-awesome.css' => '2b7ebbcc',
|
'rsrc/css/font/font-awesome.css' => '2b7ebbcc',
|
||||||
'rsrc/css/font/font-lato.css' => 'c7ccd872',
|
'rsrc/css/font/font-lato.css' => 'c7ccd872',
|
||||||
'rsrc/css/font/phui-font-icon-base.css' => '6449bce8',
|
'rsrc/css/font/phui-font-icon-base.css' => '4e8274c4',
|
||||||
'rsrc/css/layout/phabricator-filetree-view.css' => 'fccf9f82',
|
'rsrc/css/layout/phabricator-filetree-view.css' => 'fccf9f82',
|
||||||
'rsrc/css/layout/phabricator-source-code-view.css' => 'cbeef983',
|
'rsrc/css/layout/phabricator-source-code-view.css' => 'cbeef983',
|
||||||
'rsrc/css/phui/calendar/phui-calendar-day.css' => '572b1893',
|
'rsrc/css/phui/calendar/phui-calendar-day.css' => '572b1893',
|
||||||
|
@ -127,6 +128,7 @@ return array(
|
||||||
'rsrc/css/phui/phui-box.css' => '5c8387cf',
|
'rsrc/css/phui/phui-box.css' => '5c8387cf',
|
||||||
'rsrc/css/phui/phui-button.css' => '4a5fbe3d',
|
'rsrc/css/phui/phui-button.css' => '4a5fbe3d',
|
||||||
'rsrc/css/phui/phui-chart.css' => '6bf6f78e',
|
'rsrc/css/phui/phui-chart.css' => '6bf6f78e',
|
||||||
|
'rsrc/css/phui/phui-cms.css' => 'be43c8a8',
|
||||||
'rsrc/css/phui/phui-crumbs-view.css' => '9dac418c',
|
'rsrc/css/phui/phui-crumbs-view.css' => '9dac418c',
|
||||||
'rsrc/css/phui/phui-curtain-view.css' => '7148ae25',
|
'rsrc/css/phui/phui-curtain-view.css' => '7148ae25',
|
||||||
'rsrc/css/phui/phui-document-pro.css' => 'dc3d46ed',
|
'rsrc/css/phui/phui-document-pro.css' => 'dc3d46ed',
|
||||||
|
@ -134,19 +136,19 @@ return array(
|
||||||
'rsrc/css/phui/phui-document.css' => 'c32e8dec',
|
'rsrc/css/phui/phui-document.css' => 'c32e8dec',
|
||||||
'rsrc/css/phui/phui-feed-story.css' => 'aa49845d',
|
'rsrc/css/phui/phui-feed-story.css' => 'aa49845d',
|
||||||
'rsrc/css/phui/phui-fontkit.css' => '9cda225e',
|
'rsrc/css/phui/phui-fontkit.css' => '9cda225e',
|
||||||
'rsrc/css/phui/phui-form-view.css' => 'fab0a10f',
|
'rsrc/css/phui/phui-form-view.css' => '76b4a46c',
|
||||||
'rsrc/css/phui/phui-form.css' => 'aac1d51d',
|
'rsrc/css/phui/phui-form.css' => 'aac1d51d',
|
||||||
'rsrc/css/phui/phui-head-thing.css' => 'fd311e5f',
|
'rsrc/css/phui/phui-head-thing.css' => 'fd311e5f',
|
||||||
'rsrc/css/phui/phui-header-view.css' => '06385974',
|
'rsrc/css/phui/phui-header-view.css' => '06385974',
|
||||||
'rsrc/css/phui/phui-hovercard.css' => 'de1a2119',
|
'rsrc/css/phui/phui-hovercard.css' => 'de1a2119',
|
||||||
'rsrc/css/phui/phui-icon-set-selector.css' => '1ab67aad',
|
'rsrc/css/phui/phui-icon-set-selector.css' => '1ab67aad',
|
||||||
'rsrc/css/phui/phui-icon.css' => 'd0534b71',
|
'rsrc/css/phui/phui-icon.css' => 'b1dbd620',
|
||||||
'rsrc/css/phui/phui-image-mask.css' => 'a8498f9c',
|
'rsrc/css/phui/phui-image-mask.css' => 'a8498f9c',
|
||||||
'rsrc/css/phui/phui-info-panel.css' => '27ea50a1',
|
'rsrc/css/phui/phui-info-panel.css' => '27ea50a1',
|
||||||
'rsrc/css/phui/phui-info-view.css' => '28efab79',
|
'rsrc/css/phui/phui-info-view.css' => '28efab79',
|
||||||
'rsrc/css/phui/phui-list.css' => '9da2aa00',
|
'rsrc/css/phui/phui-list.css' => '9da2aa00',
|
||||||
'rsrc/css/phui/phui-object-box.css' => '6b487c57',
|
'rsrc/css/phui/phui-object-box.css' => '6b487c57',
|
||||||
'rsrc/css/phui/phui-object-item-list-view.css' => '8d99e42b',
|
'rsrc/css/phui/phui-object-item-list-view.css' => '40010767',
|
||||||
'rsrc/css/phui/phui-pager.css' => 'bea33d23',
|
'rsrc/css/phui/phui-pager.css' => 'bea33d23',
|
||||||
'rsrc/css/phui/phui-pinboard-view.css' => '2495140e',
|
'rsrc/css/phui/phui-pinboard-view.css' => '2495140e',
|
||||||
'rsrc/css/phui/phui-profile-menu.css' => '8a3fc181',
|
'rsrc/css/phui/phui-profile-menu.css' => '8a3fc181',
|
||||||
|
@ -422,7 +424,7 @@ return array(
|
||||||
'rsrc/js/application/phortune/phortune-credit-card-form.js' => '2290aeef',
|
'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-control.js' => 'd0c516d5',
|
||||||
'rsrc/js/application/policy/behavior-policy-rule-editor.js' => '5e9f347c',
|
'rsrc/js/application/policy/behavior-policy-rule-editor.js' => '5e9f347c',
|
||||||
'rsrc/js/application/projects/WorkboardBoard.js' => '52291776',
|
'rsrc/js/application/projects/WorkboardBoard.js' => 'fe7cb52a',
|
||||||
'rsrc/js/application/projects/WorkboardCard.js' => 'c587b80f',
|
'rsrc/js/application/projects/WorkboardCard.js' => 'c587b80f',
|
||||||
'rsrc/js/application/projects/WorkboardColumn.js' => 'bae58312',
|
'rsrc/js/application/projects/WorkboardColumn.js' => 'bae58312',
|
||||||
'rsrc/js/application/projects/WorkboardController.js' => '55baf5ed',
|
'rsrc/js/application/projects/WorkboardController.js' => '55baf5ed',
|
||||||
|
@ -572,6 +574,7 @@ return array(
|
||||||
'font-fontawesome' => '2b7ebbcc',
|
'font-fontawesome' => '2b7ebbcc',
|
||||||
'font-lato' => 'c7ccd872',
|
'font-lato' => 'c7ccd872',
|
||||||
'global-drag-and-drop-css' => '5c1b47c2',
|
'global-drag-and-drop-css' => '5c1b47c2',
|
||||||
|
'guides-app-css' => '1d5414e5',
|
||||||
'harbormaster-css' => 'f491c9f4',
|
'harbormaster-css' => 'f491c9f4',
|
||||||
'herald-css' => 'dc31f6e9',
|
'herald-css' => 'dc31f6e9',
|
||||||
'herald-rule-editor' => 'd6a7e717',
|
'herald-rule-editor' => 'd6a7e717',
|
||||||
|
@ -750,7 +753,7 @@ return array(
|
||||||
'javelin-view-renderer' => '6c2b09a2',
|
'javelin-view-renderer' => '6c2b09a2',
|
||||||
'javelin-view-visitor' => 'efe49472',
|
'javelin-view-visitor' => 'efe49472',
|
||||||
'javelin-websocket' => 'e292eaf4',
|
'javelin-websocket' => 'e292eaf4',
|
||||||
'javelin-workboard-board' => '52291776',
|
'javelin-workboard-board' => 'fe7cb52a',
|
||||||
'javelin-workboard-card' => 'c587b80f',
|
'javelin-workboard-card' => 'c587b80f',
|
||||||
'javelin-workboard-column' => 'bae58312',
|
'javelin-workboard-column' => 'bae58312',
|
||||||
'javelin-workboard-controller' => '55baf5ed',
|
'javelin-workboard-controller' => '55baf5ed',
|
||||||
|
@ -832,29 +835,30 @@ return array(
|
||||||
'phui-calendar-list-css' => 'fcc9fb41',
|
'phui-calendar-list-css' => 'fcc9fb41',
|
||||||
'phui-calendar-month-css' => '8e10e92c',
|
'phui-calendar-month-css' => '8e10e92c',
|
||||||
'phui-chart-css' => '6bf6f78e',
|
'phui-chart-css' => '6bf6f78e',
|
||||||
|
'phui-cms-css' => 'be43c8a8',
|
||||||
'phui-crumbs-view-css' => '9dac418c',
|
'phui-crumbs-view-css' => '9dac418c',
|
||||||
'phui-curtain-view-css' => '7148ae25',
|
'phui-curtain-view-css' => '7148ae25',
|
||||||
'phui-document-summary-view-css' => '9ca48bdf',
|
'phui-document-summary-view-css' => '9ca48bdf',
|
||||||
'phui-document-view-css' => 'c32e8dec',
|
'phui-document-view-css' => 'c32e8dec',
|
||||||
'phui-document-view-pro-css' => 'dc3d46ed',
|
'phui-document-view-pro-css' => 'dc3d46ed',
|
||||||
'phui-feed-story-css' => 'aa49845d',
|
'phui-feed-story-css' => 'aa49845d',
|
||||||
'phui-font-icon-base-css' => '6449bce8',
|
'phui-font-icon-base-css' => '4e8274c4',
|
||||||
'phui-fontkit-css' => '9cda225e',
|
'phui-fontkit-css' => '9cda225e',
|
||||||
'phui-form-css' => 'aac1d51d',
|
'phui-form-css' => 'aac1d51d',
|
||||||
'phui-form-view-css' => 'fab0a10f',
|
'phui-form-view-css' => '76b4a46c',
|
||||||
'phui-head-thing-view-css' => 'fd311e5f',
|
'phui-head-thing-view-css' => 'fd311e5f',
|
||||||
'phui-header-view-css' => '06385974',
|
'phui-header-view-css' => '06385974',
|
||||||
'phui-hovercard' => '1bd28176',
|
'phui-hovercard' => '1bd28176',
|
||||||
'phui-hovercard-view-css' => 'de1a2119',
|
'phui-hovercard-view-css' => 'de1a2119',
|
||||||
'phui-icon-set-selector-css' => '1ab67aad',
|
'phui-icon-set-selector-css' => '1ab67aad',
|
||||||
'phui-icon-view-css' => 'd0534b71',
|
'phui-icon-view-css' => 'b1dbd620',
|
||||||
'phui-image-mask-css' => 'a8498f9c',
|
'phui-image-mask-css' => 'a8498f9c',
|
||||||
'phui-info-panel-css' => '27ea50a1',
|
'phui-info-panel-css' => '27ea50a1',
|
||||||
'phui-info-view-css' => '28efab79',
|
'phui-info-view-css' => '28efab79',
|
||||||
'phui-inline-comment-view-css' => '5953c28e',
|
'phui-inline-comment-view-css' => '5953c28e',
|
||||||
'phui-list-view-css' => '9da2aa00',
|
'phui-list-view-css' => '9da2aa00',
|
||||||
'phui-object-box-css' => '6b487c57',
|
'phui-object-box-css' => '6b487c57',
|
||||||
'phui-object-item-list-view-css' => '8d99e42b',
|
'phui-object-item-list-view-css' => '40010767',
|
||||||
'phui-pager-css' => 'bea33d23',
|
'phui-pager-css' => 'bea33d23',
|
||||||
'phui-pinboard-view-css' => '2495140e',
|
'phui-pinboard-view-css' => '2495140e',
|
||||||
'phui-profile-menu-css' => '8a3fc181',
|
'phui-profile-menu-css' => '8a3fc181',
|
||||||
|
@ -1297,15 +1301,6 @@ return array(
|
||||||
'javelin-vector',
|
'javelin-vector',
|
||||||
'javelin-typeahead-static-source',
|
'javelin-typeahead-static-source',
|
||||||
),
|
),
|
||||||
52291776 => array(
|
|
||||||
'javelin-install',
|
|
||||||
'javelin-dom',
|
|
||||||
'javelin-util',
|
|
||||||
'javelin-stratcom',
|
|
||||||
'javelin-workflow',
|
|
||||||
'phabricator-draggable-list',
|
|
||||||
'javelin-workboard-column',
|
|
||||||
),
|
|
||||||
'5359e785' => array(
|
'5359e785' => array(
|
||||||
'javelin-install',
|
'javelin-install',
|
||||||
'javelin-util',
|
'javelin-util',
|
||||||
|
@ -2219,6 +2214,15 @@ return array(
|
||||||
'javelin-view-visitor',
|
'javelin-view-visitor',
|
||||||
'javelin-util',
|
'javelin-util',
|
||||||
),
|
),
|
||||||
|
'fe7cb52a' => array(
|
||||||
|
'javelin-install',
|
||||||
|
'javelin-dom',
|
||||||
|
'javelin-util',
|
||||||
|
'javelin-stratcom',
|
||||||
|
'javelin-workflow',
|
||||||
|
'phabricator-draggable-list',
|
||||||
|
'javelin-workboard-column',
|
||||||
|
),
|
||||||
'fea0eb47' => array(
|
'fea0eb47' => array(
|
||||||
'javelin-install',
|
'javelin-install',
|
||||||
),
|
),
|
||||||
|
|
|
@ -132,7 +132,6 @@ phutil_register_library_map(array(
|
||||||
'AphrontApplicationConfiguration' => 'aphront/configuration/AphrontApplicationConfiguration.php',
|
'AphrontApplicationConfiguration' => 'aphront/configuration/AphrontApplicationConfiguration.php',
|
||||||
'AphrontBarView' => 'view/widget/bars/AphrontBarView.php',
|
'AphrontBarView' => 'view/widget/bars/AphrontBarView.php',
|
||||||
'AphrontBoolHTTPParameterType' => 'aphront/httpparametertype/AphrontBoolHTTPParameterType.php',
|
'AphrontBoolHTTPParameterType' => 'aphront/httpparametertype/AphrontBoolHTTPParameterType.php',
|
||||||
'AphrontCSRFException' => 'aphront/exception/AphrontCSRFException.php',
|
|
||||||
'AphrontCalendarEventView' => 'applications/calendar/view/AphrontCalendarEventView.php',
|
'AphrontCalendarEventView' => 'applications/calendar/view/AphrontCalendarEventView.php',
|
||||||
'AphrontController' => 'aphront/AphrontController.php',
|
'AphrontController' => 'aphront/AphrontController.php',
|
||||||
'AphrontCursorPagerView' => 'view/control/AphrontCursorPagerView.php',
|
'AphrontCursorPagerView' => 'view/control/AphrontCursorPagerView.php',
|
||||||
|
@ -1598,6 +1597,7 @@ phutil_register_library_map(array(
|
||||||
'PHUIButtonBarView' => 'view/phui/PHUIButtonBarView.php',
|
'PHUIButtonBarView' => 'view/phui/PHUIButtonBarView.php',
|
||||||
'PHUIButtonExample' => 'applications/uiexample/examples/PHUIButtonExample.php',
|
'PHUIButtonExample' => 'applications/uiexample/examples/PHUIButtonExample.php',
|
||||||
'PHUIButtonView' => 'view/phui/PHUIButtonView.php',
|
'PHUIButtonView' => 'view/phui/PHUIButtonView.php',
|
||||||
|
'PHUICMSView' => 'view/phui/PHUICMSView.php',
|
||||||
'PHUICalendarDayView' => 'view/phui/calendar/PHUICalendarDayView.php',
|
'PHUICalendarDayView' => 'view/phui/calendar/PHUICalendarDayView.php',
|
||||||
'PHUICalendarListView' => 'view/phui/calendar/PHUICalendarListView.php',
|
'PHUICalendarListView' => 'view/phui/calendar/PHUICalendarListView.php',
|
||||||
'PHUICalendarMonthView' => 'view/phui/calendar/PHUICalendarMonthView.php',
|
'PHUICalendarMonthView' => 'view/phui/calendar/PHUICalendarMonthView.php',
|
||||||
|
@ -2630,6 +2630,13 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorGlobalLock' => 'infrastructure/util/PhabricatorGlobalLock.php',
|
'PhabricatorGlobalLock' => 'infrastructure/util/PhabricatorGlobalLock.php',
|
||||||
'PhabricatorGlobalUploadTargetView' => 'applications/files/view/PhabricatorGlobalUploadTargetView.php',
|
'PhabricatorGlobalUploadTargetView' => 'applications/files/view/PhabricatorGlobalUploadTargetView.php',
|
||||||
'PhabricatorGoogleAuthProvider' => 'applications/auth/provider/PhabricatorGoogleAuthProvider.php',
|
'PhabricatorGoogleAuthProvider' => 'applications/auth/provider/PhabricatorGoogleAuthProvider.php',
|
||||||
|
'PhabricatorGuideApplication' => 'applications/guides/application/PhabricatorGuideApplication.php',
|
||||||
|
'PhabricatorGuideController' => 'applications/guides/controller/PhabricatorGuideController.php',
|
||||||
|
'PhabricatorGuideInstallController' => 'applications/guides/controller/PhabricatorGuideInstallController.php',
|
||||||
|
'PhabricatorGuideItemView' => 'applications/guides/view/PhabricatorGuideItemView.php',
|
||||||
|
'PhabricatorGuideListView' => 'applications/guides/view/PhabricatorGuideListView.php',
|
||||||
|
'PhabricatorGuideQuickStartController' => 'applications/guides/controller/PhabricatorGuideQuickStartController.php',
|
||||||
|
'PhabricatorGuideWelcomeController' => 'applications/guides/controller/PhabricatorGuideWelcomeController.php',
|
||||||
'PhabricatorHTTPParameterTypeTableView' => 'applications/config/view/PhabricatorHTTPParameterTypeTableView.php',
|
'PhabricatorHTTPParameterTypeTableView' => 'applications/config/view/PhabricatorHTTPParameterTypeTableView.php',
|
||||||
'PhabricatorHandleList' => 'applications/phid/handle/pool/PhabricatorHandleList.php',
|
'PhabricatorHandleList' => 'applications/phid/handle/pool/PhabricatorHandleList.php',
|
||||||
'PhabricatorHandleObjectSelectorDataView' => 'applications/phid/handle/view/PhabricatorHandleObjectSelectorDataView.php',
|
'PhabricatorHandleObjectSelectorDataView' => 'applications/phid/handle/view/PhabricatorHandleObjectSelectorDataView.php',
|
||||||
|
@ -4566,7 +4573,6 @@ phutil_register_library_map(array(
|
||||||
'AphrontApplicationConfiguration' => 'Phobject',
|
'AphrontApplicationConfiguration' => 'Phobject',
|
||||||
'AphrontBarView' => 'AphrontView',
|
'AphrontBarView' => 'AphrontView',
|
||||||
'AphrontBoolHTTPParameterType' => 'AphrontHTTPParameterType',
|
'AphrontBoolHTTPParameterType' => 'AphrontHTTPParameterType',
|
||||||
'AphrontCSRFException' => 'AphrontException',
|
|
||||||
'AphrontCalendarEventView' => 'AphrontView',
|
'AphrontCalendarEventView' => 'AphrontView',
|
||||||
'AphrontController' => 'Phobject',
|
'AphrontController' => 'Phobject',
|
||||||
'AphrontCursorPagerView' => 'AphrontView',
|
'AphrontCursorPagerView' => 'AphrontView',
|
||||||
|
@ -6245,6 +6251,7 @@ phutil_register_library_map(array(
|
||||||
'PHUIButtonBarView' => 'AphrontTagView',
|
'PHUIButtonBarView' => 'AphrontTagView',
|
||||||
'PHUIButtonExample' => 'PhabricatorUIExample',
|
'PHUIButtonExample' => 'PhabricatorUIExample',
|
||||||
'PHUIButtonView' => 'AphrontTagView',
|
'PHUIButtonView' => 'AphrontTagView',
|
||||||
|
'PHUICMSView' => 'AphrontTagView',
|
||||||
'PHUICalendarDayView' => 'AphrontView',
|
'PHUICalendarDayView' => 'AphrontView',
|
||||||
'PHUICalendarListView' => 'AphrontTagView',
|
'PHUICalendarListView' => 'AphrontTagView',
|
||||||
'PHUICalendarMonthView' => 'AphrontView',
|
'PHUICalendarMonthView' => 'AphrontView',
|
||||||
|
@ -7431,6 +7438,13 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorGlobalLock' => 'PhutilLock',
|
'PhabricatorGlobalLock' => 'PhutilLock',
|
||||||
'PhabricatorGlobalUploadTargetView' => 'AphrontView',
|
'PhabricatorGlobalUploadTargetView' => 'AphrontView',
|
||||||
'PhabricatorGoogleAuthProvider' => 'PhabricatorOAuth2AuthProvider',
|
'PhabricatorGoogleAuthProvider' => 'PhabricatorOAuth2AuthProvider',
|
||||||
|
'PhabricatorGuideApplication' => 'PhabricatorApplication',
|
||||||
|
'PhabricatorGuideController' => 'PhabricatorController',
|
||||||
|
'PhabricatorGuideInstallController' => 'PhabricatorGuideController',
|
||||||
|
'PhabricatorGuideItemView' => 'Phobject',
|
||||||
|
'PhabricatorGuideListView' => 'AphrontView',
|
||||||
|
'PhabricatorGuideQuickStartController' => 'PhabricatorGuideController',
|
||||||
|
'PhabricatorGuideWelcomeController' => 'PhabricatorGuideController',
|
||||||
'PhabricatorHTTPParameterTypeTableView' => 'AphrontView',
|
'PhabricatorHTTPParameterTypeTableView' => 'AphrontView',
|
||||||
'PhabricatorHandleList' => array(
|
'PhabricatorHandleList' => array(
|
||||||
'Phobject',
|
'Phobject',
|
||||||
|
|
|
@ -261,25 +261,30 @@ final class AphrontRequest extends Phobject {
|
||||||
// Add some diagnostic details so we can figure out if some CSRF issues
|
// Add some diagnostic details so we can figure out if some CSRF issues
|
||||||
// are JS problems or people accessing Ajax URIs directly with their
|
// are JS problems or people accessing Ajax URIs directly with their
|
||||||
// browsers.
|
// browsers.
|
||||||
$more_info = array();
|
$info = array();
|
||||||
|
|
||||||
|
$info[] = pht(
|
||||||
|
'You are trying to save some data to Phabricator, but the request '.
|
||||||
|
'your browser made included an incorrect token. Reload the page '.
|
||||||
|
'and try again. You may need to clear your cookies.');
|
||||||
|
|
||||||
if ($this->isAjax()) {
|
if ($this->isAjax()) {
|
||||||
$more_info[] = pht('This was an Ajax request.');
|
$info[] = pht('This was an Ajax request.');
|
||||||
} else {
|
} else {
|
||||||
$more_info[] = pht('This was a Web request.');
|
$info[] = pht('This was a Web request.');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($token) {
|
if ($token) {
|
||||||
$more_info[] = pht('This request had an invalid CSRF token.');
|
$info[] = pht('This request had an invalid CSRF token.');
|
||||||
} else {
|
} else {
|
||||||
$more_info[] = pht('This request had no CSRF token.');
|
$info[] = pht('This request had no CSRF token.');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Give a more detailed explanation of how to avoid the exception
|
// Give a more detailed explanation of how to avoid the exception
|
||||||
// in developer mode.
|
// in developer mode.
|
||||||
if (PhabricatorEnv::getEnvConfig('phabricator.developer-mode')) {
|
if (PhabricatorEnv::getEnvConfig('phabricator.developer-mode')) {
|
||||||
// TODO: Clean this up, see T1921.
|
// TODO: Clean this up, see T1921.
|
||||||
$more_info[] = pht(
|
$info[] = pht(
|
||||||
"To avoid this error, use %s to construct forms. If you are already ".
|
"To avoid this error, use %s to construct forms. If you are already ".
|
||||||
"using %s, make sure the form 'action' uses a relative URI (i.e., ".
|
"using %s, make sure the form 'action' uses a relative URI (i.e., ".
|
||||||
"begins with a '%s'). Forms using absolute URIs do not include CSRF ".
|
"begins with a '%s'). Forms using absolute URIs do not include CSRF ".
|
||||||
|
@ -299,16 +304,16 @@ final class AphrontRequest extends Phobject {
|
||||||
'setRenderAsForm(true)');
|
'setRenderAsForm(true)');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$message = implode("\n", $info);
|
||||||
|
|
||||||
// This should only be able to happen if you load a form, pull your
|
// This should only be able to happen if you load a form, pull your
|
||||||
// internet for 6 hours, and then reconnect and immediately submit,
|
// internet for 6 hours, and then reconnect and immediately submit,
|
||||||
// but give the user some indication of what happened since the workflow
|
// but give the user some indication of what happened since the workflow
|
||||||
// is incredibly confusing otherwise.
|
// is incredibly confusing otherwise.
|
||||||
throw new AphrontCSRFException(
|
throw new AphrontMalformedRequestException(
|
||||||
pht(
|
pht('Invalid Request (CSRF)'),
|
||||||
'You are trying to save some data to Phabricator, but the request '.
|
$message,
|
||||||
'your browser made included an incorrect token. Reload the page '.
|
true);
|
||||||
'and try again. You may need to clear your cookies.')."\n\n".
|
|
||||||
implode("\n", $more_info));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -480,7 +485,8 @@ final class AphrontRequest extends Phobject {
|
||||||
$configured_as = PhabricatorEnv::getEnvConfig('phabricator.base-uri');
|
$configured_as = PhabricatorEnv::getEnvConfig('phabricator.base-uri');
|
||||||
$accessed_as = $this->getHost();
|
$accessed_as = $this->getHost();
|
||||||
|
|
||||||
throw new Exception(
|
throw new AphrontMalformedRequestException(
|
||||||
|
pht('Bad Host Header'),
|
||||||
pht(
|
pht(
|
||||||
'This Phabricator install is configured as "%s", but you are '.
|
'This Phabricator install is configured as "%s", but you are '.
|
||||||
'using the domain name "%s" to access a page which is trying to '.
|
'using the domain name "%s" to access a page which is trying to '.
|
||||||
|
@ -488,7 +494,8 @@ final class AphrontRequest extends Phobject {
|
||||||
'domain or a configured alternate domain. Phabricator will not '.
|
'domain or a configured alternate domain. Phabricator will not '.
|
||||||
'set cookies on other domains for security reasons.',
|
'set cookies on other domains for security reasons.',
|
||||||
$configured_as,
|
$configured_as,
|
||||||
$accessed_as));
|
$accessed_as),
|
||||||
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
$base_domain = $base_domain_uri->getDomain();
|
$base_domain = $base_domain_uri->getDomain();
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
final class AphrontCSRFException extends AphrontException {}
|
|
|
@ -28,8 +28,18 @@ final class PhabricatorDefaultRequestExceptionHandler
|
||||||
|
|
||||||
$viewer = $this->getViewer($request);
|
$viewer = $this->getViewer($request);
|
||||||
|
|
||||||
// Always log the unhandled exception.
|
// Some types of uninteresting request exceptions don't get logged, usually
|
||||||
phlog($ex);
|
// because they are caused by the background radiation of bot traffic on
|
||||||
|
// the internet. These include requests with bad CSRF tokens and
|
||||||
|
// questionable "Host" headers.
|
||||||
|
$should_log = true;
|
||||||
|
if ($ex instanceof AphrontMalformedRequestException) {
|
||||||
|
$should_log = !$ex->getIsUnlogged();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($should_log) {
|
||||||
|
phlog($ex);
|
||||||
|
}
|
||||||
|
|
||||||
$class = get_class($ex);
|
$class = get_class($ex);
|
||||||
$message = $ex->getMessage();
|
$message = $ex->getMessage();
|
||||||
|
|
|
@ -16,7 +16,7 @@ final class AlmanacConsoleController extends AlmanacController {
|
||||||
id(new PHUIObjectItemView())
|
id(new PHUIObjectItemView())
|
||||||
->setHeader(pht('Devices'))
|
->setHeader(pht('Devices'))
|
||||||
->setHref($this->getApplicationURI('device/'))
|
->setHref($this->getApplicationURI('device/'))
|
||||||
->setIcon('fa-server')
|
->setImageIcon('fa-server')
|
||||||
->addAttribute(
|
->addAttribute(
|
||||||
pht(
|
pht(
|
||||||
'Create an inventory of physical and virtual hosts and '.
|
'Create an inventory of physical and virtual hosts and '.
|
||||||
|
@ -26,7 +26,7 @@ final class AlmanacConsoleController extends AlmanacController {
|
||||||
id(new PHUIObjectItemView())
|
id(new PHUIObjectItemView())
|
||||||
->setHeader(pht('Services'))
|
->setHeader(pht('Services'))
|
||||||
->setHref($this->getApplicationURI('service/'))
|
->setHref($this->getApplicationURI('service/'))
|
||||||
->setIcon('fa-plug')
|
->setImageIcon('fa-plug')
|
||||||
->addAttribute(
|
->addAttribute(
|
||||||
pht(
|
pht(
|
||||||
'Create and update services, and map them to interfaces on '.
|
'Create and update services, and map them to interfaces on '.
|
||||||
|
@ -36,7 +36,7 @@ final class AlmanacConsoleController extends AlmanacController {
|
||||||
id(new PHUIObjectItemView())
|
id(new PHUIObjectItemView())
|
||||||
->setHeader(pht('Networks'))
|
->setHeader(pht('Networks'))
|
||||||
->setHref($this->getApplicationURI('network/'))
|
->setHref($this->getApplicationURI('network/'))
|
||||||
->setIcon('fa-globe')
|
->setImageIcon('fa-globe')
|
||||||
->addAttribute(
|
->addAttribute(
|
||||||
pht(
|
pht(
|
||||||
'Manage public and private networks.')));
|
'Manage public and private networks.')));
|
||||||
|
@ -45,7 +45,7 @@ final class AlmanacConsoleController extends AlmanacController {
|
||||||
id(new PHUIObjectItemView())
|
id(new PHUIObjectItemView())
|
||||||
->setHeader(pht('Namespaces'))
|
->setHeader(pht('Namespaces'))
|
||||||
->setHref($this->getApplicationURI('namespace/'))
|
->setHref($this->getApplicationURI('namespace/'))
|
||||||
->setIcon('fa-asterisk')
|
->setImageIcon('fa-asterisk')
|
||||||
->addAttribute(
|
->addAttribute(
|
||||||
pht('Control who can create new named services and devices.')));
|
pht('Control who can create new named services and devices.')));
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ final class AlmanacConsoleController extends AlmanacController {
|
||||||
id(new PHUIObjectItemView())
|
id(new PHUIObjectItemView())
|
||||||
->setHeader(pht('Documentation'))
|
->setHeader(pht('Documentation'))
|
||||||
->setHref($docs_uri)
|
->setHref($docs_uri)
|
||||||
->setIcon('fa-book')
|
->setImageIcon('fa-book')
|
||||||
->addAttribute(pht('Browse documentation for Almanac.')));
|
->addAttribute(pht('Browse documentation for Almanac.')));
|
||||||
|
|
||||||
$crumbs = $this->buildApplicationCrumbs();
|
$crumbs = $this->buildApplicationCrumbs();
|
||||||
|
|
|
@ -53,7 +53,7 @@ final class PhabricatorAuthListController
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($config->getIsEnabled()) {
|
if ($config->getIsEnabled()) {
|
||||||
$item->setState(PHUIObjectItemView::STATE_SUCCESS);
|
$item->setStatusIcon('fa-check-circle green');
|
||||||
$item->addAction(
|
$item->addAction(
|
||||||
id(new PHUIListItemView())
|
id(new PHUIListItemView())
|
||||||
->setIcon('fa-times')
|
->setIcon('fa-times')
|
||||||
|
@ -61,8 +61,8 @@ final class PhabricatorAuthListController
|
||||||
->setDisabled(!$can_manage)
|
->setDisabled(!$can_manage)
|
||||||
->addSigil('workflow'));
|
->addSigil('workflow'));
|
||||||
} else {
|
} else {
|
||||||
$item->setState(PHUIObjectItemView::STATE_FAIL);
|
$item->setStatusIcon('fa-ban red');
|
||||||
$item->addIcon('fa-times grey', pht('Disabled'));
|
$item->addIcon('fa-ban grey', pht('Disabled'));
|
||||||
$item->addAction(
|
$item->addAction(
|
||||||
id(new PHUIListItemView())
|
id(new PHUIListItemView())
|
||||||
->setIcon('fa-plus')
|
->setIcon('fa-plus')
|
||||||
|
|
|
@ -464,12 +464,14 @@ abstract class PhabricatorAuthProvider extends Phobject {
|
||||||
public function getAuthCSRFCode(AphrontRequest $request) {
|
public function getAuthCSRFCode(AphrontRequest $request) {
|
||||||
$phcid = $request->getCookie(PhabricatorCookies::COOKIE_CLIENTID);
|
$phcid = $request->getCookie(PhabricatorCookies::COOKIE_CLIENTID);
|
||||||
if (!strlen($phcid)) {
|
if (!strlen($phcid)) {
|
||||||
throw new Exception(
|
throw new AphrontMalformedRequestException(
|
||||||
|
pht('Missing Client ID Cookie'),
|
||||||
pht(
|
pht(
|
||||||
'Your browser did not submit a "%s" cookie with client state '.
|
'Your browser did not submit a "%s" cookie with client state '.
|
||||||
'information in the request. Check that cookies are enabled. '.
|
'information in the request. Check that cookies are enabled. '.
|
||||||
'If this problem persists, you may need to clear your cookies.',
|
'If this problem persists, you may need to clear your cookies.',
|
||||||
PhabricatorCookies::COOKIE_CLIENTID));
|
PhabricatorCookies::COOKIE_CLIENTID),
|
||||||
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return PhabricatorHash::digest($phcid);
|
return PhabricatorHash::digest($phcid);
|
||||||
|
|
|
@ -3,6 +3,17 @@
|
||||||
abstract class ConduitListParameterType
|
abstract class ConduitListParameterType
|
||||||
extends ConduitParameterType {
|
extends ConduitParameterType {
|
||||||
|
|
||||||
|
private $allowEmptyList = true;
|
||||||
|
|
||||||
|
public function setAllowEmptyList($allow_empty_list) {
|
||||||
|
$this->allowEmptyList = $allow_empty_list;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAllowEmptyList() {
|
||||||
|
return $this->allowEmptyList;
|
||||||
|
}
|
||||||
|
|
||||||
protected function getParameterValue(array $request, $key) {
|
protected function getParameterValue(array $request, $key) {
|
||||||
$value = parent::getParameterValue($request, $key);
|
$value = parent::getParameterValue($request, $key);
|
||||||
|
|
||||||
|
@ -27,6 +38,13 @@ abstract class ConduitListParameterType
|
||||||
pht('Expected a list, but value is an object.'));
|
pht('Expected a list, but value is an object.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!$value && !$this->getAllowEmptyList()) {
|
||||||
|
$this->raiseValidationException(
|
||||||
|
$request,
|
||||||
|
$key,
|
||||||
|
pht('Expected a nonempty list, but value is an empty list.'));
|
||||||
|
}
|
||||||
|
|
||||||
return $value;
|
return $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,11 @@ abstract class ConduitParameterType extends Phobject {
|
||||||
protected function raiseValidationException(array $request, $key, $message) {
|
protected function raiseValidationException(array $request, $key, $message) {
|
||||||
// TODO: Specialize this so we can give users more tailored messages from
|
// TODO: Specialize this so we can give users more tailored messages from
|
||||||
// Conduit.
|
// Conduit.
|
||||||
throw new Exception($message);
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Error while reading "%s": %s',
|
||||||
|
$key,
|
||||||
|
$message));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,7 @@ final class PhabricatorConfigListController
|
||||||
->setHeader($group->getName())
|
->setHeader($group->getName())
|
||||||
->setHref('/config/group/'.$group->getKey().'/')
|
->setHref('/config/group/'.$group->getKey().'/')
|
||||||
->addAttribute($group->getDescription())
|
->addAttribute($group->getDescription())
|
||||||
->setIcon($group->getIcon());
|
->setImageIcon($group->getIcon());
|
||||||
$list->addItem($item);
|
$list->addItem($item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -234,7 +234,7 @@ abstract class PhabricatorApplicationConfigOptions extends Phobject {
|
||||||
if (isset($options[$key])) {
|
if (isset($options[$key])) {
|
||||||
throw new Exception(
|
throw new Exception(
|
||||||
pht(
|
pht(
|
||||||
"Mulitple %s subclasses contain an option named '%s'!",
|
"Multiple %s subclasses contain an option named '%s'!",
|
||||||
__CLASS__,
|
__CLASS__,
|
||||||
$key));
|
$key));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1533,7 +1533,7 @@ final class DifferentialTransactionEditor
|
||||||
|
|
||||||
foreach ($packages as $key => $package) {
|
foreach ($packages as $key => $package) {
|
||||||
$package_phid = $package->getPHID();
|
$package_phid = $package->getPHID();
|
||||||
if ($authority[$package_phid]) {
|
if (isset($authority[$package_phid])) {
|
||||||
unset($packages[$key]);
|
unset($packages[$key]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ final class HeraldCommitAdapter
|
||||||
protected $diff;
|
protected $diff;
|
||||||
protected $revision;
|
protected $revision;
|
||||||
|
|
||||||
protected $repository;
|
|
||||||
protected $commit;
|
protected $commit;
|
||||||
protected $commitData;
|
protected $commitData;
|
||||||
private $commitDiff;
|
private $commitDiff;
|
||||||
|
@ -42,6 +41,7 @@ final class HeraldCommitAdapter
|
||||||
|
|
||||||
public function setObject($object) {
|
public function setObject($object) {
|
||||||
$this->commit = $object;
|
$this->commit = $object;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,41 +86,26 @@ final class HeraldCommitAdapter
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTriggerObjectPHIDs() {
|
public function getTriggerObjectPHIDs() {
|
||||||
|
$project_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST;
|
||||||
|
|
||||||
return array_merge(
|
return array_merge(
|
||||||
array(
|
array(
|
||||||
$this->repository->getPHID(),
|
$this->getRepository()->getPHID(),
|
||||||
$this->getPHID(),
|
$this->getPHID(),
|
||||||
),
|
),
|
||||||
$this->repository->getProjectPHIDs());
|
$this->loadEdgePHIDs($project_type));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function explainValidTriggerObjects() {
|
public function explainValidTriggerObjects() {
|
||||||
return pht('This rule can trigger for **repositories** and **projects**.');
|
return pht('This rule can trigger for **repositories** and **projects**.');
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function newLegacyAdapter(
|
|
||||||
PhabricatorRepository $repository,
|
|
||||||
PhabricatorRepositoryCommit $commit,
|
|
||||||
PhabricatorRepositoryCommitData $commit_data) {
|
|
||||||
|
|
||||||
$object = new HeraldCommitAdapter();
|
|
||||||
|
|
||||||
$commit->attachRepository($repository);
|
|
||||||
|
|
||||||
$object->repository = $repository;
|
|
||||||
$object->commit = $commit;
|
|
||||||
$object->commitData = $commit_data;
|
|
||||||
|
|
||||||
return $object;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setCommit(PhabricatorRepositoryCommit $commit) {
|
public function setCommit(PhabricatorRepositoryCommit $commit) {
|
||||||
$viewer = PhabricatorUser::getOmnipotentUser();
|
$viewer = PhabricatorUser::getOmnipotentUser();
|
||||||
|
|
||||||
$repository = id(new PhabricatorRepositoryQuery())
|
$repository = id(new PhabricatorRepositoryQuery())
|
||||||
->setViewer($viewer)
|
->setViewer($viewer)
|
||||||
->withIDs(array($commit->getRepositoryID()))
|
->withIDs(array($commit->getRepositoryID()))
|
||||||
->needProjectPHIDs(true)
|
|
||||||
->executeOne();
|
->executeOne();
|
||||||
if (!$repository) {
|
if (!$repository) {
|
||||||
throw new Exception(pht('Unable to load repository!'));
|
throw new Exception(pht('Unable to load repository!'));
|
||||||
|
@ -137,7 +122,6 @@ final class HeraldCommitAdapter
|
||||||
$this->commit->attachRepository($repository);
|
$this->commit->attachRepository($repository);
|
||||||
$this->commit->attachCommitData($data);
|
$this->commit->attachCommitData($data);
|
||||||
|
|
||||||
$this->repository = $repository;
|
|
||||||
$this->commitData = $data;
|
$this->commitData = $data;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
|
@ -150,7 +134,7 @@ final class HeraldCommitAdapter
|
||||||
public function loadAffectedPaths() {
|
public function loadAffectedPaths() {
|
||||||
if ($this->affectedPaths === null) {
|
if ($this->affectedPaths === null) {
|
||||||
$result = PhabricatorOwnerPathQuery::loadAffectedPaths(
|
$result = PhabricatorOwnerPathQuery::loadAffectedPaths(
|
||||||
$this->repository,
|
$this->getRepository(),
|
||||||
$this->commit,
|
$this->commit,
|
||||||
PhabricatorUser::getOmnipotentUser());
|
PhabricatorUser::getOmnipotentUser());
|
||||||
$this->affectedPaths = $result;
|
$this->affectedPaths = $result;
|
||||||
|
@ -161,7 +145,7 @@ final class HeraldCommitAdapter
|
||||||
public function loadAffectedPackages() {
|
public function loadAffectedPackages() {
|
||||||
if ($this->affectedPackages === null) {
|
if ($this->affectedPackages === null) {
|
||||||
$packages = PhabricatorOwnersPackage::loadAffectedPackages(
|
$packages = PhabricatorOwnersPackage::loadAffectedPackages(
|
||||||
$this->repository,
|
$this->getRepository(),
|
||||||
$this->loadAffectedPaths());
|
$this->loadAffectedPaths());
|
||||||
$this->affectedPackages = $packages;
|
$this->affectedPackages = $packages;
|
||||||
}
|
}
|
||||||
|
@ -314,7 +298,7 @@ final class HeraldCommitAdapter
|
||||||
$drequest = DiffusionRequest::newFromDictionary(
|
$drequest = DiffusionRequest::newFromDictionary(
|
||||||
array(
|
array(
|
||||||
'user' => $viewer,
|
'user' => $viewer,
|
||||||
'repository' => $this->repository,
|
'repository' => $this->getRepository(),
|
||||||
'commit' => $this->commit->getCommitIdentifier(),
|
'commit' => $this->commit->getCommitIdentifier(),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -325,6 +309,10 @@ final class HeraldCommitAdapter
|
||||||
$params);
|
$params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getRepository() {
|
||||||
|
return $this->getObject()->getRepository();
|
||||||
|
}
|
||||||
|
|
||||||
/* -( HarbormasterBuildableAdapterInterface )------------------------------ */
|
/* -( HarbormasterBuildableAdapterInterface )------------------------------ */
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ final class DrydockConsoleController extends DrydockController {
|
||||||
$menu->addItem(
|
$menu->addItem(
|
||||||
id(new PHUIObjectItemView())
|
id(new PHUIObjectItemView())
|
||||||
->setHeader(pht('Blueprints'))
|
->setHeader(pht('Blueprints'))
|
||||||
->setIcon('fa-map-o')
|
->setImageIcon('fa-map-o')
|
||||||
->setHref($this->getApplicationURI('blueprint/'))
|
->setHref($this->getApplicationURI('blueprint/'))
|
||||||
->addAttribute(
|
->addAttribute(
|
||||||
pht(
|
pht(
|
||||||
|
@ -41,7 +41,7 @@ final class DrydockConsoleController extends DrydockController {
|
||||||
$menu->addItem(
|
$menu->addItem(
|
||||||
id(new PHUIObjectItemView())
|
id(new PHUIObjectItemView())
|
||||||
->setHeader(pht('Resources'))
|
->setHeader(pht('Resources'))
|
||||||
->setIcon('fa-map')
|
->setImageIcon('fa-map')
|
||||||
->setHref($this->getApplicationURI('resource/'))
|
->setHref($this->getApplicationURI('resource/'))
|
||||||
->addAttribute(
|
->addAttribute(
|
||||||
pht('View and manage resources Drydock has built, like hosts.')));
|
pht('View and manage resources Drydock has built, like hosts.')));
|
||||||
|
@ -49,14 +49,14 @@ final class DrydockConsoleController extends DrydockController {
|
||||||
$menu->addItem(
|
$menu->addItem(
|
||||||
id(new PHUIObjectItemView())
|
id(new PHUIObjectItemView())
|
||||||
->setHeader(pht('Leases'))
|
->setHeader(pht('Leases'))
|
||||||
->setIcon('fa-link')
|
->setImageIcon('fa-link')
|
||||||
->setHref($this->getApplicationURI('lease/'))
|
->setHref($this->getApplicationURI('lease/'))
|
||||||
->addAttribute(pht('Manage leases on resources.')));
|
->addAttribute(pht('Manage leases on resources.')));
|
||||||
|
|
||||||
$menu->addItem(
|
$menu->addItem(
|
||||||
id(new PHUIObjectItemView())
|
id(new PHUIObjectItemView())
|
||||||
->setHeader(pht('Repository Operations'))
|
->setHeader(pht('Repository Operations'))
|
||||||
->setIcon('fa-fighter-jet')
|
->setImageIcon('fa-fighter-jet')
|
||||||
->setHref($this->getApplicationURI('operation/'))
|
->setHref($this->getApplicationURI('operation/'))
|
||||||
->addAttribute(pht('Review the repository operation queue.')));
|
->addAttribute(pht('Review the repository operation queue.')));
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorGuideApplication extends PhabricatorApplication {
|
||||||
|
|
||||||
|
public function getBaseURI() {
|
||||||
|
return '/guides/';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName() {
|
||||||
|
return pht('Guides');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getShortDescription() {
|
||||||
|
return pht('Short Tutorials');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIcon() {
|
||||||
|
return 'fa-map-o';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isPrototype() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getApplicationGroup() {
|
||||||
|
return self::GROUP_UTILITIES;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRoutes() {
|
||||||
|
return array(
|
||||||
|
'/guides/' => array(
|
||||||
|
'' => 'PhabricatorGuideWelcomeController',
|
||||||
|
'install/'
|
||||||
|
=> 'PhabricatorGuideInstallController',
|
||||||
|
'quickstart/'
|
||||||
|
=> 'PhabricatorGuideQuickStartController',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class PhabricatorGuideController extends PhabricatorController {
|
||||||
|
|
||||||
|
public function buildSideNavView($filter = null, $for_app = false) {
|
||||||
|
|
||||||
|
$nav = new AphrontSideNavFilterView();
|
||||||
|
$nav->setBaseURI(new PhutilURI($this->getApplicationURI()));
|
||||||
|
$nav->addLabel(pht('Guides'));
|
||||||
|
$nav->addFilter('/', pht('Welcome'));
|
||||||
|
$nav->addFilter('install/', pht('Installation Guide'));
|
||||||
|
$nav->addFilter('quickstart/', pht('Quick Start Guide'));
|
||||||
|
|
||||||
|
return $nav;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildApplicationMenu() {
|
||||||
|
return $this->buildSideNavView(null, true)->getMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,196 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorGuideInstallController
|
||||||
|
extends PhabricatorGuideController {
|
||||||
|
|
||||||
|
public function shouldAllowPublic() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleRequest(AphrontRequest $request) {
|
||||||
|
require_celerity_resource('guides-app-css');
|
||||||
|
$viewer = $request->getViewer();
|
||||||
|
|
||||||
|
$title = pht('Installation Guide');
|
||||||
|
|
||||||
|
$nav = $this->buildSideNavView();
|
||||||
|
$nav->selectFilter('install/');
|
||||||
|
|
||||||
|
$header = id(new PHUIHeaderView())
|
||||||
|
->setHeader($title)
|
||||||
|
->setProfileHeader(true);
|
||||||
|
|
||||||
|
$crumbs = $this->buildApplicationCrumbs()
|
||||||
|
->addTextCrumb(pht('Installation'));
|
||||||
|
|
||||||
|
$content = $this->getGuideContent($viewer);
|
||||||
|
|
||||||
|
$view = id(new PHUICMSView())
|
||||||
|
->setCrumbs($crumbs)
|
||||||
|
->setNavigation($nav)
|
||||||
|
->setHeader($header)
|
||||||
|
->setContent($content);
|
||||||
|
|
||||||
|
return $this->newPage()
|
||||||
|
->setTitle($title)
|
||||||
|
->addClass('phui-cms-body')
|
||||||
|
->appendChild($view);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getGuideContent($viewer) {
|
||||||
|
$guide_items = new PhabricatorGuideListView();
|
||||||
|
|
||||||
|
$title = pht('Resolve Setup Issues');
|
||||||
|
$issues_resolved = !PhabricatorSetupCheck::getOpenSetupIssueKeys();
|
||||||
|
$href = PhabricatorEnv::getURI('/config/issue/');
|
||||||
|
if ($issues_resolved) {
|
||||||
|
$icon = 'fa-check';
|
||||||
|
$icon_bg = 'bg-green';
|
||||||
|
$skip = null;
|
||||||
|
$description = pht(
|
||||||
|
"You've resolved (or ignored) all outstanding setup issues.");
|
||||||
|
} else {
|
||||||
|
$icon = 'fa-warning';
|
||||||
|
$icon_bg = 'bg-red';
|
||||||
|
$skip = '#';
|
||||||
|
$description =
|
||||||
|
pht('You have some unresolved setup issues to take care of.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$item = id(new PhabricatorGuideItemView())
|
||||||
|
->setTitle($title)
|
||||||
|
->setHref($href)
|
||||||
|
->setIcon($icon)
|
||||||
|
->setIconBackground($icon_bg)
|
||||||
|
->setSkipHref($skip)
|
||||||
|
->setDescription($description);
|
||||||
|
$guide_items->addItem($item);
|
||||||
|
|
||||||
|
$configs = id(new PhabricatorAuthProviderConfigQuery())
|
||||||
|
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$title = pht('Login and Registration');
|
||||||
|
$href = PhabricatorEnv::getURI('/auth/');
|
||||||
|
$have_auth = (bool)$configs;
|
||||||
|
if ($have_auth) {
|
||||||
|
$icon = 'fa-check';
|
||||||
|
$icon_bg = 'bg-green';
|
||||||
|
$skip = null;
|
||||||
|
$description = pht(
|
||||||
|
"You've configured at least one authentication provider.");
|
||||||
|
} else {
|
||||||
|
$icon = 'fa-key';
|
||||||
|
$icon_bg = 'bg-sky';
|
||||||
|
$skip = '#';
|
||||||
|
$description = pht(
|
||||||
|
'Authentication providers allow users to register accounts and '.
|
||||||
|
'log in to Phabricator.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$item = id(new PhabricatorGuideItemView())
|
||||||
|
->setTitle($title)
|
||||||
|
->setHref($href)
|
||||||
|
->setIcon($icon)
|
||||||
|
->setIconBackground($icon_bg)
|
||||||
|
->setSkipHref($skip)
|
||||||
|
->setDescription($description);
|
||||||
|
$guide_items->addItem($item);
|
||||||
|
|
||||||
|
|
||||||
|
$title = pht('Configure Phabricator');
|
||||||
|
$href = PhabricatorEnv::getURI('/config/');
|
||||||
|
|
||||||
|
// Just load any config value at all; if one exists the install has figured
|
||||||
|
// out how to configure things.
|
||||||
|
$have_config = (bool)id(new PhabricatorConfigEntry())->loadAllWhere(
|
||||||
|
'1 = 1 LIMIT 1');
|
||||||
|
|
||||||
|
if ($have_config) {
|
||||||
|
$icon = 'fa-check';
|
||||||
|
$icon_bg = 'bg-green';
|
||||||
|
$skip = null;
|
||||||
|
$description = pht(
|
||||||
|
"You've configured at least one setting from the web interface.");
|
||||||
|
} else {
|
||||||
|
$icon = 'fa-sliders';
|
||||||
|
$icon_bg = 'bg-sky';
|
||||||
|
$skip = '#';
|
||||||
|
$description = pht(
|
||||||
|
'Learn how to configure mail and other options in Phabricator.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$item = id(new PhabricatorGuideItemView())
|
||||||
|
->setTitle($title)
|
||||||
|
->setHref($href)
|
||||||
|
->setIcon($icon)
|
||||||
|
->setIconBackground($icon_bg)
|
||||||
|
->setSkipHref($skip)
|
||||||
|
->setDescription($description);
|
||||||
|
$guide_items->addItem($item);
|
||||||
|
|
||||||
|
|
||||||
|
$title = pht('User Account Settings');
|
||||||
|
$href = PhabricatorEnv::getURI('/settings/');
|
||||||
|
$preferences = id(new PhabricatorUserPreferencesQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withUsers(array($viewer))
|
||||||
|
->executeOne();
|
||||||
|
|
||||||
|
$have_settings = ($preferences && $preferences->getPreferences());
|
||||||
|
if ($have_settings) {
|
||||||
|
$icon = 'fa-check';
|
||||||
|
$icon_bg = 'bg-green';
|
||||||
|
$skip = null;
|
||||||
|
$description = pht(
|
||||||
|
"You've adjusted at least one setting on your account.");
|
||||||
|
} else {
|
||||||
|
$icon = 'fa-wrench';
|
||||||
|
$icon_bg = 'bg-sky';
|
||||||
|
$skip = '#';
|
||||||
|
$description = pht(
|
||||||
|
'Configure account settings for all users, or just yourself');
|
||||||
|
}
|
||||||
|
|
||||||
|
$item = id(new PhabricatorGuideItemView())
|
||||||
|
->setTitle($title)
|
||||||
|
->setHref($href)
|
||||||
|
->setIcon($icon)
|
||||||
|
->setIconBackground($icon_bg)
|
||||||
|
->setSkipHref($skip)
|
||||||
|
->setDescription($description);
|
||||||
|
$guide_items->addItem($item);
|
||||||
|
|
||||||
|
|
||||||
|
$title = pht('Notification Server');
|
||||||
|
$href = PhabricatorEnv::getURI('/config/notifications/');
|
||||||
|
// TODO: Wire up a notifications check
|
||||||
|
$have_notifications = false;
|
||||||
|
if ($have_notifications) {
|
||||||
|
$icon = 'fa-check';
|
||||||
|
$icon_bg = 'bg-green';
|
||||||
|
$skip = null;
|
||||||
|
$description = pht(
|
||||||
|
"You've set up a real-time notification server.");
|
||||||
|
} else {
|
||||||
|
$icon = 'fa-bell';
|
||||||
|
$icon_bg = 'bg-sky';
|
||||||
|
$skip = '#';
|
||||||
|
$description = pht(
|
||||||
|
'Phabricator can deliver notifications in real-time with WebSockets.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$item = id(new PhabricatorGuideItemView())
|
||||||
|
->setTitle($title)
|
||||||
|
->setHref($href)
|
||||||
|
->setIcon($icon)
|
||||||
|
->setIconBackground($icon_bg)
|
||||||
|
->setSkipHref($skip)
|
||||||
|
->setDescription($description);
|
||||||
|
|
||||||
|
$guide_items->addItem($item);
|
||||||
|
|
||||||
|
return $guide_items;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,210 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorGuideQuickStartController
|
||||||
|
extends PhabricatorGuideController {
|
||||||
|
|
||||||
|
public function shouldAllowPublic() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleRequest(AphrontRequest $request) {
|
||||||
|
require_celerity_resource('guides-app-css');
|
||||||
|
$viewer = $request->getViewer();
|
||||||
|
|
||||||
|
$title = pht('Quick Start Guide');
|
||||||
|
|
||||||
|
$nav = $this->buildSideNavView();
|
||||||
|
$nav->selectFilter('quickstart/');
|
||||||
|
|
||||||
|
$header = id(new PHUIHeaderView())
|
||||||
|
->setHeader($title)
|
||||||
|
->setProfileHeader(true);
|
||||||
|
|
||||||
|
$crumbs = $this->buildApplicationCrumbs()
|
||||||
|
->addTextCrumb(pht('Quick Start'));
|
||||||
|
|
||||||
|
$content = $this->getGuideContent($viewer);
|
||||||
|
|
||||||
|
$view = id(new PHUICMSView())
|
||||||
|
->setCrumbs($crumbs)
|
||||||
|
->setNavigation($nav)
|
||||||
|
->setHeader($header)
|
||||||
|
->setContent($content);
|
||||||
|
|
||||||
|
return $this->newPage()
|
||||||
|
->setTitle($title)
|
||||||
|
->addClass('phui-cms-body')
|
||||||
|
->appendChild($view);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getGuideContent($viewer) {
|
||||||
|
$guide_items = new PhabricatorGuideListView();
|
||||||
|
|
||||||
|
$title = pht('Configure Applications');
|
||||||
|
$apps_check = true;
|
||||||
|
$href = PhabricatorEnv::getURI('/applications/');
|
||||||
|
if ($apps_check) {
|
||||||
|
$icon = 'fa-check';
|
||||||
|
$icon_bg = 'bg-green';
|
||||||
|
$skip = null;
|
||||||
|
$description = pht(
|
||||||
|
"You've uninstalled any unneeded applications for now.");
|
||||||
|
} else {
|
||||||
|
$icon = 'fa-globe';
|
||||||
|
$icon_bg = 'bg-sky';
|
||||||
|
$skip = '#';
|
||||||
|
$description =
|
||||||
|
pht('Use all our applications, or uninstall the ones you don\'t want.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$item = id(new PhabricatorGuideItemView())
|
||||||
|
->setTitle($title)
|
||||||
|
->setHref($href)
|
||||||
|
->setIcon($icon)
|
||||||
|
->setIconBackground($icon_bg)
|
||||||
|
->setSkipHref($skip)
|
||||||
|
->setDescription($description);
|
||||||
|
$guide_items->addItem($item);
|
||||||
|
|
||||||
|
|
||||||
|
$title = pht('Invite Collaborators');
|
||||||
|
$people_check = true;
|
||||||
|
$href = PhabricatorEnv::getURI('/people/invite/');
|
||||||
|
if ($people_check) {
|
||||||
|
$icon = 'fa-check';
|
||||||
|
$icon_bg = 'bg-green';
|
||||||
|
$skip = null;
|
||||||
|
$description = pht(
|
||||||
|
'You will not be alone on this journey.');
|
||||||
|
} else {
|
||||||
|
$icon = 'fa-group';
|
||||||
|
$icon_bg = 'bg-sky';
|
||||||
|
$skip = '#';
|
||||||
|
$description =
|
||||||
|
pht('Invite the rest of your team to get started on Phabricator.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$item = id(new PhabricatorGuideItemView())
|
||||||
|
->setTitle($title)
|
||||||
|
->setHref($href)
|
||||||
|
->setIcon($icon)
|
||||||
|
->setIconBackground($icon_bg)
|
||||||
|
->setSkipHref($skip)
|
||||||
|
->setDescription($description);
|
||||||
|
$guide_items->addItem($item);
|
||||||
|
|
||||||
|
|
||||||
|
$title = pht('Create a Repository');
|
||||||
|
$repository_check = true;
|
||||||
|
$href = PhabricatorEnv::getURI('/diffusion/');
|
||||||
|
if ($repository_check) {
|
||||||
|
$icon = 'fa-check';
|
||||||
|
$icon_bg = 'bg-green';
|
||||||
|
$skip = null;
|
||||||
|
$description = pht(
|
||||||
|
"You've created at least one repository.");
|
||||||
|
} else {
|
||||||
|
$icon = 'fa-code';
|
||||||
|
$icon_bg = 'bg-sky';
|
||||||
|
$skip = '#';
|
||||||
|
$description =
|
||||||
|
pht('If you are here for code review, let\'s set up your first '.
|
||||||
|
'repository.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$item = id(new PhabricatorGuideItemView())
|
||||||
|
->setTitle($title)
|
||||||
|
->setHref($href)
|
||||||
|
->setIcon($icon)
|
||||||
|
->setIconBackground($icon_bg)
|
||||||
|
->setSkipHref($skip)
|
||||||
|
->setDescription($description);
|
||||||
|
$guide_items->addItem($item);
|
||||||
|
|
||||||
|
|
||||||
|
$title = pht('Create a Project');
|
||||||
|
$project_check = true;
|
||||||
|
$href = PhabricatorEnv::getURI('/project/');
|
||||||
|
if ($project_check) {
|
||||||
|
$icon = 'fa-check';
|
||||||
|
$icon_bg = 'bg-green';
|
||||||
|
$skip = null;
|
||||||
|
$description = pht(
|
||||||
|
"You've created at least one project.");
|
||||||
|
} else {
|
||||||
|
$icon = 'fa-briefcase';
|
||||||
|
$icon_bg = 'bg-sky';
|
||||||
|
$skip = '#';
|
||||||
|
$description =
|
||||||
|
pht('Project tags define everything. Create them for teams, tags, '.
|
||||||
|
'or actual projects.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$item = id(new PhabricatorGuideItemView())
|
||||||
|
->setTitle($title)
|
||||||
|
->setHref($href)
|
||||||
|
->setIcon($icon)
|
||||||
|
->setIconBackground($icon_bg)
|
||||||
|
->setSkipHref($skip)
|
||||||
|
->setDescription($description);
|
||||||
|
$guide_items->addItem($item);
|
||||||
|
|
||||||
|
|
||||||
|
$title = pht('Build a Dashboard');
|
||||||
|
$dashboard_check = true;
|
||||||
|
$href = PhabricatorEnv::getURI('/dashboard/');
|
||||||
|
if ($dashboard_check) {
|
||||||
|
$icon = 'fa-check';
|
||||||
|
$icon_bg = 'bg-green';
|
||||||
|
$skip = null;
|
||||||
|
$description = pht(
|
||||||
|
"You've created at least one dashboard.");
|
||||||
|
} else {
|
||||||
|
$icon = 'fa-dashboard';
|
||||||
|
$icon_bg = 'bg-sky';
|
||||||
|
$skip = '#';
|
||||||
|
$description =
|
||||||
|
pht('Customize the default homepage layout and items.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$item = id(new PhabricatorGuideItemView())
|
||||||
|
->setTitle($title)
|
||||||
|
->setHref($href)
|
||||||
|
->setIcon($icon)
|
||||||
|
->setIconBackground($icon_bg)
|
||||||
|
->setSkipHref($skip)
|
||||||
|
->setDescription($description);
|
||||||
|
$guide_items->addItem($item);
|
||||||
|
|
||||||
|
|
||||||
|
$title = pht('Personalize your Install');
|
||||||
|
$ui_check = true;
|
||||||
|
$href = PhabricatorEnv::getURI('/config/group/ui/');
|
||||||
|
if ($dashboard_check) {
|
||||||
|
$icon = 'fa-check';
|
||||||
|
$icon_bg = 'bg-green';
|
||||||
|
$skip = null;
|
||||||
|
$description = pht(
|
||||||
|
'It looks amazing, good work. Home Sweet Home.');
|
||||||
|
} else {
|
||||||
|
$icon = 'fa-home';
|
||||||
|
$icon_bg = 'bg-sky';
|
||||||
|
$skip = '#';
|
||||||
|
$description =
|
||||||
|
pht('Change the name and add your company logo, just to give it a '.
|
||||||
|
'little extra polish.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$item = id(new PhabricatorGuideItemView())
|
||||||
|
->setTitle($title)
|
||||||
|
->setHref($href)
|
||||||
|
->setIcon($icon)
|
||||||
|
->setIconBackground($icon_bg)
|
||||||
|
->setSkipHref($skip)
|
||||||
|
->setDescription($description);
|
||||||
|
$guide_items->addItem($item);
|
||||||
|
|
||||||
|
return $guide_items;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorGuideWelcomeController
|
||||||
|
extends PhabricatorGuideController {
|
||||||
|
|
||||||
|
public function shouldAllowPublic() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleRequest(AphrontRequest $request) {
|
||||||
|
require_celerity_resource('guides-app-css');
|
||||||
|
$viewer = $request->getViewer();
|
||||||
|
|
||||||
|
$title = pht('Welcome to Phabricator');
|
||||||
|
|
||||||
|
$nav = $this->buildSideNavView();
|
||||||
|
$nav->selectFilter('/');
|
||||||
|
|
||||||
|
$header = id(new PHUIHeaderView())
|
||||||
|
->setHeader($title)
|
||||||
|
->setProfileHeader(true);
|
||||||
|
|
||||||
|
$crumbs = $this->buildApplicationCrumbs()
|
||||||
|
->addTextCrumb(pht('Welcome'));
|
||||||
|
|
||||||
|
$content = id(new PHUIDocumentViewPro())
|
||||||
|
->appendChild($this->getGuideContent($viewer));
|
||||||
|
|
||||||
|
$view = id(new PHUICMSView())
|
||||||
|
->setCrumbs($crumbs)
|
||||||
|
->setNavigation($nav)
|
||||||
|
->setHeader($header)
|
||||||
|
->setContent($content);
|
||||||
|
|
||||||
|
return $this->newPage()
|
||||||
|
->setTitle($title)
|
||||||
|
->addClass('phui-cms-body')
|
||||||
|
->appendChild($view);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getGuideContent($viewer) {
|
||||||
|
|
||||||
|
$content = pht(
|
||||||
|
'You have successfully installed Phabricator. These next guides will '.
|
||||||
|
'take you through configuration and new user orientation. '.
|
||||||
|
'These steps are optional, and you can go through them in any order. '.
|
||||||
|
'If you want to get back to this guide later on, you can find it in '.
|
||||||
|
'the **Config** application under **Welcome Guide**.');
|
||||||
|
|
||||||
|
return new PHUIRemarkupView($viewer, $content);
|
||||||
|
}
|
||||||
|
}
|
67
src/applications/guides/view/PhabricatorGuideItemView.php
Normal file
67
src/applications/guides/view/PhabricatorGuideItemView.php
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorGuideItemView extends Phobject {
|
||||||
|
|
||||||
|
private $title;
|
||||||
|
private $href;
|
||||||
|
private $description;
|
||||||
|
private $icon;
|
||||||
|
private $iconBackground;
|
||||||
|
private $skipHref;
|
||||||
|
|
||||||
|
public function setTitle($title) {
|
||||||
|
$this->title = $title;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setDescription($description) {
|
||||||
|
$this->description = $description;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setHref($href) {
|
||||||
|
$this->href = $href;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setIcon($icon) {
|
||||||
|
$this->icon = $icon;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setIconBackground($background) {
|
||||||
|
$this->iconBackground = $background;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setSkipHref($href) {
|
||||||
|
$this->skipHref = $href;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitle() {
|
||||||
|
return $this->title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDescription() {
|
||||||
|
return $this->description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getHref() {
|
||||||
|
return $this->href;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIcon() {
|
||||||
|
return $this->icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIconBackground() {
|
||||||
|
return $this->iconBackground;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSkipHref() {
|
||||||
|
return $this->skipHref;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
45
src/applications/guides/view/PhabricatorGuideListView.php
Normal file
45
src/applications/guides/view/PhabricatorGuideListView.php
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorGuideListView extends AphrontView {
|
||||||
|
|
||||||
|
private $items = array();
|
||||||
|
|
||||||
|
public function addItem(PhabricatorGuideItemView $item) {
|
||||||
|
$this->items[] = $item;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render() {
|
||||||
|
require_celerity_resource('guides-app-css');
|
||||||
|
|
||||||
|
$list = id(new PHUIObjectItemListView())
|
||||||
|
->addClass('guides-app');
|
||||||
|
|
||||||
|
foreach ($this->items as $item) {
|
||||||
|
$icon = id(new PHUIIconView())
|
||||||
|
->setIcon($item->getIcon())
|
||||||
|
->setBackground($item->getIconBackground());
|
||||||
|
|
||||||
|
$list_item = id(new PHUIObjectItemView())
|
||||||
|
->setHeader($item->getTitle())
|
||||||
|
->setHref($item->getHref())
|
||||||
|
->setImageIcon($icon)
|
||||||
|
->addAttribute($item->getDescription());
|
||||||
|
|
||||||
|
$skip_href = $item->getSkipHref();
|
||||||
|
if ($skip_href) {
|
||||||
|
$skip = id(new PHUIButtonView())
|
||||||
|
->setText(pht('Skip'))
|
||||||
|
->setTag('a')
|
||||||
|
->setHref($skip_href)
|
||||||
|
->setColor(PHUIButtonView::GREY);
|
||||||
|
$list_item->setLaunchButton($skip);
|
||||||
|
}
|
||||||
|
$list->addItem($list_item);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $list;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -61,6 +61,10 @@ final class HarbormasterBuildSearchEngine
|
||||||
$query->withBuildPlanPHIDs($map['plans']);
|
$query->withBuildPlanPHIDs($map['plans']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($map['buildables']) {
|
||||||
|
$query->withBuildablePHIDs($map['buildables']);
|
||||||
|
}
|
||||||
|
|
||||||
if ($map['statuses']) {
|
if ($map['statuses']) {
|
||||||
$query->withBuildStatuses($map['statuses']);
|
$query->withBuildStatuses($map['statuses']);
|
||||||
}
|
}
|
||||||
|
|
|
@ -214,18 +214,6 @@ final class PhabricatorAppSearchEngine
|
||||||
$icon = 'application';
|
$icon = 'application';
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: This sheet doesn't work the same way other sheets do so it
|
|
||||||
// ends up with the wrong classes if we try to use PHUIIconView. This
|
|
||||||
// is probably all changing in the redesign anyway.
|
|
||||||
|
|
||||||
$icon_view = javelin_tag(
|
|
||||||
'span',
|
|
||||||
array(
|
|
||||||
'class' => 'phui-icon-view phui-font-fa '.$icon,
|
|
||||||
'aural' => false,
|
|
||||||
),
|
|
||||||
'');
|
|
||||||
|
|
||||||
$description = $application->getShortDescription();
|
$description = $application->getShortDescription();
|
||||||
|
|
||||||
$configure = id(new PHUIButtonView())
|
$configure = id(new PHUIButtonView())
|
||||||
|
@ -241,7 +229,7 @@ final class PhabricatorAppSearchEngine
|
||||||
|
|
||||||
$item = id(new PHUIObjectItemView())
|
$item = id(new PHUIObjectItemView())
|
||||||
->setHeader($name)
|
->setHeader($name)
|
||||||
->setImageIcon($icon_view)
|
->setImageIcon($icon)
|
||||||
->setSubhead($description)
|
->setSubhead($description)
|
||||||
->setLaunchButton($configure);
|
->setLaunchButton($configure);
|
||||||
|
|
||||||
|
|
|
@ -61,15 +61,21 @@ final class PHUIHandleTagListView extends AphrontTagView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->limit && (count($handles) > $this->limit)) {
|
// We may be passed a PhabricatorHandleList; if we are, convert it into
|
||||||
if (!is_array($handles)) {
|
// a normal array.
|
||||||
$handles = iterator_to_array($handles);
|
if (!is_array($handles)) {
|
||||||
}
|
$handles = iterator_to_array($handles);
|
||||||
$handles = array_slice($handles, 0, $this->limit);
|
}
|
||||||
|
|
||||||
|
$over_limit = $this->limit && (count($handles) > $this->limit);
|
||||||
|
if ($over_limit) {
|
||||||
|
$visible = array_slice($handles, 0, $this->limit);
|
||||||
|
} else {
|
||||||
|
$visible = $handles;
|
||||||
}
|
}
|
||||||
|
|
||||||
$list = array();
|
$list = array();
|
||||||
foreach ($handles as $handle) {
|
foreach ($visible as $handle) {
|
||||||
$tag = $handle->renderTag();
|
$tag = $handle->renderTag();
|
||||||
if ($this->showHovercards) {
|
if ($this->showHovercards) {
|
||||||
$tag->setPHID($handle->getPHID());
|
$tag->setPHID($handle->getPHID());
|
||||||
|
@ -84,21 +90,21 @@ final class PHUIHandleTagListView extends AphrontTagView {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->limit) {
|
if ($over_limit) {
|
||||||
if (count($this->handles) > $this->limit) {
|
$tip_text = implode(', ', mpull($handles, 'getName'));
|
||||||
$tip_text = implode(', ', mpull($this->handles, 'getName'));
|
|
||||||
|
|
||||||
$more = $this->newPlaceholderTag()
|
Javelin::initBehavior('phabricator-tooltips');
|
||||||
->setName("\xE2\x80\xA6")
|
|
||||||
->addSigil('has-tooltip')
|
|
||||||
->setMetadata(
|
|
||||||
array(
|
|
||||||
'tip' => $tip_text,
|
|
||||||
'size' => 200,
|
|
||||||
));
|
|
||||||
|
|
||||||
$list[] = $this->newItem($more);
|
$more = $this->newPlaceholderTag()
|
||||||
}
|
->setName("\xE2\x80\xA6")
|
||||||
|
->addSigil('has-tooltip')
|
||||||
|
->setMetadata(
|
||||||
|
array(
|
||||||
|
'tip' => $tip_text,
|
||||||
|
'size' => 200,
|
||||||
|
));
|
||||||
|
|
||||||
|
$list[] = $this->newItem($more);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $list;
|
return $list;
|
||||||
|
|
|
@ -19,6 +19,10 @@ final class PhabricatorRepositoryManagementMovePathsWorkflow
|
||||||
'param' => 'prefix',
|
'param' => 'prefix',
|
||||||
'help' => pht('Replace matching prefixes with this string.'),
|
'help' => pht('Replace matching prefixes with this string.'),
|
||||||
),
|
),
|
||||||
|
array(
|
||||||
|
'name' => 'force',
|
||||||
|
'help' => pht('Apply changes without prompting.'),
|
||||||
|
),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,6 +51,8 @@ final class PhabricatorRepositoryManagementMovePathsWorkflow
|
||||||
'You must specify a path prefix to move to with --to.'));
|
'You must specify a path prefix to move to with --to.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$is_force = $args->getArg('force');
|
||||||
|
|
||||||
$rows = array();
|
$rows = array();
|
||||||
|
|
||||||
$any_changes = false;
|
$any_changes = false;
|
||||||
|
@ -118,7 +124,7 @@ final class PhabricatorRepositoryManagementMovePathsWorkflow
|
||||||
}
|
}
|
||||||
|
|
||||||
$prompt = pht('Apply these changes?');
|
$prompt = pht('Apply these changes?');
|
||||||
if (!phutil_console_confirm($prompt)) {
|
if (!$is_force && !phutil_console_confirm($prompt)) {
|
||||||
throw new Exception(pht('Declining to apply changes.'));
|
throw new Exception(pht('Declining to apply changes.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,8 @@ final class PhabricatorIDsSearchField
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function newConduitParameterType() {
|
protected function newConduitParameterType() {
|
||||||
return new ConduitIntListParameterType();
|
return id(new ConduitIntListParameterType())
|
||||||
|
->setAllowEmptyList(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,8 @@ final class PhabricatorPHIDsSearchField
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function newConduitParameterType() {
|
protected function newConduitParameterType() {
|
||||||
return new ConduitPHIDListParameterType();
|
return id(new ConduitPHIDListParameterType())
|
||||||
|
->setAllowEmptyList(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,8 @@ final class PhabricatorSearchDatasourceField
|
||||||
|
|
||||||
protected function newConduitParameterType() {
|
protected function newConduitParameterType() {
|
||||||
if (!$this->conduitParameterType) {
|
if (!$this->conduitParameterType) {
|
||||||
return new ConduitStringListParameterType();
|
return id(new ConduitStringListParameterType())
|
||||||
|
->setAllowEmptyList(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->conduitParameterType;
|
return $this->conduitParameterType;
|
||||||
|
|
|
@ -62,11 +62,14 @@ final class PhabricatorUserPreferencesSearchEngine
|
||||||
->setViewer($viewer);
|
->setViewer($viewer);
|
||||||
foreach ($settings as $setting) {
|
foreach ($settings as $setting) {
|
||||||
|
|
||||||
|
$icon = id(new PHUIIconView())
|
||||||
|
->setIcon('fa-globe')
|
||||||
|
->setBackground('bg-sky');
|
||||||
|
|
||||||
$item = id(new PHUIObjectItemView())
|
$item = id(new PHUIObjectItemView())
|
||||||
->setHeader($setting->getDisplayName())
|
->setHeader($setting->getDisplayName())
|
||||||
->setHref($setting->getEditURI())
|
->setHref($setting->getEditURI())
|
||||||
->setImageURI(PhabricatorUser::getDefaultProfileImageURI())
|
->setImageIcon($icon)
|
||||||
->setIcon('fa-globe')
|
|
||||||
->addAttribute(pht('Edit global default settings for all users.'));
|
->addAttribute(pht('Edit global default settings for all users.'));
|
||||||
|
|
||||||
$list->addItem($item);
|
$list->addItem($item);
|
||||||
|
|
|
@ -9,7 +9,7 @@ final class PhabricatorEditorMultipleSetting
|
||||||
const VALUE_SINGLE = 'disable';
|
const VALUE_SINGLE = 'disable';
|
||||||
|
|
||||||
public function getSettingName() {
|
public function getSettingName() {
|
||||||
return pht('Edit Mulitple Files');
|
return pht('Edit Multiple Files');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getSettingPanelKey() {
|
public function getSettingPanelKey() {
|
||||||
|
|
|
@ -130,6 +130,17 @@ final class PHUIIconExample extends PhabricatorUIExample {
|
||||||
->addClass('mmr');
|
->addClass('mmr');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$squares = array('fa-briefcase', 'fa-code', 'fa-globe', 'fa-home');
|
||||||
|
$squareview = array();
|
||||||
|
foreach ($squares as $icon) {
|
||||||
|
$squareview[] =
|
||||||
|
id(new PHUIIconView())
|
||||||
|
->setIcon($icon)
|
||||||
|
->setBackground('bg-blue')
|
||||||
|
->setHref('#')
|
||||||
|
->addClass('mmr');
|
||||||
|
}
|
||||||
|
|
||||||
$layout_cicons = id(new PHUIBoxView())
|
$layout_cicons = id(new PHUIBoxView())
|
||||||
->appendChild($cicons)
|
->appendChild($cicons)
|
||||||
->addMargin(PHUI::MARGIN_LARGE);
|
->addMargin(PHUI::MARGIN_LARGE);
|
||||||
|
@ -155,6 +166,10 @@ final class PHUIIconExample extends PhabricatorUIExample {
|
||||||
->addMargin(PHUI::MARGIN_MEDIUM);
|
->addMargin(PHUI::MARGIN_MEDIUM);
|
||||||
|
|
||||||
$layout5 = id(new PHUIBoxView())
|
$layout5 = id(new PHUIBoxView())
|
||||||
|
->appendChild($squareview)
|
||||||
|
->addMargin(PHUI::MARGIN_MEDIUM);
|
||||||
|
|
||||||
|
$layout6 = id(new PHUIBoxView())
|
||||||
->appendChild($loginview)
|
->appendChild($loginview)
|
||||||
->addMargin(PHUI::MARGIN_MEDIUM);
|
->addMargin(PHUI::MARGIN_MEDIUM);
|
||||||
|
|
||||||
|
@ -187,9 +202,13 @@ final class PHUIIconExample extends PhabricatorUIExample {
|
||||||
->appendChild($layout4);
|
->appendChild($layout4);
|
||||||
|
|
||||||
$wrap5 = id(new PHUIObjectBoxView())
|
$wrap5 = id(new PHUIObjectBoxView())
|
||||||
->setHeaderText(pht('Authentication'))
|
->setHeaderText(pht('Squares'))
|
||||||
->appendChild($layout5);
|
->appendChild($layout5);
|
||||||
|
|
||||||
|
$wrap6 = id(new PHUIObjectBoxView())
|
||||||
|
->setHeaderText(pht('Authentication'))
|
||||||
|
->appendChild($layout6);
|
||||||
|
|
||||||
return phutil_tag(
|
return phutil_tag(
|
||||||
'div',
|
'div',
|
||||||
array(
|
array(
|
||||||
|
@ -202,6 +221,7 @@ final class PHUIIconExample extends PhabricatorUIExample {
|
||||||
$wrap3,
|
$wrap3,
|
||||||
$wrap4,
|
$wrap4,
|
||||||
$wrap5,
|
$wrap5,
|
||||||
|
$wrap6,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -340,55 +340,6 @@ final class PHUIObjectItemListExample extends PhabricatorUIExample {
|
||||||
|
|
||||||
$out[] = $box;
|
$out[] = $box;
|
||||||
|
|
||||||
$list = id(new PHUIObjectItemListView())
|
|
||||||
->setStates(true);
|
|
||||||
|
|
||||||
$list->addItem(
|
|
||||||
id(new PHUIObjectItemView())
|
|
||||||
->setObjectName('X1200')
|
|
||||||
->setHeader(pht('Action Passed'))
|
|
||||||
->addAttribute(pht('That went swimmingly, go you'))
|
|
||||||
->setHref('#')
|
|
||||||
->setState(PHUIObjectItemView::STATE_SUCCESS));
|
|
||||||
|
|
||||||
$list->addItem(
|
|
||||||
id(new PHUIObjectItemView())
|
|
||||||
->setObjectName('X1201')
|
|
||||||
->setHeader(pht('Action Failed'))
|
|
||||||
->addAttribute(pht('Whoopsies, might want to fix that'))
|
|
||||||
->setHref('#')
|
|
||||||
->setState(PHUIObjectItemView::STATE_FAIL));
|
|
||||||
|
|
||||||
$list->addItem(
|
|
||||||
id(new PHUIObjectItemView())
|
|
||||||
->setObjectName('X1202')
|
|
||||||
->setHeader(pht('Action Warning'))
|
|
||||||
->addAttribute(pht('We need to talk about things'))
|
|
||||||
->setHref('#')
|
|
||||||
->setState(PHUIObjectItemView::STATE_WARN));
|
|
||||||
|
|
||||||
$list->addItem(
|
|
||||||
id(new PHUIObjectItemView())
|
|
||||||
->setObjectName('X1203')
|
|
||||||
->setHeader(pht('Action Noted'))
|
|
||||||
->addAttribute(pht('The weather seems nice today'))
|
|
||||||
->setHref('#')
|
|
||||||
->setState(PHUIObjectItemView::STATE_NOTE));
|
|
||||||
|
|
||||||
$list->addItem(
|
|
||||||
id(new PHUIObjectItemView())
|
|
||||||
->setObjectName('X1203')
|
|
||||||
->setHeader(pht('Action In Progress'))
|
|
||||||
->addAttribute(pht('Outlook fuzzy, try again later'))
|
|
||||||
->setHref('#')
|
|
||||||
->setState(PHUIObjectItemView::STATE_BUILD));
|
|
||||||
|
|
||||||
$box = id(new PHUIObjectBoxView())
|
|
||||||
->setHeaderText(pht('State Icons'))
|
|
||||||
->setObjectList($list);
|
|
||||||
|
|
||||||
$out[] = array($box);
|
|
||||||
|
|
||||||
return $out;
|
return $out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -367,7 +367,7 @@ produce a consistent message about a common error state in a convenient way.
|
||||||
|
|
||||||
There are a handful of error strings in the codebase which may be used before
|
There are a handful of error strings in the codebase which may be used before
|
||||||
the translation framework is loaded, or may be used during handling other
|
the translation framework is loaded, or may be used during handling other
|
||||||
errors, possibly rasised from within the translation framework. This handful
|
errors, possibly raised from within the translation framework. This handful
|
||||||
of special cases are left untranslated to prevent fatals and cycles in the
|
of special cases are left untranslated to prevent fatals and cycles in the
|
||||||
error handler.
|
error handler.
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,8 @@
|
||||||
Adjust environmental settings (SSL, remote IP, rate limiting) using a preamble
|
Adjust environmental settings (SSL, remote IP, rate limiting) using a preamble
|
||||||
script.
|
script.
|
||||||
|
|
||||||
= Overview =
|
Overview
|
||||||
|
========
|
||||||
|
|
||||||
If Phabricator is deployed in an environment where HTTP headers behave oddly
|
If Phabricator is deployed in an environment where HTTP headers behave oddly
|
||||||
(usually, because it is behind a load balancer), it may not be able to detect
|
(usually, because it is behind a load balancer), it may not be able to detect
|
||||||
|
@ -37,27 +38,52 @@ If present, this script will be executed at the very beginning of each web
|
||||||
request, allowing you to adjust the environment. For common adjustments and
|
request, allowing you to adjust the environment. For common adjustments and
|
||||||
examples, see the next sections.
|
examples, see the next sections.
|
||||||
|
|
||||||
= Adjusting Client IPs =
|
Adjusting Client IPs
|
||||||
|
====================
|
||||||
|
|
||||||
If your install is behind a load balancer, Phabricator may incorrectly detect
|
If your install is behind a load balancer, Phabricator may incorrectly detect
|
||||||
all requests as originating from the load balancer, rather than from the correct
|
all requests as originating from the load balancer, rather than from the
|
||||||
client IPs. If this is the case and some other header (like `X-Forwarded-For`)
|
correct client IPs.
|
||||||
is known to be trustworthy, you can overwrite the `REMOTE_ADDR` setting so
|
|
||||||
Phabricator can figure out the client IP correctly:
|
If this is the case and some other header (like `X-Forwarded-For`) is known to
|
||||||
|
be trustworthy, you can read the header and overwrite the `REMOTE_ADDR` value
|
||||||
|
so Phabricator can figure out the client IP correctly.
|
||||||
|
|
||||||
|
You should do this //only// if the `X-Forwarded-For` header is known to be
|
||||||
|
trustworthy. In particular, if users can make requests to the web server
|
||||||
|
directly, they can provide an arbitrary `X-Forwarded-For` header, and thereby
|
||||||
|
spoof an arbitrary client IP.
|
||||||
|
|
||||||
|
The `X-Forwarded-For` header may also contain a list of addresses if a request
|
||||||
|
has been forwarded through multiple loadbalancers. Using a snippet like this
|
||||||
|
will usually handle most situations correctly:
|
||||||
|
|
||||||
```
|
```
|
||||||
name=Overwrite REMOTE_ADDR with X-Forwarded-For
|
name=Overwrite REMOTE_ADDR with X-Forwarded-For
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
$_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_FORWARDED_FOR'];
|
// Overwrite REMOTE_ADDR with the value in the "X-Forwarded-For" HTTP header.
|
||||||
|
|
||||||
|
// Only do this if you're certain the request is coming from a loadbalancer!
|
||||||
|
// If the request came directly from a client, doing this will allow them to
|
||||||
|
// them spoof any remote address.
|
||||||
|
|
||||||
|
// The header may contain a list of IPs, like "1.2.3.4, 4.5.6.7", if the
|
||||||
|
// request the load balancer received also had this header.
|
||||||
|
|
||||||
|
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
|
||||||
|
$forwarded_for = $_SERVER['HTTP_X_FORWARDED_FOR'];
|
||||||
|
if ($forwarded_for) {
|
||||||
|
$forwarded_for = explode(',', $forwarded_for);
|
||||||
|
$forwarded_for = end($forwarded_for);
|
||||||
|
$forwarded_for = trim($forwarded_for);
|
||||||
|
$_SERVER['REMOTE_ADDR'] = $forwarded_for;
|
||||||
|
}
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
You should do this //only// if the `X-Forwarded-For` header is always
|
Adjusting SSL
|
||||||
trustworthy. In particular, if users can make requests to the web server
|
=============
|
||||||
directly, they can provide an arbitrary `X-Forwarded-For` header, and thereby
|
|
||||||
spoof an arbitrary client IP.
|
|
||||||
|
|
||||||
= Adjusting SSL =
|
|
||||||
|
|
||||||
If your install is behind an SSL terminating load balancer, Phabricator may
|
If your install is behind an SSL terminating load balancer, Phabricator may
|
||||||
detect requests as HTTP when the client sees them as HTTPS. This can cause
|
detect requests as HTTP when the client sees them as HTTPS. This can cause
|
||||||
|
@ -76,38 +102,9 @@ $_SERVER['HTTPS'] = true;
|
||||||
You can also set this value to `false` to explicitly tell Phabricator that a
|
You can also set this value to `false` to explicitly tell Phabricator that a
|
||||||
request is not an SSL request.
|
request is not an SSL request.
|
||||||
|
|
||||||
= Adjusting Rate Limiting =
|
|
||||||
|
|
||||||
Phabricator performs coarse, IP-based rate limiting by default. In most
|
Next Steps
|
||||||
situations the default settings should be reasonable: they are set fairly high,
|
==========
|
||||||
and intended to prevent only significantly abusive behavior.
|
|
||||||
|
|
||||||
However, if legitimate traffic is being rate limited (or you want to make the
|
|
||||||
limits more strict) you can adjust the limits in the preamble script.
|
|
||||||
|
|
||||||
```
|
|
||||||
name=Adjust Rate Limiting Behavior
|
|
||||||
<?php
|
|
||||||
|
|
||||||
// The default is 1000, so a value of 2000 increases the limit by a factor
|
|
||||||
// of 2: users will be able to make twice as many requests before being
|
|
||||||
// rate limited.
|
|
||||||
|
|
||||||
// You can set the limit to 0 to disable rate limiting.
|
|
||||||
|
|
||||||
PhabricatorStartup::setMaximumRate(2000);
|
|
||||||
```
|
|
||||||
|
|
||||||
By examining `$_SERVER['REMOTE_ADDR']` or similar parameters, you could also
|
|
||||||
adjust the rate limit dynamically: for example, remove it for requests from an
|
|
||||||
internal network, but impose a strict limit for external requests.
|
|
||||||
|
|
||||||
Rate limiting needs to be configured in this way in order to make it as cheap as
|
|
||||||
possible to activate after a client is rate limited. The limiting checks execute
|
|
||||||
before any libraries or configuration are loaded, and can emit a response within
|
|
||||||
a few milliseconds.
|
|
||||||
|
|
||||||
= Next Steps =
|
|
||||||
|
|
||||||
Continue by:
|
Continue by:
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,24 @@ not necessarily that the repository is still importing.
|
||||||
- //Field Not Present// This commit was processed before we implemented
|
- //Field Not Present// This commit was processed before we implemented
|
||||||
this diagnostic feature, and no information is available.
|
this diagnostic feature, and no information is available.
|
||||||
|
|
||||||
|
|
||||||
|
Manually Closing Revisions
|
||||||
|
==========================
|
||||||
|
|
||||||
|
If autoclose didn't activate for some reason and you want to manually close
|
||||||
|
revisions, you can do so in several ways:
|
||||||
|
|
||||||
|
**Close Revision**: The revision author can use the "Close Revision" action
|
||||||
|
from the web UI, located in the action dropdown on the revision page (where
|
||||||
|
reviewers would "Accept Revision" or "Request Changes").
|
||||||
|
|
||||||
|
`differential.always-allow-close`: If you set this option in {nav Config},
|
||||||
|
any user can take the "Close Revision" action in the web UI.
|
||||||
|
|
||||||
|
`arc close-revision`: You can close revisions from the command line by using
|
||||||
|
`arc close-revision`.
|
||||||
|
|
||||||
|
|
||||||
Next Steps
|
Next Steps
|
||||||
==========
|
==========
|
||||||
|
|
||||||
|
|
|
@ -104,6 +104,8 @@ final class PhabricatorWorkerArchiveTaskQuery
|
||||||
|
|
||||||
if ($this->dateCreatedBefore) {
|
if ($this->dateCreatedBefore) {
|
||||||
return qsprintf($conn_r, 'ORDER BY dateCreated DESC, id DESC');
|
return qsprintf($conn_r, 'ORDER BY dateCreated DESC, id DESC');
|
||||||
|
} else if ($this->dateModifiedSince) {
|
||||||
|
return qsprintf($conn_r, 'ORDER BY dateModified DESC, id DESC');
|
||||||
} else {
|
} else {
|
||||||
return qsprintf($conn_r, 'ORDER BY id DESC');
|
return qsprintf($conn_r, 'ORDER BY id DESC');
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,9 @@ final class PhabricatorWorkerArchiveTask extends PhabricatorWorkerTask {
|
||||||
'leaseOwner' => array(
|
'leaseOwner' => array(
|
||||||
'columns' => array('leaseOwner', 'priority', 'id'),
|
'columns' => array('leaseOwner', 'priority', 'id'),
|
||||||
),
|
),
|
||||||
|
'key_modified' => array(
|
||||||
|
'columns' => array('dateModified'),
|
||||||
|
),
|
||||||
) + $parent[self::CONFIG_KEY_SCHEMA];
|
) + $parent[self::CONFIG_KEY_SCHEMA];
|
||||||
|
|
||||||
return $config;
|
return $config;
|
||||||
|
|
|
@ -16,6 +16,26 @@ final class PhabricatorStorageManagementDumpWorkflow
|
||||||
'Add __--master-data__ to the __mysqldump__ command, '.
|
'Add __--master-data__ to the __mysqldump__ command, '.
|
||||||
'generating a CHANGE MASTER statement in the output.'),
|
'generating a CHANGE MASTER statement in the output.'),
|
||||||
),
|
),
|
||||||
|
array(
|
||||||
|
'name' => 'output',
|
||||||
|
'param' => 'file',
|
||||||
|
'help' => pht(
|
||||||
|
'Write output directly to disk. This handles errors better '.
|
||||||
|
'than using pipes. Use with __--compress__ to gzip the '.
|
||||||
|
'output.'),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'name' => 'compress',
|
||||||
|
'help' => pht(
|
||||||
|
'With __--output__, write a compressed file to disk instead '.
|
||||||
|
'of a plaintext file.'),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'name' => 'overwrite',
|
||||||
|
'help' => pht(
|
||||||
|
'With __--output__, overwrite the output file if it already '.
|
||||||
|
'exists.'),
|
||||||
|
),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,6 +75,38 @@ final class PhabricatorStorageManagementDumpWorkflow
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$output_file = $args->getArg('output');
|
||||||
|
$is_compress = $args->getArg('compress');
|
||||||
|
$is_overwrite = $args->getArg('overwrite');
|
||||||
|
|
||||||
|
if ($is_compress) {
|
||||||
|
if ($output_file === null) {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
pht(
|
||||||
|
'The "--compress" flag can only be used alongside "--output".'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($is_overwrite) {
|
||||||
|
if ($output_file === null) {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
pht(
|
||||||
|
'The "--overwrite" flag can only be used alongside "--output".'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($output_file !== null) {
|
||||||
|
if (Filesystem::pathExists($output_file)) {
|
||||||
|
if (!$is_overwrite) {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
pht(
|
||||||
|
'Output file "%s" already exists. Use "--overwrite" '.
|
||||||
|
'to overwrite.',
|
||||||
|
$output_file));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$argv = array();
|
$argv = array();
|
||||||
$argv[] = '--hex-blob';
|
$argv[] = '--hex-blob';
|
||||||
$argv[] = '--single-transaction';
|
$argv[] = '--single-transaction';
|
||||||
|
@ -79,13 +131,83 @@ final class PhabricatorStorageManagementDumpWorkflow
|
||||||
$argv[] = $database;
|
$argv[] = $database;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if ($has_password) {
|
if ($has_password) {
|
||||||
$err = phutil_passthru('mysqldump -p%P %Ls', $password, $argv);
|
$command = csprintf('mysqldump -p%P %Ls', $password, $argv);
|
||||||
} else {
|
} else {
|
||||||
$err = phutil_passthru('mysqldump %Ls', $argv);
|
$command = csprintf('mysqldump %Ls', $argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $err;
|
// If we aren't writing to a file, just passthru the command.
|
||||||
|
if ($output_file === null) {
|
||||||
|
return phutil_passthru('%C', $command);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we are writing to a file, stream the command output to disk. This
|
||||||
|
// mode makes sure the whole command fails if there's an error (commonly,
|
||||||
|
// a full disk). See T6996 for discussion.
|
||||||
|
|
||||||
|
if ($is_compress) {
|
||||||
|
$file = gzopen($output_file, 'wb');
|
||||||
|
} else {
|
||||||
|
$file = fopen($output_file, 'wb');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$file) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Failed to open file "%s" for writing.',
|
||||||
|
$file));
|
||||||
|
}
|
||||||
|
|
||||||
|
$future = new ExecFuture('%C', $command);
|
||||||
|
|
||||||
|
$lines = new LinesOfALargeExecFuture($future);
|
||||||
|
|
||||||
|
try {
|
||||||
|
foreach ($lines as $line) {
|
||||||
|
$line = $line."\n";
|
||||||
|
if ($is_compress) {
|
||||||
|
$ok = gzwrite($file, $line);
|
||||||
|
} else {
|
||||||
|
$ok = fwrite($file, $line);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($ok !== strlen($line)) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Failed to write %d byte(s) to file "%s".',
|
||||||
|
new PhutilNumber(strlen($line)),
|
||||||
|
$output_file));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($is_compress) {
|
||||||
|
$ok = gzclose($file);
|
||||||
|
} else {
|
||||||
|
$ok = fclose($file);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($ok !== true) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Failed to close file "%s".',
|
||||||
|
$output_file));
|
||||||
|
}
|
||||||
|
} catch (Exception $ex) {
|
||||||
|
// If we might have written a partial file to disk, try to remove it so
|
||||||
|
// we don't leave any confusing artifacts laying around.
|
||||||
|
|
||||||
|
try {
|
||||||
|
Filesystem::remove($output_file);
|
||||||
|
} catch (Exception $ex) {
|
||||||
|
// Ignore any errors we hit.
|
||||||
|
}
|
||||||
|
|
||||||
|
throw $ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,15 +8,20 @@ final class PhabricatorStorageManagementRenamespaceWorkflow
|
||||||
->setName('renamespace')
|
->setName('renamespace')
|
||||||
->setExamples(
|
->setExamples(
|
||||||
'**renamespace** [__options__] '.
|
'**renamespace** [__options__] '.
|
||||||
'--in __dump.sql__ --from __old__ --to __new__ > __out.sql__')
|
'--input __dump.sql__ --from __old__ --to __new__ > __out.sql__')
|
||||||
->setSynopsis(pht('Change the database namespace of a .sql dump file.'))
|
->setSynopsis(pht('Change the database namespace of a .sql dump file.'))
|
||||||
->setArguments(
|
->setArguments(
|
||||||
array(
|
array(
|
||||||
array(
|
array(
|
||||||
'name' => 'in',
|
'name' => 'input',
|
||||||
'param' => 'file',
|
'param' => 'file',
|
||||||
'help' => pht('SQL dumpfile to process.'),
|
'help' => pht('SQL dumpfile to process.'),
|
||||||
),
|
),
|
||||||
|
array(
|
||||||
|
'name' => 'live',
|
||||||
|
'help' => pht(
|
||||||
|
'Generate a live dump instead of processing a file on disk.'),
|
||||||
|
),
|
||||||
array(
|
array(
|
||||||
'name' => 'from',
|
'name' => 'from',
|
||||||
'param' => 'namespace',
|
'param' => 'namespace',
|
||||||
|
@ -27,6 +32,21 @@ final class PhabricatorStorageManagementRenamespaceWorkflow
|
||||||
'param' => 'namespace',
|
'param' => 'namespace',
|
||||||
'help' => pht('Desired database namespace for output.'),
|
'help' => pht('Desired database namespace for output.'),
|
||||||
),
|
),
|
||||||
|
array(
|
||||||
|
'name' => 'output',
|
||||||
|
'param' => 'file',
|
||||||
|
'help' => pht('Write output directly to a file on disk.'),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'name' => 'compress',
|
||||||
|
'help' => pht('Emit gzipped output instead of plain text.'),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'name' => 'overwrite',
|
||||||
|
'help' => pht(
|
||||||
|
'With __--output__, write to disk even if the file already '.
|
||||||
|
'exists.'),
|
||||||
|
),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,12 +57,13 @@ final class PhabricatorStorageManagementRenamespaceWorkflow
|
||||||
public function didExecute(PhutilArgumentParser $args) {
|
public function didExecute(PhutilArgumentParser $args) {
|
||||||
$console = PhutilConsole::getConsole();
|
$console = PhutilConsole::getConsole();
|
||||||
|
|
||||||
$in = $args->getArg('in');
|
$input = $args->getArg('input');
|
||||||
if (!strlen($in)) {
|
$is_live = $args->getArg('live');
|
||||||
|
if (!strlen($input) && !$is_live) {
|
||||||
throw new PhutilArgumentUsageException(
|
throw new PhutilArgumentUsageException(
|
||||||
pht(
|
pht(
|
||||||
'Specify the dumpfile to read with %s.',
|
'Specify the dumpfile to read with "--in", or use "--live" to '.
|
||||||
'--in'));
|
'generate one automatically.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$from = $args->getArg('from');
|
$from = $args->getArg('from');
|
||||||
|
@ -61,6 +82,62 @@ final class PhabricatorStorageManagementRenamespaceWorkflow
|
||||||
'--to'));
|
'--to'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$output_file = $args->getArg('output');
|
||||||
|
$is_overwrite = $args->getArg('overwrite');
|
||||||
|
$is_compress = $args->getArg('compress');
|
||||||
|
|
||||||
|
if ($is_overwrite) {
|
||||||
|
if ($output_file === null) {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
pht(
|
||||||
|
'The "--overwrite" flag can only be used alongside "--output".'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($output_file !== null) {
|
||||||
|
if (Filesystem::pathExists($output_file)) {
|
||||||
|
if (!$is_overwrite) {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
pht(
|
||||||
|
'Output file "%s" already exists. Use "--overwrite" '.
|
||||||
|
'to overwrite.',
|
||||||
|
$output_file));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($is_live) {
|
||||||
|
$root = dirname(phutil_get_library_root('phabricator'));
|
||||||
|
|
||||||
|
$future = new ExecFuture(
|
||||||
|
'%R dump',
|
||||||
|
$root.'/bin/storage');
|
||||||
|
|
||||||
|
$lines = new LinesOfALargeExecFuture($future);
|
||||||
|
} else {
|
||||||
|
$lines = new LinesOfALargeFile($input);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($output_file === null) {
|
||||||
|
$file = fopen('php://stdout', 'wb');
|
||||||
|
$output_name = pht('stdout');
|
||||||
|
} else {
|
||||||
|
if ($is_compress) {
|
||||||
|
$file = gzopen($output_file, 'wb');
|
||||||
|
} else {
|
||||||
|
$file = fopen($output_file, 'wb');
|
||||||
|
}
|
||||||
|
$output_name = $output_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$file) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Failed to open output file "%s" for writing.',
|
||||||
|
$output_name));
|
||||||
|
}
|
||||||
|
|
||||||
$patterns = array(
|
$patterns = array(
|
||||||
'use' => '@^(USE `)([^_]+)(_.*)$@',
|
'use' => '@^(USE `)([^_]+)(_.*)$@',
|
||||||
'create' => '@^(CREATE DATABASE /\*.*?\*/ `)([^_]+)(_.*)$@',
|
'create' => '@^(CREATE DATABASE /\*.*?\*/ `)([^_]+)(_.*)$@',
|
||||||
|
@ -68,27 +145,66 @@ final class PhabricatorStorageManagementRenamespaceWorkflow
|
||||||
|
|
||||||
$found = array_fill_keys(array_keys($patterns), 0);
|
$found = array_fill_keys(array_keys($patterns), 0);
|
||||||
|
|
||||||
$matches = null;
|
try {
|
||||||
foreach (new LinesOfALargeFile($in) as $line) {
|
$matches = null;
|
||||||
|
foreach ($lines as $line) {
|
||||||
|
|
||||||
foreach ($patterns as $key => $pattern) {
|
foreach ($patterns as $key => $pattern) {
|
||||||
if (preg_match($pattern, $line, $matches)) {
|
if (preg_match($pattern, $line, $matches)) {
|
||||||
$namespace = $matches[2];
|
$namespace = $matches[2];
|
||||||
if ($namespace != $from) {
|
if ($namespace != $from) {
|
||||||
throw new Exception(
|
throw new Exception(
|
||||||
pht(
|
pht(
|
||||||
'Expected namespace "%s", found "%s": %s.',
|
'Expected namespace "%s", found "%s": %s.',
|
||||||
$from,
|
$from,
|
||||||
$namespace,
|
$namespace,
|
||||||
$line));
|
$line));
|
||||||
|
}
|
||||||
|
|
||||||
|
$line = $matches[1].$to.$matches[3];
|
||||||
|
$found[$key]++;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$line = $matches[1].$to.$matches[3];
|
$data = $line."\n";
|
||||||
$found[$key]++;
|
|
||||||
|
if ($is_compress) {
|
||||||
|
$bytes = gzwrite($file, $data);
|
||||||
|
} else {
|
||||||
|
$bytes = fwrite($file, $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($bytes !== strlen($data)) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Failed to write %d byte(s) to "%s".',
|
||||||
|
new PhutilNumber(strlen($data)),
|
||||||
|
$output_name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
echo $line."\n";
|
if ($is_compress) {
|
||||||
|
$ok = gzclose($file);
|
||||||
|
} else {
|
||||||
|
$ok = fclose($file);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($ok !== true) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Failed to close file "%s".',
|
||||||
|
$output_file));
|
||||||
|
}
|
||||||
|
} catch (Exception $ex) {
|
||||||
|
try {
|
||||||
|
if ($output_file !== null) {
|
||||||
|
Filesystem::remove($output_file);
|
||||||
|
}
|
||||||
|
} catch (Exception $ex) {
|
||||||
|
// Ignore any exception.
|
||||||
|
}
|
||||||
|
|
||||||
|
throw $ex;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Give the user a chance to catch things if the results are crazy.
|
// Give the user a chance to catch things if the results are crazy.
|
||||||
|
|
118
src/view/phui/PHUICMSView.php
Normal file
118
src/view/phui/PHUICMSView.php
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PHUICMSView extends AphrontTagView {
|
||||||
|
|
||||||
|
private $header;
|
||||||
|
private $nav;
|
||||||
|
private $crumbs;
|
||||||
|
private $content;
|
||||||
|
private $toc;
|
||||||
|
private $comments;
|
||||||
|
|
||||||
|
public function setHeader(PHUIHeaderView $header) {
|
||||||
|
$this->header = $header;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setNavigation(AphrontSideNavFilterView $nav) {
|
||||||
|
$this->nav = $nav;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setCrumbs(PHUICrumbsView $crumbs) {
|
||||||
|
$this->crumbs = $crumbs;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setContent($content) {
|
||||||
|
$this->content = $content;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setToc($toc) {
|
||||||
|
$this->toc = $toc;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setComments($comments) {
|
||||||
|
$this->comments = $comments;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getTagName() {
|
||||||
|
return 'div';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getTagAttributes() {
|
||||||
|
require_celerity_resource('phui-cms-css');
|
||||||
|
|
||||||
|
$classes = array();
|
||||||
|
$classes[] = 'phui-cms-view';
|
||||||
|
|
||||||
|
if ($this->comments) {
|
||||||
|
$classes[] = 'phui-cms-has-comments';
|
||||||
|
}
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'class' => implode(' ', $classes),
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getTagContent() {
|
||||||
|
|
||||||
|
$content = phutil_tag(
|
||||||
|
'div',
|
||||||
|
array(
|
||||||
|
'class' => 'phui-cms-page-content',
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
$this->header,
|
||||||
|
$this->content,
|
||||||
|
));
|
||||||
|
|
||||||
|
$comments = null;
|
||||||
|
if ($this->comments) {
|
||||||
|
$comments = phutil_tag(
|
||||||
|
'div',
|
||||||
|
array(
|
||||||
|
'class' => 'phui-cms-comments',
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
$this->comments,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
$navigation = $this->nav;
|
||||||
|
$navigation->appendChild($content);
|
||||||
|
$navigation->appendChild($comments);
|
||||||
|
|
||||||
|
$page = phutil_tag(
|
||||||
|
'div',
|
||||||
|
array(
|
||||||
|
'class' => 'phui-cms-inner',
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
$navigation,
|
||||||
|
));
|
||||||
|
|
||||||
|
$cms_view = phutil_tag(
|
||||||
|
'div',
|
||||||
|
array(
|
||||||
|
'class' => 'phui-cms-wrap',
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
$this->crumbs,
|
||||||
|
$page,
|
||||||
|
));
|
||||||
|
|
||||||
|
$classes = array();
|
||||||
|
$classes[] = 'phui-cms-page';
|
||||||
|
|
||||||
|
return phutil_tag(
|
||||||
|
'div',
|
||||||
|
array(
|
||||||
|
'class' => implode(' ', $classes),
|
||||||
|
),
|
||||||
|
$cms_view);
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,6 +17,7 @@ final class PHUIIconView extends AphrontTagView {
|
||||||
private $spriteSheet;
|
private $spriteSheet;
|
||||||
private $iconFont;
|
private $iconFont;
|
||||||
private $iconColor;
|
private $iconColor;
|
||||||
|
private $iconBackground;
|
||||||
|
|
||||||
public function setHref($href) {
|
public function setHref($href) {
|
||||||
$this->href = $href;
|
$this->href = $href;
|
||||||
|
@ -54,6 +55,11 @@ final class PHUIIconView extends AphrontTagView {
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setBackground($color) {
|
||||||
|
$this->iconBackground = $color;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
protected function getTagName() {
|
protected function getTagName() {
|
||||||
$tag = 'span';
|
$tag = 'span';
|
||||||
if ($this->href) {
|
if ($this->href) {
|
||||||
|
@ -79,6 +85,10 @@ final class PHUIIconView extends AphrontTagView {
|
||||||
if ($this->iconColor) {
|
if ($this->iconColor) {
|
||||||
$classes[] = $this->iconColor;
|
$classes[] = $this->iconColor;
|
||||||
}
|
}
|
||||||
|
if ($this->iconBackground) {
|
||||||
|
$classes[] = 'phui-icon-square';
|
||||||
|
$classes[] = $this->iconBackground;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if ($this->headSize) {
|
if ($this->headSize) {
|
||||||
$classes[] = $this->headSize;
|
$classes[] = $this->headSize;
|
||||||
|
|
|
@ -9,7 +9,6 @@ final class PHUIObjectItemListView extends AphrontTagView {
|
||||||
private $flush;
|
private $flush;
|
||||||
private $simple;
|
private $simple;
|
||||||
private $allowEmptyList;
|
private $allowEmptyList;
|
||||||
private $states;
|
|
||||||
private $itemClass = 'phui-object-item-standard';
|
private $itemClass = 'phui-object-item-standard';
|
||||||
|
|
||||||
public function setAllowEmptyList($allow_empty_list) {
|
public function setAllowEmptyList($allow_empty_list) {
|
||||||
|
@ -51,11 +50,6 @@ final class PHUIObjectItemListView extends AphrontTagView {
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setStates($states) {
|
|
||||||
$this->states = $states;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setItemClass($item_class) {
|
public function setItemClass($item_class) {
|
||||||
$this->itemClass = $item_class;
|
$this->itemClass = $item_class;
|
||||||
return $this;
|
return $this;
|
||||||
|
@ -69,9 +63,6 @@ final class PHUIObjectItemListView extends AphrontTagView {
|
||||||
$classes = array();
|
$classes = array();
|
||||||
|
|
||||||
$classes[] = 'phui-object-item-list-view';
|
$classes[] = 'phui-object-item-list-view';
|
||||||
if ($this->states) {
|
|
||||||
$classes[] = 'phui-object-list-states';
|
|
||||||
}
|
|
||||||
if ($this->flush) {
|
if ($this->flush) {
|
||||||
$classes[] = 'phui-object-list-flush';
|
$classes[] = 'phui-object-list-flush';
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,8 +19,6 @@ final class PHUIObjectItemView extends AphrontTagView {
|
||||||
private $headIcons = array();
|
private $headIcons = array();
|
||||||
private $disabled;
|
private $disabled;
|
||||||
private $imageURI;
|
private $imageURI;
|
||||||
private $state;
|
|
||||||
private $fontIcon;
|
|
||||||
private $imageIcon;
|
private $imageIcon;
|
||||||
private $titleText;
|
private $titleText;
|
||||||
private $badge;
|
private $badge;
|
||||||
|
@ -29,16 +27,6 @@ final class PHUIObjectItemView extends AphrontTagView {
|
||||||
private $launchButton;
|
private $launchButton;
|
||||||
private $coverImage;
|
private $coverImage;
|
||||||
|
|
||||||
const AGE_FRESH = 'fresh';
|
|
||||||
const AGE_STALE = 'stale';
|
|
||||||
const AGE_OLD = 'old';
|
|
||||||
|
|
||||||
const STATE_SUCCESS = 'green';
|
|
||||||
const STATE_FAIL = 'red';
|
|
||||||
const STATE_WARN = 'yellow';
|
|
||||||
const STATE_NOTE = 'blue';
|
|
||||||
const STATE_BUILD = 'sky';
|
|
||||||
|
|
||||||
public function setDisabled($disabled) {
|
public function setDisabled($disabled) {
|
||||||
$this->disabled = $disabled;
|
$this->disabled = $disabled;
|
||||||
return $this;
|
return $this;
|
||||||
|
@ -143,6 +131,10 @@ final class PHUIObjectItemView extends AphrontTagView {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setImageIcon($image_icon) {
|
public function setImageIcon($image_icon) {
|
||||||
|
if (!$image_icon instanceof PHUIIconView) {
|
||||||
|
$image_icon = id(new PHUIIconView())
|
||||||
|
->setIcon($image_icon);
|
||||||
|
}
|
||||||
$this->imageIcon = $image_icon;
|
$this->imageIcon = $image_icon;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
@ -156,63 +148,9 @@ final class PHUIObjectItemView extends AphrontTagView {
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setState($state) {
|
public function setEpoch($epoch) {
|
||||||
$this->state = $state;
|
|
||||||
switch ($state) {
|
|
||||||
case self::STATE_SUCCESS:
|
|
||||||
$fi = 'fa-check-circle green';
|
|
||||||
break;
|
|
||||||
case self::STATE_FAIL:
|
|
||||||
$fi = 'fa-times-circle red';
|
|
||||||
break;
|
|
||||||
case self::STATE_WARN:
|
|
||||||
$fi = 'fa-exclamation-circle yellow';
|
|
||||||
break;
|
|
||||||
case self::STATE_NOTE:
|
|
||||||
$fi = 'fa-info-circle blue';
|
|
||||||
break;
|
|
||||||
case self::STATE_BUILD:
|
|
||||||
$fi = 'fa-refresh ph-spin sky';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
$this->setIcon($fi);
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setIcon($icon) {
|
|
||||||
$this->fontIcon = id(new PHUIIconView())
|
|
||||||
->setIcon($icon);
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setEpoch($epoch, $age = self::AGE_FRESH) {
|
|
||||||
$date = phabricator_datetime($epoch, $this->getUser());
|
$date = phabricator_datetime($epoch, $this->getUser());
|
||||||
|
$this->addIcon('none', $date);
|
||||||
$days = floor((time() - $epoch) / 60 / 60 / 24);
|
|
||||||
|
|
||||||
switch ($age) {
|
|
||||||
case self::AGE_FRESH:
|
|
||||||
$this->addIcon('none', $date);
|
|
||||||
break;
|
|
||||||
case self::AGE_STALE:
|
|
||||||
$attr = array(
|
|
||||||
'tip' => pht('Stale (%s day(s))', new PhutilNumber($days)),
|
|
||||||
'class' => 'icon-age-stale',
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->addIcon('fa-clock-o yellow', $date, $attr);
|
|
||||||
break;
|
|
||||||
case self::AGE_OLD:
|
|
||||||
$attr = array(
|
|
||||||
'tip' => pht('Old (%s day(s))', new PhutilNumber($days)),
|
|
||||||
'class' => 'icon-age-old',
|
|
||||||
);
|
|
||||||
$this->addIcon('fa-clock-o red', $date, $attr);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new Exception(pht("Unknown age '%s'!", $age));
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -309,10 +247,6 @@ final class PHUIObjectItemView extends AphrontTagView {
|
||||||
$item_classes[] = 'phui-object-item-disabled';
|
$item_classes[] = 'phui-object-item-disabled';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->state) {
|
|
||||||
$item_classes[] = 'phui-object-item-state-'.$this->state;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ($this->effect) {
|
switch ($this->effect) {
|
||||||
case 'highlighted':
|
case 'highlighted':
|
||||||
$item_classes[] = 'phui-object-item-highlighted';
|
$item_classes[] = 'phui-object-item-highlighted';
|
||||||
|
@ -338,10 +272,6 @@ final class PHUIObjectItemView extends AphrontTagView {
|
||||||
$item_classes[] = 'phui-object-item-with-image-icon';
|
$item_classes[] = 'phui-object-item-with-image-icon';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->fontIcon) {
|
|
||||||
$item_classes[] = 'phui-object-item-with-ficon';
|
|
||||||
}
|
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
'class' => $item_classes,
|
'class' => $item_classes,
|
||||||
);
|
);
|
||||||
|
@ -596,16 +526,6 @@ final class PHUIObjectItemView extends AphrontTagView {
|
||||||
$this->getImageIcon());
|
$this->getImageIcon());
|
||||||
}
|
}
|
||||||
|
|
||||||
$ficon = null;
|
|
||||||
if ($this->fontIcon) {
|
|
||||||
$image = phutil_tag(
|
|
||||||
'div',
|
|
||||||
array(
|
|
||||||
'class' => 'phui-object-item-ficon',
|
|
||||||
),
|
|
||||||
$this->fontIcon);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($image && $this->href) {
|
if ($image && $this->href) {
|
||||||
$image = phutil_tag(
|
$image = phutil_tag(
|
||||||
'a',
|
'a',
|
||||||
|
|
34
webroot/rsrc/css/application/guides/guides.css
Normal file
34
webroot/rsrc/css/application/guides/guides.css
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
/**
|
||||||
|
* @provides guides-app-css
|
||||||
|
*/
|
||||||
|
|
||||||
|
.guides-app ul.phui-object-item-list-view {
|
||||||
|
margin: 0;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.guides-app .phui-object-item-no-bar .phui-object-item-frame {
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.guides-app .phui-object-item-image-icon {
|
||||||
|
margin: 8px 2px 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.guides-app a.phui-object-item-link {
|
||||||
|
color: #000;
|
||||||
|
font-size: {$biggestfontsize};
|
||||||
|
}
|
||||||
|
|
||||||
|
.guides-app .phui-object-item-name {
|
||||||
|
padding-top: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.guides-app .phui-object-item-launch-button a.button {
|
||||||
|
font-size: {$normalfontsize};
|
||||||
|
padding: 3px 12px 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.device-desktop .guides-app .phui-object-item {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
|
@ -151,6 +151,45 @@
|
||||||
color: rgba({$alphagrey},0.3);
|
color: rgba({$alphagrey},0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Backgrounds */
|
||||||
|
|
||||||
|
.phui-icon-view.bg-dark {
|
||||||
|
background-color: {$darkgreytext};
|
||||||
|
}
|
||||||
|
.phui-icon-view.bg-bluegrey {
|
||||||
|
background-color: {$bluetext};
|
||||||
|
}
|
||||||
|
.phui-icon-view.bg-red {
|
||||||
|
background-color: {$red};
|
||||||
|
}
|
||||||
|
.phui-icon-view.bg-orange {
|
||||||
|
background-color: {$orange};
|
||||||
|
}
|
||||||
|
.phui-icon-view.bg-yellow {
|
||||||
|
background-color: {$yellow};
|
||||||
|
}
|
||||||
|
.phui-icon-view.bg-green {
|
||||||
|
background-color: {$green}
|
||||||
|
}
|
||||||
|
.phui-icon-view.bg-blue {
|
||||||
|
background-color: {$blue};
|
||||||
|
}
|
||||||
|
.phui-icon-view.bg-sky {
|
||||||
|
background-color: {$sky};
|
||||||
|
}
|
||||||
|
.phui-icon-view.bg-indigo {
|
||||||
|
background-color: {$indigo};
|
||||||
|
}
|
||||||
|
.phui-icon-view.bg-pink {
|
||||||
|
background-color: {$pink};
|
||||||
|
}
|
||||||
|
.phui-icon-view.bg-fire {
|
||||||
|
background-color: {$fire};
|
||||||
|
}
|
||||||
|
.phui-icon-view.bg-violet {
|
||||||
|
background-color: {$violet};
|
||||||
|
}
|
||||||
|
|
||||||
/* Hovers */
|
/* Hovers */
|
||||||
|
|
||||||
.device-desktop a.phui-icon-view.lightgreytext:hover,
|
.device-desktop a.phui-icon-view.lightgreytext:hover,
|
||||||
|
|
48
webroot/rsrc/css/phui/phui-cms.css
Normal file
48
webroot/rsrc/css/phui/phui-cms.css
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
/**
|
||||||
|
* @provides phui-cms-css
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
.phui-cms-body {
|
||||||
|
background-color: #f0f0f2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.phui-cms-view .phui-crumbs-view {
|
||||||
|
border-bottom: 1px solid {$thinblueborder};
|
||||||
|
}
|
||||||
|
|
||||||
|
.phui-cms-page {
|
||||||
|
max-width: 1140px;
|
||||||
|
margin: 0 auto;
|
||||||
|
background-color: #fff;
|
||||||
|
border-left: 1px solid {$lightblueborder};
|
||||||
|
border-right: 1px solid {$lightblueborder};
|
||||||
|
border-bottom: 1px solid {$lightblueborder};
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.phui-cms-view .phui-basic-nav.phui-navigation-shell .phabricator-nav-local {
|
||||||
|
background-color: {$page.background};
|
||||||
|
width: 240px;
|
||||||
|
border-right: 1px solid {$thinblueborder};
|
||||||
|
}
|
||||||
|
|
||||||
|
.phui-cms-view .phabricator-nav-content {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.phui-cms-view .phui-document-container {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.phui-cms-view .phui-cms-page-content .phui-profile-header {
|
||||||
|
padding: 32px 20px;
|
||||||
|
border-bottom: 1px solid {$thinblueborder};
|
||||||
|
}
|
||||||
|
|
||||||
|
.phui-cms-view .phui-document-view.phui-document-view-pro {
|
||||||
|
width: auto;
|
||||||
|
max-width: inherit;
|
||||||
|
padding: 0 20px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
|
@ -109,7 +109,8 @@
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
}
|
}
|
||||||
|
|
||||||
.aphront-form-input input {
|
.aphront-form-input input[type="text"],
|
||||||
|
.aphront-form-input input[type="password"] {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -80,3 +80,20 @@ a.phui-icon-circle:hover {
|
||||||
a.phui-icon-circle:hover .phui-icon-view {
|
a.phui-icon-circle:hover .phui-icon-view {
|
||||||
color: {$sky};
|
color: {$sky};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* - Icon in a Square ------------------------------------------------------- */
|
||||||
|
|
||||||
|
.phui-icon-view.phui-icon-square {
|
||||||
|
height: 40px;
|
||||||
|
width: 40px;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 26px;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 38px;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.phui-icon-view.phui-icon-square:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
|
@ -487,46 +487,6 @@ ul.phui-object-item-list-view .phui-object-item-selected
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* - Foot Icons ----------------------------------------------------------------
|
|
||||||
|
|
||||||
Object counts shown in the footer.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
.phui-object-item-foot-icons {
|
|
||||||
margin-left: 10px;
|
|
||||||
bottom: 0;
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
|
|
||||||
.phui-object-item-with-foot-icons .phui-object-item-content,
|
|
||||||
.device-phone .phui-object-item-with-foot-icons .phui-object-item-col2 {
|
|
||||||
padding-bottom: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.device-phone .phui-object-item-with-foot-icons .phui-object-item-content {
|
|
||||||
padding-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.phui-object-item-foot-icon {
|
|
||||||
display: inline-block;
|
|
||||||
background: {$lightgreyborder};
|
|
||||||
color: #ffffff;
|
|
||||||
font-weight: bold;
|
|
||||||
margin-right: 3px;
|
|
||||||
padding: 3px 6px 0;
|
|
||||||
height: 17px;
|
|
||||||
vertical-align: middle;
|
|
||||||
position: relative;
|
|
||||||
font-size: 12px;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
}
|
|
||||||
|
|
||||||
.phui-object-item-foot-icon .phui-icon-view {
|
|
||||||
margin-right: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* - Handle Icons --------------------------------------------------------------
|
/* - Handle Icons --------------------------------------------------------------
|
||||||
|
|
||||||
Shows owners, reviewers, etc., using profile picture icons.
|
Shows owners, reviewers, etc., using profile picture icons.
|
||||||
|
@ -621,35 +581,6 @@ ul.phui-object-item-list-view .phui-object-item-selected
|
||||||
list-style: none;
|
list-style: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* - State ---------------------------------------------------------------------
|
|
||||||
|
|
||||||
Provides a list of object status or states, success or fail, etc
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
.phui-object-item-ficon {
|
|
||||||
width: 48px;
|
|
||||||
height: 26px;
|
|
||||||
margin-top: 12px;
|
|
||||||
position: absolute;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.phui-object-item-with-ficon .phui-object-item-content-box {
|
|
||||||
margin-left: 38px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.phui-object-box .phui-object-list-states {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.phui-object-list-states .phui-info-view {
|
|
||||||
margin: 0;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* - Badges ---------------------------------------------------------------- */
|
/* - Badges ---------------------------------------------------------------- */
|
||||||
|
|
||||||
.phui-object-item-col0.phui-object-item-badge {
|
.phui-object-item-col0.phui-object-item-badge {
|
||||||
|
@ -720,37 +651,19 @@ ul.phui-object-item-list-view .phui-object-item-selected
|
||||||
|
|
||||||
.phui-object-item-image-icon {
|
.phui-object-item-image-icon {
|
||||||
background: none;
|
background: none;
|
||||||
width: 30px;
|
width: 40px;
|
||||||
height: 30px;
|
height: 40px;
|
||||||
margin: 4px 0;
|
margin: 8px 6px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
}
|
}
|
||||||
|
|
||||||
.phui-object-item-image-icon .phui-icon-view {
|
.phui-object-item-image-icon .phui-icon-view {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 24px;
|
width: 40px;
|
||||||
height: 24px;
|
height: 40px;
|
||||||
left: 6px;
|
font-size: 26px;
|
||||||
top: 10px;
|
|
||||||
font-size: 24px;
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
vertical-align: bottom;
|
line-height: 36px;
|
||||||
}
|
|
||||||
|
|
||||||
.phui-object-item-with-image-icon .phui-object-item-frame {
|
|
||||||
min-height: 48px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.phui-object-item-with-image-icon .phui-object-item-content-box {
|
|
||||||
margin-left: 36px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.device-desktop .phui-object-item-launcher-list .phui-object-item-content {
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.device-desktop .phui-object-item-launcher-list .phui-object-icon-pane {
|
|
||||||
width: auto;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.phui-object-item-image {
|
.phui-object-item-image {
|
||||||
|
@ -762,10 +675,12 @@ ul.phui-object-item-list-view .phui-object-item-selected
|
||||||
position: absolute;
|
position: absolute;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.phui-object-item-with-image-icon .phui-object-item-frame,
|
||||||
.phui-object-item-with-image .phui-object-item-frame {
|
.phui-object-item-with-image .phui-object-item-frame {
|
||||||
min-height: 52px;
|
min-height: 52px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.phui-object-item-with-image-icon .phui-object-item-content-box,
|
||||||
.phui-object-item-with-image .phui-object-item-content-box {
|
.phui-object-item-with-image .phui-object-item-content-box {
|
||||||
margin-left: 46px;
|
margin-left: 46px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -216,8 +216,18 @@ JX.install('WorkboardBoard', {
|
||||||
}
|
}
|
||||||
|
|
||||||
var column_maps = response.columnMaps;
|
var column_maps = response.columnMaps;
|
||||||
|
var natural_column;
|
||||||
for (var natural_phid in column_maps) {
|
for (var natural_phid in column_maps) {
|
||||||
this.getColumn(natural_phid).setNaturalOrder(column_maps[natural_phid]);
|
natural_column = this.getColumn(natural_phid);
|
||||||
|
if (!natural_column) {
|
||||||
|
// Our view of the board may be out of date, so we might get back
|
||||||
|
// information about columns that aren't visible. Just ignore the
|
||||||
|
// position information for any columns we aren't displaying on the
|
||||||
|
// client.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
natural_column.setNaturalOrder(column_maps[natural_phid]);
|
||||||
}
|
}
|
||||||
|
|
||||||
var property_maps = response.propertyMaps;
|
var property_maps = response.propertyMaps;
|
||||||
|
|
Loading…
Reference in a new issue