mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-27 17:22:42 +01:00
(stable) Promote 2016 Week 38
This commit is contained in:
commit
c8281bc339
206 changed files with 2774 additions and 2317 deletions
|
@ -7,8 +7,10 @@
|
|||
*/
|
||||
return array(
|
||||
'names' => array(
|
||||
'core.pkg.css' => 'ad6a3591',
|
||||
'core.pkg.js' => '2b8af4e4',
|
||||
'conpherence.pkg.css' => '80a3fcb3',
|
||||
'conpherence.pkg.js' => '89b4837e',
|
||||
'core.pkg.css' => '476e9330',
|
||||
'core.pkg.js' => '1d376fa9',
|
||||
'darkconsole.pkg.js' => 'e7393ebb',
|
||||
'differential.pkg.css' => '3fb7f532',
|
||||
'differential.pkg.js' => '634399e9',
|
||||
|
@ -18,7 +20,7 @@ return array(
|
|||
'maniphest.pkg.js' => '949a7498',
|
||||
'rsrc/css/aphront/aphront-bars.css' => '231ac33c',
|
||||
'rsrc/css/aphront/dark-console.css' => 'f54bf286',
|
||||
'rsrc/css/aphront/dialog-view.css' => '913c172e',
|
||||
'rsrc/css/aphront/dialog-view.css' => '593d3f67',
|
||||
'rsrc/css/aphront/lightbox-attachment.css' => '7acac05d',
|
||||
'rsrc/css/aphront/list-filter-view.css' => '5d6f0526',
|
||||
'rsrc/css/aphront/multi-column.css' => 'fd18389d',
|
||||
|
@ -32,7 +34,7 @@ return array(
|
|||
'rsrc/css/aphront/typeahead.css' => 'd4f16145',
|
||||
'rsrc/css/application/almanac/almanac.css' => 'dbb9b3af',
|
||||
'rsrc/css/application/auth/auth.css' => '0877ed6e',
|
||||
'rsrc/css/application/base/main-menu-view.css' => 'e862571a',
|
||||
'rsrc/css/application/base/main-menu-view.css' => 'f03e17be',
|
||||
'rsrc/css/application/base/notification-menu.css' => 'b3ab500d',
|
||||
'rsrc/css/application/base/phabricator-application-launch-view.css' => '95351601',
|
||||
'rsrc/css/application/base/phui-theme.css' => '027ba77e',
|
||||
|
@ -41,17 +43,17 @@ return array(
|
|||
'rsrc/css/application/conduit/conduit-api.css' => '7bc725c4',
|
||||
'rsrc/css/application/config/config-options.css' => '0ede4c9b',
|
||||
'rsrc/css/application/config/config-page.css' => '8798e14f',
|
||||
'rsrc/css/application/config/config-template.css' => '8e6c6fcd',
|
||||
'rsrc/css/application/config/config-welcome.css' => '035aa483',
|
||||
'rsrc/css/application/config/config-template.css' => '8f18fa41',
|
||||
'rsrc/css/application/config/setup-issue.css' => 'f794cfc3',
|
||||
'rsrc/css/application/config/unhandled-exception.css' => '4c96257a',
|
||||
'rsrc/css/application/conpherence/durable-column.css' => '86396117',
|
||||
'rsrc/css/application/conpherence/menu.css' => '90bdf85c',
|
||||
'rsrc/css/application/conpherence/message-pane.css' => '5c7b7b17',
|
||||
'rsrc/css/application/conpherence/durable-column.css' => '194ac487',
|
||||
'rsrc/css/application/conpherence/header-pane.css' => '517de9fe',
|
||||
'rsrc/css/application/conpherence/menu.css' => '78c7b811',
|
||||
'rsrc/css/application/conpherence/message-pane.css' => '8d13ac4d',
|
||||
'rsrc/css/application/conpherence/notification.css' => '6cdcc253',
|
||||
'rsrc/css/application/conpherence/transaction.css' => '85d0974c',
|
||||
'rsrc/css/application/conpherence/update.css' => 'faf6be09',
|
||||
'rsrc/css/application/conpherence/widget-pane.css' => 'c5b74f9e',
|
||||
'rsrc/css/application/conpherence/participant-pane.css' => '7bba0b56',
|
||||
'rsrc/css/application/conpherence/transaction.css' => '46253e19',
|
||||
'rsrc/css/application/conpherence/update.css' => '53bc527a',
|
||||
'rsrc/css/application/contentsource/content-source-view.css' => '4b8b05d4',
|
||||
'rsrc/css/application/countdown/timer.css' => '16c52f5c',
|
||||
'rsrc/css/application/daemon/bulk-job.css' => 'df9c1d4a',
|
||||
|
@ -95,7 +97,7 @@ return array(
|
|||
'rsrc/css/application/policy/policy.css' => '957ea14c',
|
||||
'rsrc/css/application/ponder/ponder-view.css' => 'fbd45f96',
|
||||
'rsrc/css/application/project/project-card-view.css' => '9418c97d',
|
||||
'rsrc/css/application/project/project-view.css' => '9ce99f21',
|
||||
'rsrc/css/application/project/project-view.css' => '55d99221',
|
||||
'rsrc/css/application/releeph/releeph-core.css' => '9b3c5733',
|
||||
'rsrc/css/application/releeph/releeph-preview-branch.css' => 'b7a6f4a5',
|
||||
'rsrc/css/application/releeph/releeph-request-differential-create-dialog.css' => '8d8b92cd',
|
||||
|
@ -106,9 +108,9 @@ return array(
|
|||
'rsrc/css/application/tokens/tokens.css' => '3d0f239e',
|
||||
'rsrc/css/application/uiexample/example.css' => '528b19de',
|
||||
'rsrc/css/core/core.css' => 'd0801452',
|
||||
'rsrc/css/core/remarkup.css' => '5ed06ed8',
|
||||
'rsrc/css/core/remarkup.css' => 'cd912f2c',
|
||||
'rsrc/css/core/syntax.css' => '769d3498',
|
||||
'rsrc/css/core/z-index.css' => '2b01a823',
|
||||
'rsrc/css/core/z-index.css' => '0d4e5558',
|
||||
'rsrc/css/diviner/diviner-shared.css' => 'aa3656aa',
|
||||
'rsrc/css/font/font-aleo.css' => '8bdb2835',
|
||||
'rsrc/css/font/font-awesome.css' => '2b7ebbcc',
|
||||
|
@ -129,9 +131,9 @@ return array(
|
|||
'rsrc/css/phui/phui-button.css' => '4a5fbe3d',
|
||||
'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-curtain-view.css' => '7148ae25',
|
||||
'rsrc/css/phui/phui-document-pro.css' => 'dc3d46ed',
|
||||
'rsrc/css/phui/phui-crumbs-view.css' => '195ac419',
|
||||
'rsrc/css/phui/phui-curtain-view.css' => '947bf1a4',
|
||||
'rsrc/css/phui/phui-document-pro.css' => 'ca1fed81',
|
||||
'rsrc/css/phui/phui-document-summary.css' => '9ca48bdf',
|
||||
'rsrc/css/phui/phui-document.css' => 'c32e8dec',
|
||||
'rsrc/css/phui/phui-feed-story.css' => 'aa49845d',
|
||||
|
@ -142,10 +144,11 @@ return array(
|
|||
'rsrc/css/phui/phui-header-view.css' => '06385974',
|
||||
'rsrc/css/phui/phui-hovercard.css' => 'de1a2119',
|
||||
'rsrc/css/phui/phui-icon-set-selector.css' => '1ab67aad',
|
||||
'rsrc/css/phui/phui-icon.css' => 'b1dbd620',
|
||||
'rsrc/css/phui/phui-icon.css' => '9bab6f02',
|
||||
'rsrc/css/phui/phui-image-mask.css' => 'a8498f9c',
|
||||
'rsrc/css/phui/phui-info-panel.css' => '27ea50a1',
|
||||
'rsrc/css/phui/phui-info-view.css' => '28efab79',
|
||||
'rsrc/css/phui/phui-invisible-character-view.css' => '6993d9f0',
|
||||
'rsrc/css/phui/phui-list.css' => '9da2aa00',
|
||||
'rsrc/css/phui/phui-object-box.css' => '6b487c57',
|
||||
'rsrc/css/phui/phui-object-item-list-view.css' => '87278fa0',
|
||||
|
@ -159,12 +162,12 @@ return array(
|
|||
'rsrc/css/phui/phui-status.css' => 'd5263e49',
|
||||
'rsrc/css/phui/phui-tag-view.css' => '6bbd83e2',
|
||||
'rsrc/css/phui/phui-timeline-view.css' => 'bc523970',
|
||||
'rsrc/css/phui/phui-two-column-view.css' => '5afdf637',
|
||||
'rsrc/css/phui/phui-two-column-view.css' => 'fcfbe347',
|
||||
'rsrc/css/phui/workboards/phui-workboard-color.css' => 'ac6fe6a7',
|
||||
'rsrc/css/phui/workboards/phui-workboard.css' => 'bda3ef58',
|
||||
'rsrc/css/phui/workboards/phui-workcard.css' => '0c62d7c5',
|
||||
'rsrc/css/phui/workboards/phui-workpanel.css' => '92197373',
|
||||
'rsrc/css/sprite-login.css' => '60e8560e',
|
||||
'rsrc/css/sprite-login.css' => '6dbbbd97',
|
||||
'rsrc/css/sprite-tokens.css' => '9cdfd599',
|
||||
'rsrc/css/syntax/syntax-default.css' => '9923583c',
|
||||
'rsrc/externals/d3/d3.min.js' => 'a11a5ff2',
|
||||
|
@ -262,14 +265,79 @@ return array(
|
|||
'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadPreloadedSource.js' => '54f314a0',
|
||||
'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadSource.js' => 'b25d5444',
|
||||
'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadStaticSource.js' => '6c0e62fa',
|
||||
'rsrc/favicons/apple-touch-icon-120x120.png' => '43742962',
|
||||
'rsrc/favicons/apple-touch-icon-152x152.png' => '669eaec3',
|
||||
'rsrc/favicons/apple-touch-icon-76x76.png' => 'ecdef672',
|
||||
'rsrc/favicons/favicon-128.png' => '47cdff03',
|
||||
'rsrc/favicons/favicon-16x16.png' => 'ee2523ac',
|
||||
'rsrc/favicons/favicon-32x32.png' => 'b6a8150e',
|
||||
'rsrc/favicons/favicon-96x96.png' => '8f7ea177',
|
||||
'rsrc/favicons/mask-icon.svg' => '0460cb1f',
|
||||
'rsrc/favicons/apple-touch-icon-114x114.png' => '12a24178',
|
||||
'rsrc/favicons/apple-touch-icon-120x120.png' => '0d1543c7',
|
||||
'rsrc/favicons/apple-touch-icon-144x144.png' => '8043b5a5',
|
||||
'rsrc/favicons/apple-touch-icon-152x152.png' => '65905ecd',
|
||||
'rsrc/favicons/apple-touch-icon-57x57.png' => '2bfc7b0a',
|
||||
'rsrc/favicons/apple-touch-icon-60x60.png' => '8ff52925',
|
||||
'rsrc/favicons/apple-touch-icon-72x72.png' => 'a2bb65d6',
|
||||
'rsrc/favicons/apple-touch-icon-76x76.png' => '2d061a11',
|
||||
'rsrc/favicons/dark/apple-touch-icon-114x114.png' => 'd0c8978c',
|
||||
'rsrc/favicons/dark/apple-touch-icon-120x120.png' => '3a618bc0',
|
||||
'rsrc/favicons/dark/apple-touch-icon-144x144.png' => '92c1e188',
|
||||
'rsrc/favicons/dark/apple-touch-icon-152x152.png' => '7ce7e469',
|
||||
'rsrc/favicons/dark/apple-touch-icon-57x57.png' => 'e3f3f38b',
|
||||
'rsrc/favicons/dark/apple-touch-icon-60x60.png' => '1e0dcc72',
|
||||
'rsrc/favicons/dark/apple-touch-icon-72x72.png' => '7fb599b6',
|
||||
'rsrc/favicons/dark/apple-touch-icon-76x76.png' => '91146961',
|
||||
'rsrc/favicons/dark/favicon-128.png' => 'd6ac4346',
|
||||
'rsrc/favicons/dark/favicon-16x16.png' => '17434bb0',
|
||||
'rsrc/favicons/dark/favicon-196x196.png' => '5e06ee72',
|
||||
'rsrc/favicons/dark/favicon-32x32.png' => 'bdd7e16b',
|
||||
'rsrc/favicons/dark/favicon-96x96.png' => '0cf55978',
|
||||
'rsrc/favicons/dark/mstile-144x144.png' => '4dc9d42d',
|
||||
'rsrc/favicons/dark/mstile-150x150.png' => '2dc61c90',
|
||||
'rsrc/favicons/dark/mstile-310x150.png' => '4fe58ab2',
|
||||
'rsrc/favicons/dark/mstile-310x310.png' => 'e62c1677',
|
||||
'rsrc/favicons/dark/mstile-70x70.png' => '6d1f41b7',
|
||||
'rsrc/favicons/favicon-128.png' => '72f7e812',
|
||||
'rsrc/favicons/favicon-16x16.png' => 'fc6275ba',
|
||||
'rsrc/favicons/favicon-196x196.png' => '95db275e',
|
||||
'rsrc/favicons/favicon-32x32.png' => '5bd18b6c',
|
||||
'rsrc/favicons/favicon-96x96.png' => '7242c8e9',
|
||||
'rsrc/favicons/mask-icon.svg' => 'e132a80f',
|
||||
'rsrc/favicons/mstile-144x144.png' => '310c2ee5',
|
||||
'rsrc/favicons/mstile-150x150.png' => '74bf5133',
|
||||
'rsrc/favicons/mstile-310x150.png' => '4a49d3ee',
|
||||
'rsrc/favicons/mstile-310x310.png' => 'a52ab264',
|
||||
'rsrc/favicons/mstile-70x70.png' => '5edce7b8',
|
||||
'rsrc/favicons/red/apple-touch-icon-114x114.png' => '91e37d1d',
|
||||
'rsrc/favicons/red/apple-touch-icon-120x120.png' => '66687533',
|
||||
'rsrc/favicons/red/apple-touch-icon-144x144.png' => 'bc06002c',
|
||||
'rsrc/favicons/red/apple-touch-icon-152x152.png' => 'a713de42',
|
||||
'rsrc/favicons/red/apple-touch-icon-57x57.png' => '4729688b',
|
||||
'rsrc/favicons/red/apple-touch-icon-60x60.png' => '07b9b609',
|
||||
'rsrc/favicons/red/apple-touch-icon-72x72.png' => 'b20c3698',
|
||||
'rsrc/favicons/red/apple-touch-icon-76x76.png' => 'c6e7dd5c',
|
||||
'rsrc/favicons/red/favicon-128.png' => 'e2b2f8fe',
|
||||
'rsrc/favicons/red/favicon-16x16.png' => '929fbceb',
|
||||
'rsrc/favicons/red/favicon-196x196.png' => '94c089a5',
|
||||
'rsrc/favicons/red/favicon-32x32.png' => '5848673e',
|
||||
'rsrc/favicons/red/favicon-96x96.png' => '895d54e8',
|
||||
'rsrc/favicons/red/mstile-144x144.png' => '448639f5',
|
||||
'rsrc/favicons/red/mstile-150x150.png' => 'c2ba45d0',
|
||||
'rsrc/favicons/red/mstile-310x150.png' => 'b0e50799',
|
||||
'rsrc/favicons/red/mstile-310x310.png' => '2475c5a5',
|
||||
'rsrc/favicons/red/mstile-70x70.png' => '49b197e8',
|
||||
'rsrc/favicons/yellow/apple-touch-icon-114x114.png' => '5271fb3f',
|
||||
'rsrc/favicons/yellow/apple-touch-icon-120x120.png' => '6c3d9bf9',
|
||||
'rsrc/favicons/yellow/apple-touch-icon-144x144.png' => '6484472c',
|
||||
'rsrc/favicons/yellow/apple-touch-icon-152x152.png' => 'e305dda8',
|
||||
'rsrc/favicons/yellow/apple-touch-icon-57x57.png' => 'fa6c43d4',
|
||||
'rsrc/favicons/yellow/apple-touch-icon-60x60.png' => '2673f162',
|
||||
'rsrc/favicons/yellow/apple-touch-icon-72x72.png' => '3ad8020c',
|
||||
'rsrc/favicons/yellow/apple-touch-icon-76x76.png' => '58cffd81',
|
||||
'rsrc/favicons/yellow/favicon-128.png' => '3b2f8233',
|
||||
'rsrc/favicons/yellow/favicon-16x16.png' => 'f3a90518',
|
||||
'rsrc/favicons/yellow/favicon-196x196.png' => '932c7c65',
|
||||
'rsrc/favicons/yellow/favicon-32x32.png' => '005c9f92',
|
||||
'rsrc/favicons/yellow/favicon-96x96.png' => '3ad9bfa9',
|
||||
'rsrc/favicons/yellow/mstile-144x144.png' => 'fc52335c',
|
||||
'rsrc/favicons/yellow/mstile-150x150.png' => '9e556f80',
|
||||
'rsrc/favicons/yellow/mstile-310x150.png' => '2c915073',
|
||||
'rsrc/favicons/yellow/mstile-310x310.png' => 'ee49978d',
|
||||
'rsrc/favicons/yellow/mstile-70x70.png' => '85c7c939',
|
||||
'rsrc/image/BFCFDA.png' => 'd5ec91f4',
|
||||
'rsrc/image/actions/edit.png' => '2fc41442',
|
||||
'rsrc/image/avatar.png' => 'e132bb6a',
|
||||
|
@ -343,8 +411,8 @@ return array(
|
|||
'rsrc/image/phrequent_active.png' => 'a466a8ed',
|
||||
'rsrc/image/phrequent_inactive.png' => 'bfc15a69',
|
||||
'rsrc/image/resize.png' => 'fd476de4',
|
||||
'rsrc/image/sprite-login-X2.png' => 'e3991e37',
|
||||
'rsrc/image/sprite-login.png' => '03d5af29',
|
||||
'rsrc/image/sprite-login-X2.png' => '4abee916',
|
||||
'rsrc/image/sprite-login.png' => '2b9663fd',
|
||||
'rsrc/image/sprite-tokens-X2.png' => '804a5232',
|
||||
'rsrc/image/sprite-tokens.png' => 'b41d03da',
|
||||
'rsrc/image/texture/card-gradient.png' => '815f26e8',
|
||||
|
@ -371,10 +439,11 @@ return array(
|
|||
'rsrc/js/application/conpherence/ConpherenceThreadManager.js' => '01774ab2',
|
||||
'rsrc/js/application/conpherence/behavior-drag-and-drop-photo.js' => 'cf86d16a',
|
||||
'rsrc/js/application/conpherence/behavior-durable-column.js' => 'd3506890',
|
||||
'rsrc/js/application/conpherence/behavior-menu.js' => '1d45c74d',
|
||||
'rsrc/js/application/conpherence/behavior-menu.js' => '9eb55204',
|
||||
'rsrc/js/application/conpherence/behavior-participant-pane.js' => '8604caa8',
|
||||
'rsrc/js/application/conpherence/behavior-pontificate.js' => '21ba5861',
|
||||
'rsrc/js/application/conpherence/behavior-quicksand-blacklist.js' => '7927a7d3',
|
||||
'rsrc/js/application/conpherence/behavior-widget-pane.js' => 'a8458711',
|
||||
'rsrc/js/application/conpherence/behavior-toggle-widget.js' => '9bdbbab0',
|
||||
'rsrc/js/application/countdown/timer.js' => 'e4cc26b3',
|
||||
'rsrc/js/application/daemon/behavior-bulk-job-reload.js' => 'edf8a145',
|
||||
'rsrc/js/application/dashboard/behavior-dashboard-async-panel.js' => '469c0d9e',
|
||||
|
@ -438,7 +507,7 @@ return array(
|
|||
'rsrc/js/application/search/behavior-reorder-profile-menu-items.js' => 'e2e0a072',
|
||||
'rsrc/js/application/search/behavior-reorder-queries.js' => 'e9581f08',
|
||||
'rsrc/js/application/slowvote/behavior-slowvote-embed.js' => '887ad43f',
|
||||
'rsrc/js/application/transactions/behavior-comment-actions.js' => '06460e71',
|
||||
'rsrc/js/application/transactions/behavior-comment-actions.js' => '0300eae6',
|
||||
'rsrc/js/application/transactions/behavior-reorder-configs.js' => 'd7a74243',
|
||||
'rsrc/js/application/transactions/behavior-reorder-fields.js' => 'b59e1e96',
|
||||
'rsrc/js/application/transactions/behavior-show-older-transactions.js' => '94c65b72',
|
||||
|
@ -534,7 +603,7 @@ return array(
|
|||
'almanac-css' => 'dbb9b3af',
|
||||
'aphront-bars' => '231ac33c',
|
||||
'aphront-dark-console-css' => 'f54bf286',
|
||||
'aphront-dialog-view-css' => '913c172e',
|
||||
'aphront-dialog-view-css' => '593d3f67',
|
||||
'aphront-list-filter-view-css' => '5d6f0526',
|
||||
'aphront-multi-column-view-css' => 'fd18389d',
|
||||
'aphront-panel-view-css' => '8427b78d',
|
||||
|
@ -549,15 +618,15 @@ return array(
|
|||
'conduit-api-css' => '7bc725c4',
|
||||
'config-options-css' => '0ede4c9b',
|
||||
'config-page-css' => '8798e14f',
|
||||
'config-welcome-css' => '035aa483',
|
||||
'conpherence-durable-column-view' => '86396117',
|
||||
'conpherence-menu-css' => '90bdf85c',
|
||||
'conpherence-message-pane-css' => '5c7b7b17',
|
||||
'conpherence-durable-column-view' => '194ac487',
|
||||
'conpherence-header-pane-css' => '517de9fe',
|
||||
'conpherence-menu-css' => '78c7b811',
|
||||
'conpherence-message-pane-css' => '8d13ac4d',
|
||||
'conpherence-notification-css' => '6cdcc253',
|
||||
'conpherence-participant-pane-css' => '7bba0b56',
|
||||
'conpherence-thread-manager' => '01774ab2',
|
||||
'conpherence-transaction-css' => '85d0974c',
|
||||
'conpherence-update-css' => 'faf6be09',
|
||||
'conpherence-widget-pane-css' => 'c5b74f9e',
|
||||
'conpherence-transaction-css' => '46253e19',
|
||||
'conpherence-update-css' => '53bc527a',
|
||||
'd3' => 'a11a5ff2',
|
||||
'differential-changeset-view-css' => '9ef7d354',
|
||||
'differential-core-view-css' => '5b7b8ff4',
|
||||
|
@ -596,12 +665,12 @@ return array(
|
|||
'javelin-behavior-bulk-job-reload' => 'edf8a145',
|
||||
'javelin-behavior-calendar-month-view' => 'fe33e256',
|
||||
'javelin-behavior-choose-control' => '327a00d1',
|
||||
'javelin-behavior-comment-actions' => '06460e71',
|
||||
'javelin-behavior-comment-actions' => '0300eae6',
|
||||
'javelin-behavior-config-reorder-fields' => 'b6993408',
|
||||
'javelin-behavior-conpherence-drag-and-drop-photo' => 'cf86d16a',
|
||||
'javelin-behavior-conpherence-menu' => '1d45c74d',
|
||||
'javelin-behavior-conpherence-menu' => '9eb55204',
|
||||
'javelin-behavior-conpherence-participant-pane' => '8604caa8',
|
||||
'javelin-behavior-conpherence-pontificate' => '21ba5861',
|
||||
'javelin-behavior-conpherence-widget-pane' => 'a8458711',
|
||||
'javelin-behavior-countdown-timer' => 'e4cc26b3',
|
||||
'javelin-behavior-dark-console' => 'f411b6ae',
|
||||
'javelin-behavior-dashboard-async-panel' => '469c0d9e',
|
||||
|
@ -707,6 +776,7 @@ return array(
|
|||
'javelin-behavior-test-payment-form' => 'fc91ab6c',
|
||||
'javelin-behavior-time-typeahead' => '522431f7',
|
||||
'javelin-behavior-toggle-class' => '92b9ec77',
|
||||
'javelin-behavior-toggle-widget' => '9bdbbab0',
|
||||
'javelin-behavior-typeahead-browse' => '635de1ec',
|
||||
'javelin-behavior-typeahead-search' => '93d0c9e3',
|
||||
'javelin-behavior-view-placeholder' => '47830651',
|
||||
|
@ -779,14 +849,14 @@ return array(
|
|||
'phabricator-dashboard-css' => 'bc6f2127',
|
||||
'phabricator-drag-and-drop-file-upload' => '58dea2fa',
|
||||
'phabricator-draggable-list' => '5a13c79f',
|
||||
'phabricator-fatal-config-template-css' => '8e6c6fcd',
|
||||
'phabricator-fatal-config-template-css' => '8f18fa41',
|
||||
'phabricator-feed-css' => 'ecd4ec57',
|
||||
'phabricator-file-upload' => '680ea2c8',
|
||||
'phabricator-filetree-view-css' => 'fccf9f82',
|
||||
'phabricator-flag-css' => '5337623f',
|
||||
'phabricator-keyboard-shortcut' => '1ae869f2',
|
||||
'phabricator-keyboard-shortcut-manager' => '4a021c10',
|
||||
'phabricator-main-menu-view' => 'e862571a',
|
||||
'phabricator-main-menu-view' => 'f03e17be',
|
||||
'phabricator-nav-view-css' => 'b29426e9',
|
||||
'phabricator-notification' => 'ccf1cbf8',
|
||||
'phabricator-notification-css' => '3f6c89c9',
|
||||
|
@ -794,7 +864,7 @@ return array(
|
|||
'phabricator-object-selector-css' => '85ee8ce6',
|
||||
'phabricator-phtize' => 'd254d646',
|
||||
'phabricator-prefab' => 'cfd23f37',
|
||||
'phabricator-remarkup-css' => '5ed06ed8',
|
||||
'phabricator-remarkup-css' => 'cd912f2c',
|
||||
'phabricator-search-results-css' => '7dea472c',
|
||||
'phabricator-shaped-request' => '7cbe244b',
|
||||
'phabricator-slowvote-css' => 'a94b7230',
|
||||
|
@ -814,7 +884,7 @@ return array(
|
|||
'phabricator-uiexample-reactor-select' => 'a155550f',
|
||||
'phabricator-uiexample-reactor-sendclass' => '1def2711',
|
||||
'phabricator-uiexample-reactor-sendproperties' => 'b1f0ccee',
|
||||
'phabricator-zindex-css' => '2b01a823',
|
||||
'phabricator-zindex-css' => '0d4e5558',
|
||||
'phame-css' => '8efb0729',
|
||||
'pholio-css' => 'ca89d380',
|
||||
'pholio-edit-css' => '07676f51',
|
||||
|
@ -836,11 +906,11 @@ return array(
|
|||
'phui-calendar-month-css' => '8e10e92c',
|
||||
'phui-chart-css' => '6bf6f78e',
|
||||
'phui-cms-css' => 'be43c8a8',
|
||||
'phui-crumbs-view-css' => '9dac418c',
|
||||
'phui-curtain-view-css' => '7148ae25',
|
||||
'phui-crumbs-view-css' => '195ac419',
|
||||
'phui-curtain-view-css' => '947bf1a4',
|
||||
'phui-document-summary-view-css' => '9ca48bdf',
|
||||
'phui-document-view-css' => 'c32e8dec',
|
||||
'phui-document-view-pro-css' => 'dc3d46ed',
|
||||
'phui-document-view-pro-css' => 'ca1fed81',
|
||||
'phui-feed-story-css' => 'aa49845d',
|
||||
'phui-font-icon-base-css' => '870a7360',
|
||||
'phui-fontkit-css' => '9cda225e',
|
||||
|
@ -851,11 +921,12 @@ return array(
|
|||
'phui-hovercard' => '1bd28176',
|
||||
'phui-hovercard-view-css' => 'de1a2119',
|
||||
'phui-icon-set-selector-css' => '1ab67aad',
|
||||
'phui-icon-view-css' => 'b1dbd620',
|
||||
'phui-icon-view-css' => '9bab6f02',
|
||||
'phui-image-mask-css' => 'a8498f9c',
|
||||
'phui-info-panel-css' => '27ea50a1',
|
||||
'phui-info-view-css' => '28efab79',
|
||||
'phui-inline-comment-view-css' => '5953c28e',
|
||||
'phui-invisible-character-view-css' => '6993d9f0',
|
||||
'phui-list-view-css' => '9da2aa00',
|
||||
'phui-object-box-css' => '6b487c57',
|
||||
'phui-object-item-list-view-css' => '87278fa0',
|
||||
|
@ -870,7 +941,7 @@ return array(
|
|||
'phui-tag-view-css' => '6bbd83e2',
|
||||
'phui-theme-css' => '027ba77e',
|
||||
'phui-timeline-view-css' => 'bc523970',
|
||||
'phui-two-column-view-css' => '5afdf637',
|
||||
'phui-two-column-view-css' => 'fcfbe347',
|
||||
'phui-workboard-color-css' => 'ac6fe6a7',
|
||||
'phui-workboard-view-css' => 'bda3ef58',
|
||||
'phui-workcard-view-css' => '0c62d7c5',
|
||||
|
@ -886,13 +957,13 @@ return array(
|
|||
'policy-transaction-detail-css' => '82100a43',
|
||||
'ponder-view-css' => 'fbd45f96',
|
||||
'project-card-view-css' => '9418c97d',
|
||||
'project-view-css' => '9ce99f21',
|
||||
'project-view-css' => '55d99221',
|
||||
'releeph-core' => '9b3c5733',
|
||||
'releeph-preview-branch' => 'b7a6f4a5',
|
||||
'releeph-request-differential-create-dialog' => '8d8b92cd',
|
||||
'releeph-request-typeahead-css' => '667a48ae',
|
||||
'setup-issue-css' => 'f794cfc3',
|
||||
'sprite-login-css' => '60e8560e',
|
||||
'sprite-login-css' => '6dbbbd97',
|
||||
'sprite-tokens-css' => '9cdfd599',
|
||||
'syntax-default-css' => '9923583c',
|
||||
'syntax-highlighting-css' => '769d3498',
|
||||
|
@ -933,6 +1004,15 @@ return array(
|
|||
'javelin-dom',
|
||||
'phabricator-keyboard-shortcut',
|
||||
),
|
||||
'0300eae6' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-stratcom',
|
||||
'javelin-workflow',
|
||||
'javelin-dom',
|
||||
'phuix-form-control-view',
|
||||
'phuix-icon-view',
|
||||
'javelin-behavior-phabricator-gesture',
|
||||
),
|
||||
'05270951' => array(
|
||||
'javelin-util',
|
||||
'javelin-magical-init',
|
||||
|
@ -947,15 +1027,6 @@ return array(
|
|||
'aphront-typeahead-control-css',
|
||||
'phui-tag-view-css',
|
||||
),
|
||||
'06460e71' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-stratcom',
|
||||
'javelin-workflow',
|
||||
'javelin-dom',
|
||||
'phuix-form-control-view',
|
||||
'phuix-icon-view',
|
||||
'javelin-behavior-phabricator-gesture',
|
||||
),
|
||||
'065227cc' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
|
@ -1067,20 +1138,6 @@ return array(
|
|||
'javelin-request',
|
||||
'javelin-uri',
|
||||
),
|
||||
'1d45c74d' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
'javelin-util',
|
||||
'javelin-stratcom',
|
||||
'javelin-workflow',
|
||||
'javelin-behavior-device',
|
||||
'javelin-history',
|
||||
'javelin-vector',
|
||||
'javelin-scrollbar',
|
||||
'phabricator-title',
|
||||
'phabricator-shaped-request',
|
||||
'conpherence-thread-manager',
|
||||
),
|
||||
'1def2711' => array(
|
||||
'javelin-install',
|
||||
'javelin-dom',
|
||||
|
@ -1559,6 +1616,15 @@ return array(
|
|||
'85ee8ce6' => array(
|
||||
'aphront-dialog-view-css',
|
||||
),
|
||||
'8604caa8' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
'javelin-stratcom',
|
||||
'javelin-workflow',
|
||||
'javelin-util',
|
||||
'phabricator-notification',
|
||||
'conpherence-thread-manager',
|
||||
),
|
||||
'8694b1df' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
|
@ -1674,6 +1740,27 @@ return array(
|
|||
'phabricator-phtize',
|
||||
'changeset-view-manager',
|
||||
),
|
||||
'9bdbbab0' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
'javelin-util',
|
||||
'javelin-workflow',
|
||||
'javelin-stratcom',
|
||||
),
|
||||
'9eb55204' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
'javelin-util',
|
||||
'javelin-stratcom',
|
||||
'javelin-workflow',
|
||||
'javelin-behavior-device',
|
||||
'javelin-history',
|
||||
'javelin-vector',
|
||||
'javelin-scrollbar',
|
||||
'phabricator-title',
|
||||
'phabricator-shaped-request',
|
||||
'conpherence-thread-manager',
|
||||
),
|
||||
'9ef7d354' => array(
|
||||
'phui-inline-comment-view-css',
|
||||
),
|
||||
|
@ -1721,19 +1808,6 @@ return array(
|
|||
'javelin-stratcom',
|
||||
'javelin-dom',
|
||||
),
|
||||
'a8458711' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
'javelin-stratcom',
|
||||
'javelin-workflow',
|
||||
'javelin-util',
|
||||
'phabricator-notification',
|
||||
'javelin-behavior-device',
|
||||
'phuix-dropdown-menu',
|
||||
'phuix-action-list-view',
|
||||
'phuix-action-view',
|
||||
'conpherence-thread-manager',
|
||||
),
|
||||
'a8d8459d' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
|
@ -2096,9 +2170,6 @@ return array(
|
|||
'e6e25838' => array(
|
||||
'javelin-install',
|
||||
),
|
||||
'e862571a' => array(
|
||||
'phui-theme-css',
|
||||
),
|
||||
'e9581f08' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-stratcom',
|
||||
|
@ -2134,6 +2205,9 @@ return array(
|
|||
'javelin-workflow',
|
||||
'javelin-json',
|
||||
),
|
||||
'f03e17be' => array(
|
||||
'phui-theme-css',
|
||||
),
|
||||
'f411b6ae' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-stratcom',
|
||||
|
@ -2228,10 +2302,28 @@ return array(
|
|||
),
|
||||
),
|
||||
'packages' => array(
|
||||
'conpherence.pkg.css' => array(
|
||||
'conpherence-durable-column-view',
|
||||
'conpherence-menu-css',
|
||||
'conpherence-message-pane-css',
|
||||
'conpherence-notification-css',
|
||||
'conpherence-transaction-css',
|
||||
'conpherence-update-css',
|
||||
'conpherence-participant-pane-css',
|
||||
'conpherence-header-pane-css',
|
||||
),
|
||||
'conpherence.pkg.js' => array(
|
||||
'javelin-behavior-conpherence-drag-and-drop-photo',
|
||||
'javelin-behavior-conpherence-menu',
|
||||
'javelin-behavior-conpherence-participant-pane',
|
||||
'javelin-behavior-conpherence-pontificate',
|
||||
'javelin-behavior-toggle-widget',
|
||||
),
|
||||
'core.pkg.css' => array(
|
||||
'phabricator-core-css',
|
||||
'phabricator-zindex-css',
|
||||
'phui-button-css',
|
||||
'phui-theme-css',
|
||||
'phabricator-standard-page-view',
|
||||
'aphront-dialog-view-css',
|
||||
'phui-form-view-css',
|
||||
|
@ -2268,18 +2360,24 @@ return array(
|
|||
'phui-tag-view-css',
|
||||
'phui-list-view-css',
|
||||
'font-fontawesome',
|
||||
'font-lato',
|
||||
'font-aleo',
|
||||
'phui-font-icon-base-css',
|
||||
'phui-fontkit-css',
|
||||
'phui-box-css',
|
||||
'phui-object-box-css',
|
||||
'phui-timeline-view-css',
|
||||
'phui-two-column-view-css',
|
||||
'phui-curtain-view-css',
|
||||
'sprite-login-css',
|
||||
'sprite-tokens-css',
|
||||
'tokens-css',
|
||||
'auth-css',
|
||||
'phui-status-list-view-css',
|
||||
'phui-feed-story-css',
|
||||
'phabricator-feed-css',
|
||||
'phabricator-dashboard-css',
|
||||
'aphront-multi-column-view-css',
|
||||
'conpherence-durable-column-view',
|
||||
),
|
||||
'core.pkg.js' => array(
|
||||
'javelin-util',
|
||||
|
@ -2316,6 +2414,7 @@ return array(
|
|||
'phuix-dropdown-menu',
|
||||
'phuix-action-list-view',
|
||||
'phuix-action-view',
|
||||
'phuix-icon-view',
|
||||
'phabricator-phtize',
|
||||
'javelin-behavior-phabricator-oncopy',
|
||||
'phabricator-tooltip',
|
||||
|
|
|
@ -36,6 +36,7 @@ return array(
|
|||
'phuix-dropdown-menu',
|
||||
'phuix-action-list-view',
|
||||
'phuix-action-view',
|
||||
'phuix-icon-view',
|
||||
'phabricator-phtize',
|
||||
'javelin-behavior-phabricator-oncopy',
|
||||
'phabricator-tooltip',
|
||||
|
@ -88,6 +89,7 @@ return array(
|
|||
'phabricator-core-css',
|
||||
'phabricator-zindex-css',
|
||||
'phui-button-css',
|
||||
'phui-theme-css',
|
||||
'phabricator-standard-page-view',
|
||||
'aphront-dialog-view-css',
|
||||
'phui-form-view-css',
|
||||
|
@ -128,19 +130,43 @@ return array(
|
|||
'phui-list-view-css',
|
||||
|
||||
'font-fontawesome',
|
||||
'font-lato',
|
||||
'font-aleo',
|
||||
'phui-font-icon-base-css',
|
||||
'phui-fontkit-css',
|
||||
'phui-box-css',
|
||||
'phui-object-box-css',
|
||||
'phui-timeline-view-css',
|
||||
'phui-two-column-view-css',
|
||||
'phui-curtain-view-css',
|
||||
|
||||
'sprite-login-css',
|
||||
'sprite-tokens-css',
|
||||
'tokens-css',
|
||||
'phui-status-list-view-css',
|
||||
'auth-css',
|
||||
|
||||
'phui-status-list-view-css',
|
||||
'phui-feed-story-css',
|
||||
'phabricator-feed-css',
|
||||
'phabricator-dashboard-css',
|
||||
'aphront-multi-column-view-css',
|
||||
),
|
||||
'conpherence.pkg.css' => array(
|
||||
'conpherence-durable-column-view',
|
||||
'conpherence-menu-css',
|
||||
'conpherence-message-pane-css',
|
||||
'conpherence-notification-css',
|
||||
'conpherence-transaction-css',
|
||||
'conpherence-update-css',
|
||||
'conpherence-participant-pane-css',
|
||||
'conpherence-header-pane-css',
|
||||
),
|
||||
'conpherence.pkg.js' => array(
|
||||
'javelin-behavior-conpherence-drag-and-drop-photo',
|
||||
'javelin-behavior-conpherence-menu',
|
||||
'javelin-behavior-conpherence-participant-pane',
|
||||
'javelin-behavior-conpherence-pontificate',
|
||||
'javelin-behavior-toggle-widget',
|
||||
),
|
||||
'differential.pkg.css' => array(
|
||||
'differential-core-view-css',
|
||||
|
|
BIN
resources/sprite/login_1x/Slack.png
Normal file
BIN
resources/sprite/login_1x/Slack.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
BIN
resources/sprite/login_2x/Slack.png
Normal file
BIN
resources/sprite/login_2x/Slack.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.9 KiB |
|
@ -91,6 +91,11 @@
|
|||
"rule": ".login-Phabricator",
|
||||
"hash": "d0f830803593bbcc025d7d5a29ee3ecd"
|
||||
},
|
||||
"login-Slack": {
|
||||
"name": "login-Slack",
|
||||
"rule": ".login-Slack",
|
||||
"hash": "fe0df2df040032b949aa05948b6bd986"
|
||||
},
|
||||
"login-Stripe": {
|
||||
"name": "login-Stripe",
|
||||
"rule": ".login-Stripe",
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE {$NAMESPACE}_conpherence.conpherence_thread
|
||||
ADD topic VARCHAR(255) NOT NULL COLLATE {$COLLATE_TEXT};
|
|
@ -300,10 +300,11 @@ phutil_register_library_map(array(
|
|||
'ConpherenceNewRoomController' => 'applications/conpherence/controller/ConpherenceNewRoomController.php',
|
||||
'ConpherenceNotificationPanelController' => 'applications/conpherence/controller/ConpherenceNotificationPanelController.php',
|
||||
'ConpherenceParticipant' => 'applications/conpherence/storage/ConpherenceParticipant.php',
|
||||
'ConpherenceParticipantController' => 'applications/conpherence/controller/ConpherenceParticipantController.php',
|
||||
'ConpherenceParticipantCountQuery' => 'applications/conpherence/query/ConpherenceParticipantCountQuery.php',
|
||||
'ConpherenceParticipantQuery' => 'applications/conpherence/query/ConpherenceParticipantQuery.php',
|
||||
'ConpherenceParticipantView' => 'applications/conpherence/view/ConpherenceParticipantView.php',
|
||||
'ConpherenceParticipationStatus' => 'applications/conpherence/constants/ConpherenceParticipationStatus.php',
|
||||
'ConpherencePeopleWidgetView' => 'applications/conpherence/view/ConpherencePeopleWidgetView.php',
|
||||
'ConpherencePicCropControl' => 'applications/conpherence/view/ConpherencePicCropControl.php',
|
||||
'ConpherenceQueryThreadConduitAPIMethod' => 'applications/conpherence/conduit/ConpherenceQueryThreadConduitAPIMethod.php',
|
||||
'ConpherenceQueryTransactionConduitAPIMethod' => 'applications/conpherence/conduit/ConpherenceQueryTransactionConduitAPIMethod.php',
|
||||
|
@ -329,9 +330,6 @@ phutil_register_library_map(array(
|
|||
'ConpherenceUpdateController' => 'applications/conpherence/controller/ConpherenceUpdateController.php',
|
||||
'ConpherenceUpdateThreadConduitAPIMethod' => 'applications/conpherence/conduit/ConpherenceUpdateThreadConduitAPIMethod.php',
|
||||
'ConpherenceViewController' => 'applications/conpherence/controller/ConpherenceViewController.php',
|
||||
'ConpherenceWidgetConfigConstants' => 'applications/conpherence/constants/ConpherenceWidgetConfigConstants.php',
|
||||
'ConpherenceWidgetController' => 'applications/conpherence/controller/ConpherenceWidgetController.php',
|
||||
'ConpherenceWidgetView' => 'applications/conpherence/view/ConpherenceWidgetView.php',
|
||||
'DarkConsoleController' => 'applications/console/controller/DarkConsoleController.php',
|
||||
'DarkConsoleCore' => 'applications/console/core/DarkConsoleCore.php',
|
||||
'DarkConsoleDataController' => 'applications/console/controller/DarkConsoleDataController.php',
|
||||
|
@ -1652,6 +1650,8 @@ phutil_register_library_map(array(
|
|||
'PHUIInfoPanelExample' => 'applications/uiexample/examples/PHUIInfoPanelExample.php',
|
||||
'PHUIInfoPanelView' => 'view/phui/PHUIInfoPanelView.php',
|
||||
'PHUIInfoView' => 'view/form/PHUIInfoView.php',
|
||||
'PHUIInvisibleCharacterTestCase' => 'view/phui/__tests__/PHUIInvisibleCharacterTestCase.php',
|
||||
'PHUIInvisibleCharacterView' => 'view/phui/PHUIInvisibleCharacterView.php',
|
||||
'PHUIListExample' => 'applications/uiexample/examples/PHUIListExample.php',
|
||||
'PHUIListItemView' => 'view/phui/PHUIListItemView.php',
|
||||
'PHUIListView' => 'view/phui/PHUIListView.php',
|
||||
|
@ -2044,6 +2044,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorCalendarEventEditor' => 'applications/calendar/editor/PhabricatorCalendarEventEditor.php',
|
||||
'PhabricatorCalendarEventEmailCommand' => 'applications/calendar/command/PhabricatorCalendarEventEmailCommand.php',
|
||||
'PhabricatorCalendarEventEndDateTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventEndDateTransaction.php',
|
||||
'PhabricatorCalendarEventExportController' => 'applications/calendar/controller/PhabricatorCalendarEventExportController.php',
|
||||
'PhabricatorCalendarEventFrequencyTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventFrequencyTransaction.php',
|
||||
'PhabricatorCalendarEventFulltextEngine' => 'applications/calendar/search/PhabricatorCalendarEventFulltextEngine.php',
|
||||
'PhabricatorCalendarEventHeraldAdapter' => 'applications/calendar/herald/PhabricatorCalendarEventHeraldAdapter.php',
|
||||
|
@ -2211,12 +2212,12 @@ phutil_register_library_map(array(
|
|||
'PhabricatorConfigTransactionQuery' => 'applications/config/query/PhabricatorConfigTransactionQuery.php',
|
||||
'PhabricatorConfigValidationException' => 'applications/config/exception/PhabricatorConfigValidationException.php',
|
||||
'PhabricatorConfigVersionController' => 'applications/config/controller/PhabricatorConfigVersionController.php',
|
||||
'PhabricatorConfigWelcomeController' => 'applications/config/controller/PhabricatorConfigWelcomeController.php',
|
||||
'PhabricatorConpherenceApplication' => 'applications/conpherence/application/PhabricatorConpherenceApplication.php',
|
||||
'PhabricatorConpherenceColumnVisibleSetting' => 'applications/settings/setting/PhabricatorConpherenceColumnVisibleSetting.php',
|
||||
'PhabricatorConpherenceNotificationsSetting' => 'applications/settings/setting/PhabricatorConpherenceNotificationsSetting.php',
|
||||
'PhabricatorConpherencePreferencesSettingsPanel' => 'applications/settings/panel/PhabricatorConpherencePreferencesSettingsPanel.php',
|
||||
'PhabricatorConpherenceThreadPHIDType' => 'applications/conpherence/phid/PhabricatorConpherenceThreadPHIDType.php',
|
||||
'PhabricatorConpherenceWidgetVisibleSetting' => 'applications/settings/setting/PhabricatorConpherenceWidgetVisibleSetting.php',
|
||||
'PhabricatorConsoleApplication' => 'applications/console/application/PhabricatorConsoleApplication.php',
|
||||
'PhabricatorConsoleContentSource' => 'infrastructure/contentsource/PhabricatorConsoleContentSource.php',
|
||||
'PhabricatorContentSource' => 'infrastructure/contentsource/PhabricatorContentSource.php',
|
||||
|
@ -2647,7 +2648,6 @@ phutil_register_library_map(array(
|
|||
'PhabricatorGuideModule' => 'applications/guides/module/PhabricatorGuideModule.php',
|
||||
'PhabricatorGuideModuleController' => 'applications/guides/controller/PhabricatorGuideModuleController.php',
|
||||
'PhabricatorGuideQuickStartModule' => 'applications/guides/module/PhabricatorGuideQuickStartModule.php',
|
||||
'PhabricatorGuideWelcomeModule' => 'applications/guides/module/PhabricatorGuideWelcomeModule.php',
|
||||
'PhabricatorHTTPParameterTypeTableView' => 'applications/config/view/PhabricatorHTTPParameterTypeTableView.php',
|
||||
'PhabricatorHandleList' => 'applications/phid/handle/pool/PhabricatorHandleList.php',
|
||||
'PhabricatorHandleObjectSelectorDataView' => 'applications/phid/handle/view/PhabricatorHandleObjectSelectorDataView.php',
|
||||
|
@ -2687,6 +2687,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorImageMacroRemarkupRule' => 'applications/macro/markup/PhabricatorImageMacroRemarkupRule.php',
|
||||
'PhabricatorImageTransformer' => 'applications/files/PhabricatorImageTransformer.php',
|
||||
'PhabricatorImagemagickSetupCheck' => 'applications/config/check/PhabricatorImagemagickSetupCheck.php',
|
||||
'PhabricatorInFlightErrorView' => 'applications/config/view/PhabricatorInFlightErrorView.php',
|
||||
'PhabricatorIndexEngine' => 'applications/search/index/PhabricatorIndexEngine.php',
|
||||
'PhabricatorIndexEngineExtension' => 'applications/search/index/PhabricatorIndexEngineExtension.php',
|
||||
'PhabricatorIndexEngineExtensionModule' => 'applications/search/index/PhabricatorIndexEngineExtensionModule.php',
|
||||
|
@ -2708,6 +2709,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorJiraIssueHasObjectEdgeType' => 'applications/doorkeeper/edge/PhabricatorJiraIssueHasObjectEdgeType.php',
|
||||
'PhabricatorJumpNavHandler' => 'applications/search/engine/PhabricatorJumpNavHandler.php',
|
||||
'PhabricatorKeyValueDatabaseCache' => 'applications/cache/PhabricatorKeyValueDatabaseCache.php',
|
||||
'PhabricatorKeyboardRemarkupRule' => 'infrastructure/markup/rule/PhabricatorKeyboardRemarkupRule.php',
|
||||
'PhabricatorKeyring' => 'applications/files/keyring/PhabricatorKeyring.php',
|
||||
'PhabricatorKeyringConfigOptionType' => 'applications/files/keyring/PhabricatorKeyringConfigOptionType.php',
|
||||
'PhabricatorLDAPAuthProvider' => 'applications/auth/provider/PhabricatorLDAPAuthProvider.php',
|
||||
|
@ -3591,6 +3593,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorShowFiletreeSetting' => 'applications/settings/setting/PhabricatorShowFiletreeSetting.php',
|
||||
'PhabricatorSimpleEditType' => 'applications/transactions/edittype/PhabricatorSimpleEditType.php',
|
||||
'PhabricatorSite' => 'aphront/site/PhabricatorSite.php',
|
||||
'PhabricatorSlackAuthProvider' => 'applications/auth/provider/PhabricatorSlackAuthProvider.php',
|
||||
'PhabricatorSlowvoteApplication' => 'applications/slowvote/application/PhabricatorSlowvoteApplication.php',
|
||||
'PhabricatorSlowvoteChoice' => 'applications/slowvote/storage/PhabricatorSlowvoteChoice.php',
|
||||
'PhabricatorSlowvoteCloseController' => 'applications/slowvote/controller/PhabricatorSlowvoteCloseController.php',
|
||||
|
@ -4764,10 +4767,11 @@ phutil_register_library_map(array(
|
|||
'ConpherenceNewRoomController' => 'ConpherenceController',
|
||||
'ConpherenceNotificationPanelController' => 'ConpherenceController',
|
||||
'ConpherenceParticipant' => 'ConpherenceDAO',
|
||||
'ConpherenceParticipantController' => 'ConpherenceController',
|
||||
'ConpherenceParticipantCountQuery' => 'PhabricatorOffsetPagedQuery',
|
||||
'ConpherenceParticipantQuery' => 'PhabricatorOffsetPagedQuery',
|
||||
'ConpherenceParticipantView' => 'AphrontView',
|
||||
'ConpherenceParticipationStatus' => 'ConpherenceConstants',
|
||||
'ConpherencePeopleWidgetView' => 'ConpherenceWidgetView',
|
||||
'ConpherencePicCropControl' => 'AphrontFormControl',
|
||||
'ConpherenceQueryThreadConduitAPIMethod' => 'ConpherenceConduitAPIMethod',
|
||||
'ConpherenceQueryTransactionConduitAPIMethod' => 'ConpherenceConduitAPIMethod',
|
||||
|
@ -4799,9 +4803,6 @@ phutil_register_library_map(array(
|
|||
'ConpherenceUpdateController' => 'ConpherenceController',
|
||||
'ConpherenceUpdateThreadConduitAPIMethod' => 'ConpherenceConduitAPIMethod',
|
||||
'ConpherenceViewController' => 'ConpherenceController',
|
||||
'ConpherenceWidgetConfigConstants' => 'ConpherenceConstants',
|
||||
'ConpherenceWidgetController' => 'ConpherenceController',
|
||||
'ConpherenceWidgetView' => 'AphrontView',
|
||||
'DarkConsoleController' => 'PhabricatorController',
|
||||
'DarkConsoleCore' => 'Phobject',
|
||||
'DarkConsoleDataController' => 'PhabricatorController',
|
||||
|
@ -6318,6 +6319,8 @@ phutil_register_library_map(array(
|
|||
'PHUIInfoPanelExample' => 'PhabricatorUIExample',
|
||||
'PHUIInfoPanelView' => 'AphrontView',
|
||||
'PHUIInfoView' => 'AphrontView',
|
||||
'PHUIInvisibleCharacterTestCase' => 'PhabricatorTestCase',
|
||||
'PHUIInvisibleCharacterView' => 'AphrontView',
|
||||
'PHUIListExample' => 'PhabricatorUIExample',
|
||||
'PHUIListItemView' => 'AphrontTagView',
|
||||
'PHUIListView' => 'AphrontTagView',
|
||||
|
@ -6779,6 +6782,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorCalendarEventEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||
'PhabricatorCalendarEventEmailCommand' => 'MetaMTAEmailTransactionCommand',
|
||||
'PhabricatorCalendarEventEndDateTransaction' => 'PhabricatorCalendarEventDateTransaction',
|
||||
'PhabricatorCalendarEventExportController' => 'PhabricatorCalendarController',
|
||||
'PhabricatorCalendarEventFrequencyTransaction' => 'PhabricatorCalendarEventTransactionType',
|
||||
'PhabricatorCalendarEventFulltextEngine' => 'PhabricatorFulltextEngine',
|
||||
'PhabricatorCalendarEventHeraldAdapter' => 'HeraldAdapter',
|
||||
|
@ -6967,12 +6971,12 @@ phutil_register_library_map(array(
|
|||
'PhabricatorConfigTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||
'PhabricatorConfigValidationException' => 'Exception',
|
||||
'PhabricatorConfigVersionController' => 'PhabricatorConfigController',
|
||||
'PhabricatorConfigWelcomeController' => 'PhabricatorConfigController',
|
||||
'PhabricatorConpherenceApplication' => 'PhabricatorApplication',
|
||||
'PhabricatorConpherenceColumnVisibleSetting' => 'PhabricatorInternalSetting',
|
||||
'PhabricatorConpherenceNotificationsSetting' => 'PhabricatorSelectSetting',
|
||||
'PhabricatorConpherencePreferencesSettingsPanel' => 'PhabricatorEditEngineSettingsPanel',
|
||||
'PhabricatorConpherenceThreadPHIDType' => 'PhabricatorPHIDType',
|
||||
'PhabricatorConpherenceWidgetVisibleSetting' => 'PhabricatorInternalSetting',
|
||||
'PhabricatorConsoleApplication' => 'PhabricatorApplication',
|
||||
'PhabricatorConsoleContentSource' => 'PhabricatorContentSource',
|
||||
'PhabricatorContentSource' => 'Phobject',
|
||||
|
@ -7467,7 +7471,6 @@ phutil_register_library_map(array(
|
|||
'PhabricatorGuideModule' => 'Phobject',
|
||||
'PhabricatorGuideModuleController' => 'PhabricatorGuideController',
|
||||
'PhabricatorGuideQuickStartModule' => 'PhabricatorGuideModule',
|
||||
'PhabricatorGuideWelcomeModule' => 'PhabricatorGuideModule',
|
||||
'PhabricatorHTTPParameterTypeTableView' => 'AphrontView',
|
||||
'PhabricatorHandleList' => array(
|
||||
'Phobject',
|
||||
|
@ -7512,6 +7515,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorImageMacroRemarkupRule' => 'PhutilRemarkupRule',
|
||||
'PhabricatorImageTransformer' => 'Phobject',
|
||||
'PhabricatorImagemagickSetupCheck' => 'PhabricatorSetupCheck',
|
||||
'PhabricatorInFlightErrorView' => 'AphrontView',
|
||||
'PhabricatorIndexEngine' => 'Phobject',
|
||||
'PhabricatorIndexEngineExtension' => 'Phobject',
|
||||
'PhabricatorIndexEngineExtensionModule' => 'PhabricatorConfigModule',
|
||||
|
@ -7533,6 +7537,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorJiraIssueHasObjectEdgeType' => 'PhabricatorEdgeType',
|
||||
'PhabricatorJumpNavHandler' => 'Phobject',
|
||||
'PhabricatorKeyValueDatabaseCache' => 'PhutilKeyValueCache',
|
||||
'PhabricatorKeyboardRemarkupRule' => 'PhutilRemarkupRule',
|
||||
'PhabricatorKeyring' => 'Phobject',
|
||||
'PhabricatorKeyringConfigOptionType' => 'PhabricatorConfigJSONOptionType',
|
||||
'PhabricatorLDAPAuthProvider' => 'PhabricatorAuthProvider',
|
||||
|
@ -8598,6 +8603,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorShowFiletreeSetting' => 'PhabricatorSelectSetting',
|
||||
'PhabricatorSimpleEditType' => 'PhabricatorEditType',
|
||||
'PhabricatorSite' => 'AphrontSite',
|
||||
'PhabricatorSlackAuthProvider' => 'PhabricatorOAuth2AuthProvider',
|
||||
'PhabricatorSlowvoteApplication' => 'PhabricatorApplication',
|
||||
'PhabricatorSlowvoteChoice' => 'PhabricatorSlowvoteDAO',
|
||||
'PhabricatorSlowvoteCloseController' => 'PhabricatorSlowvoteController',
|
||||
|
@ -9357,8 +9363,9 @@ phutil_register_library_map(array(
|
|||
'PhabricatorFlaggableInterface',
|
||||
'PhabricatorTokenReceiverInterface',
|
||||
'PhabricatorDestructibleInterface',
|
||||
'PhabricatorApplicationTransactionInterface',
|
||||
'PhabricatorFulltextInterface',
|
||||
'PhabricatorProjectInterface',
|
||||
'PhabricatorApplicationTransactionInterface',
|
||||
),
|
||||
'PhrictionDocumentAuthorHeraldField' => 'PhrictionDocumentHeraldField',
|
||||
'PhrictionDocumentContentHeraldField' => 'PhrictionDocumentHeraldField',
|
||||
|
|
|
@ -886,9 +886,8 @@ final class PhabricatorAuditEditor
|
|||
protected function buildHeraldAdapter(
|
||||
PhabricatorLiskDAO $object,
|
||||
array $xactions) {
|
||||
|
||||
return id(new HeraldCommitAdapter())
|
||||
->setCommit($object);
|
||||
->setObject($object);
|
||||
}
|
||||
|
||||
protected function didApplyHeraldRules(
|
||||
|
|
|
@ -89,13 +89,14 @@ final class PhabricatorAuthRegisterController
|
|||
// user expectation and it's not clear the cases it enables are valuable.
|
||||
// See discussion in T3472.
|
||||
if (!PhabricatorUserEmail::isAllowedAddress($default_email)) {
|
||||
$debug_email = new PHUIInvisibleCharacterView($default_email);
|
||||
return $this->renderError(
|
||||
array(
|
||||
pht(
|
||||
'The account you are attempting to register with has an invalid '.
|
||||
'email address (%s). This Phabricator install only allows '.
|
||||
'registration with specific email addresses:',
|
||||
$default_email),
|
||||
$debug_email),
|
||||
phutil_tag('br'),
|
||||
phutil_tag('br'),
|
||||
PhabricatorUserEmail::describeAllowedAddresses(),
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorSlackAuthProvider
|
||||
extends PhabricatorOAuth2AuthProvider {
|
||||
|
||||
public function getProviderName() {
|
||||
return pht('Slack');
|
||||
}
|
||||
|
||||
protected function getProviderConfigurationHelp() {
|
||||
$login_uri = PhabricatorEnv::getURI($this->getLoginURI());
|
||||
|
||||
return pht(
|
||||
"To configure Slack OAuth, create a new application here:".
|
||||
"\n\n".
|
||||
"https://api.slack.com/docs/sign-in-with-slack#create_slack_app".
|
||||
"\n\n".
|
||||
"When creating your application, use these settings:".
|
||||
"\n\n".
|
||||
" - **Redirect URI:** Set this to: `%s`".
|
||||
"\n\n".
|
||||
"After completing configuration, copy the **Client ID** and ".
|
||||
"**Client Secret** to the fields above. (You may need to generate the ".
|
||||
"client secret by clicking 'New Secret' first.)",
|
||||
$login_uri);
|
||||
}
|
||||
|
||||
protected function newOAuthAdapter() {
|
||||
return new PhutilSlackAuthAdapter();
|
||||
}
|
||||
|
||||
protected function getLoginIcon() {
|
||||
return 'Slack';
|
||||
}
|
||||
|
||||
}
|
43
src/applications/cache/PhabricatorCaches.php
vendored
43
src/applications/cache/PhabricatorCaches.php
vendored
|
@ -143,6 +143,39 @@ final class PhabricatorCaches extends Phobject {
|
|||
}
|
||||
|
||||
|
||||
/* -( Server State Cache )------------------------------------------------- */
|
||||
|
||||
|
||||
/**
|
||||
* Highly specialized cache for storing server process state.
|
||||
*
|
||||
* We use this cache to track initial steps in the setup phase, before
|
||||
* configuration is loaded.
|
||||
*
|
||||
* This cache does NOT use the cache namespace (it must be accessed before
|
||||
* we build configuration), and is global across all instances on the host.
|
||||
*
|
||||
* @return PhutilKeyValueCacheStack Best available server state cache stack.
|
||||
* @task setup
|
||||
*/
|
||||
public static function getServerStateCache() {
|
||||
static $cache;
|
||||
if (!$cache) {
|
||||
$caches = self::buildSetupCaches('phabricator-server');
|
||||
|
||||
// NOTE: We are NOT adding a cache namespace here! This cache is shared
|
||||
// across all instances on the host.
|
||||
|
||||
$caches = self::addProfilerToCaches($caches);
|
||||
$cache = id(new PhutilKeyValueCacheStack())
|
||||
->setCaches($caches);
|
||||
|
||||
}
|
||||
return $cache;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* -( Setup Cache )-------------------------------------------------------- */
|
||||
|
||||
|
||||
|
@ -163,7 +196,7 @@ final class PhabricatorCaches extends Phobject {
|
|||
public static function getSetupCache() {
|
||||
static $cache;
|
||||
if (!$cache) {
|
||||
$caches = self::buildSetupCaches();
|
||||
$caches = self::buildSetupCaches('phabricator-setup');
|
||||
$cache = self::newStackFromCaches($caches);
|
||||
}
|
||||
return $cache;
|
||||
|
@ -173,7 +206,7 @@ final class PhabricatorCaches extends Phobject {
|
|||
/**
|
||||
* @task setup
|
||||
*/
|
||||
private static function buildSetupCaches() {
|
||||
private static function buildSetupCaches($cache_name) {
|
||||
// If this is the CLI, just build a setup cache.
|
||||
if (php_sapi_name() == 'cli') {
|
||||
return array();
|
||||
|
@ -188,7 +221,7 @@ final class PhabricatorCaches extends Phobject {
|
|||
|
||||
// If we don't have APC, build a poor approximation on disk. This is still
|
||||
// much better than nothing; some setup steps are quite slow.
|
||||
$disk_path = self::getSetupCacheDiskCachePath();
|
||||
$disk_path = self::getSetupCacheDiskCachePath($cache_name);
|
||||
if ($disk_path) {
|
||||
$disk = new PhutilOnDiskKeyValueCache();
|
||||
$disk->setCacheFile($disk_path);
|
||||
|
@ -205,7 +238,7 @@ final class PhabricatorCaches extends Phobject {
|
|||
/**
|
||||
* @task setup
|
||||
*/
|
||||
private static function getSetupCacheDiskCachePath() {
|
||||
private static function getSetupCacheDiskCachePath($name) {
|
||||
// The difficulty here is in choosing a path which will change on server
|
||||
// restart (we MUST have this property), but as rarely as possible
|
||||
// otherwise (we desire this property to give the cache the best hit rate
|
||||
|
@ -230,7 +263,7 @@ final class PhabricatorCaches extends Phobject {
|
|||
|
||||
$tmp_dir = sys_get_temp_dir();
|
||||
|
||||
$tmp_path = $tmp_dir.DIRECTORY_SEPARATOR.'phabricator-setup';
|
||||
$tmp_path = $tmp_dir.DIRECTORY_SEPARATOR.$name;
|
||||
if (!file_exists($tmp_path)) {
|
||||
@mkdir($tmp_path);
|
||||
}
|
||||
|
|
|
@ -59,6 +59,8 @@ final class PhabricatorCalendarApplication extends PhabricatorApplication {
|
|||
=> 'PhabricatorCalendarEventCancelController',
|
||||
'(?P<action>join|decline|accept)/(?P<id>[1-9]\d*)/'
|
||||
=> 'PhabricatorCalendarEventJoinController',
|
||||
'export/(?P<id>[1-9]\d*)/(?P<filename>[^/]*)'
|
||||
=> 'PhabricatorCalendarEventExportController',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorCalendarEventExportController
|
||||
extends PhabricatorCalendarController {
|
||||
|
||||
public function shouldAllowPublic() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $this->getViewer();
|
||||
$id = $request->getURIData('id');
|
||||
|
||||
$event = id(new PhabricatorCalendarEventQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($id))
|
||||
->executeOne();
|
||||
if (!$event) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$file_name = $event->getICSFilename();
|
||||
$event_node = $event->newIntermediateEventNode($viewer);
|
||||
|
||||
$document_node = id(new PhutilCalendarDocumentNode())
|
||||
->appendChild($event_node);
|
||||
|
||||
$root_node = id(new PhutilCalendarRootNode())
|
||||
->appendChild($document_node);
|
||||
|
||||
$ics_data = id(new PhutilICSWriter())
|
||||
->writeICSDocument($root_node);
|
||||
|
||||
return id(new AphrontFileResponse())
|
||||
->setDownload($file_name)
|
||||
->setMimeType('text/calendar')
|
||||
->setContent($ics_data);
|
||||
}
|
||||
|
||||
}
|
|
@ -193,6 +193,15 @@ final class PhabricatorCalendarEventViewController
|
|||
->setWorkflow(true));
|
||||
}
|
||||
|
||||
$ics_name = $event->getICSFilename();
|
||||
$export_uri = $this->getApplicationURI("event/export/{$id}/{$ics_name}");
|
||||
|
||||
$curtain->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName(pht('Export as .ics'))
|
||||
->setIcon('fa-download')
|
||||
->setHref($export_uri));
|
||||
|
||||
return $curtain;
|
||||
}
|
||||
|
||||
|
@ -278,7 +287,14 @@ final class PhabricatorCalendarEventViewController
|
|||
$parent = $event->getParentEvent();
|
||||
}
|
||||
|
||||
$next_uri = $parent->getURI().'/'.($sequence + 1);
|
||||
if ($parent->isValidSequenceIndex($viewer, $sequence + 1)) {
|
||||
$next_uri = $parent->getURI().'/'.($sequence + 1);
|
||||
$has_next = true;
|
||||
} else {
|
||||
$next_uri = null;
|
||||
$has_next = false;
|
||||
}
|
||||
|
||||
if ($sequence) {
|
||||
if ($sequence > 1) {
|
||||
$previous_uri = $parent->getURI().'/'.($sequence - 1);
|
||||
|
@ -302,6 +318,7 @@ final class PhabricatorCalendarEventViewController
|
|||
->setTag('a')
|
||||
->setIcon('fa-chevron-right')
|
||||
->setHref($next_uri)
|
||||
->setDisabled(!$has_next)
|
||||
->setText(pht('Next'));
|
||||
|
||||
$header
|
||||
|
@ -450,9 +467,11 @@ final class PhabricatorCalendarEventViewController
|
|||
'it.'));
|
||||
}
|
||||
|
||||
$instance = $event->newStub($viewer, $sequence);
|
||||
if (!$event->isValidSequenceIndex($viewer, $sequence)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $instance;
|
||||
return $event->newStub($viewer, $sequence);
|
||||
}
|
||||
|
||||
private function buildSubheaderView(PhabricatorCalendarEvent $event) {
|
||||
|
|
|
@ -285,6 +285,8 @@ final class PhabricatorCalendarEventEditor
|
|||
pht('EVENT DETAIL'),
|
||||
PhabricatorEnv::getProductionURI('/E'.$object->getID()));
|
||||
|
||||
$ics_attachment = $this->newICSAttachment($object);
|
||||
$body->addAttachment($ics_attachment);
|
||||
|
||||
return $body;
|
||||
}
|
||||
|
@ -303,5 +305,27 @@ final class PhabricatorCalendarEventEditor
|
|||
->setObject($object);
|
||||
}
|
||||
|
||||
private function newICSAttachment(
|
||||
PhabricatorCalendarEvent $event) {
|
||||
$actor = $this->getActor();
|
||||
|
||||
$event_node = $event->newIntermediateEventNode($actor);
|
||||
|
||||
$document_node = id(new PhutilCalendarDocumentNode())
|
||||
->appendChild($event_node);
|
||||
|
||||
$root_node = id(new PhutilCalendarRootNode())
|
||||
->appendChild($document_node);
|
||||
|
||||
$ics_data = id(new PhutilICSWriter())
|
||||
->writeICSDocument($root_node);
|
||||
|
||||
$ics_attachment = new PhabricatorMetaMTAAttachment(
|
||||
$ics_data,
|
||||
$event->getICSFilename(),
|
||||
'text/calendar');
|
||||
|
||||
return $ics_attachment;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -137,7 +137,8 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
|
|||
);
|
||||
|
||||
// Read these fields from the parent event instead of this event. For
|
||||
// example, we want any changes to the parent event's name to
|
||||
// example, we want any changes to the parent event's name to apply to
|
||||
// the child.
|
||||
if (isset($inherit[$field])) {
|
||||
if ($this->getIsStub()) {
|
||||
// TODO: This should be unconditional, but the execution order of
|
||||
|
@ -171,33 +172,66 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
|
|||
->setName($parent->getName())
|
||||
->setDescription($parent->getDescription());
|
||||
|
||||
$frequency = $parent->getFrequencyUnit();
|
||||
$modify_key = '+'.$this->getSequenceIndex().' '.$frequency;
|
||||
$sequence = $this->getSequenceIndex();
|
||||
$duration = $this->getDuration();
|
||||
$epochs = $parent->getSequenceIndexEpochs($actor, $sequence, $duration);
|
||||
|
||||
$date = $parent->getDateFrom();
|
||||
$date_time = PhabricatorTime::getDateTimeFromEpoch($date, $actor);
|
||||
$this
|
||||
->setDateFrom($epochs['dateFrom'])
|
||||
->setDateTo($epochs['dateTo'])
|
||||
->setAllDayDateFrom($epochs['allDayDateFrom'])
|
||||
->setAllDayDateTo($epochs['allDayDateTo']);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isValidSequenceIndex(PhabricatorUser $viewer, $sequence) {
|
||||
try {
|
||||
$this->getSequenceIndexEpochs($viewer, $sequence, $this->getDuration());
|
||||
return true;
|
||||
} catch (Exception $ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private function getSequenceIndexEpochs(
|
||||
PhabricatorUser $viewer,
|
||||
$sequence,
|
||||
$duration) {
|
||||
|
||||
$frequency = $this->getFrequencyUnit();
|
||||
$modify_key = '+'.$sequence.' '.$frequency;
|
||||
|
||||
$date = $this->getDateFrom();
|
||||
$date_time = PhabricatorTime::getDateTimeFromEpoch($date, $viewer);
|
||||
$date_time->modify($modify_key);
|
||||
$date = $date_time->format('U');
|
||||
|
||||
$duration = $this->getDuration();
|
||||
$end_date = $this->getRecurrenceEndDate();
|
||||
if ($end_date && $date > $end_date) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Sequence "%s" is invalid for this event: it would occur after '.
|
||||
'the event stops repeating.',
|
||||
$sequence));
|
||||
}
|
||||
|
||||
$utc = new DateTimeZone('UTC');
|
||||
|
||||
$allday_from = $parent->getAllDayDateFrom();
|
||||
$allday_from = $this->getAllDayDateFrom();
|
||||
$allday_date = new DateTime('@'.$allday_from, $utc);
|
||||
$allday_date->setTimeZone($utc);
|
||||
$allday_date->modify($modify_key);
|
||||
|
||||
$allday_min = $allday_date->format('U');
|
||||
$allday_duration = ($parent->getAllDayDateTo() - $allday_from);
|
||||
$allday_duration = ($this->getAllDayDateTo() - $allday_from);
|
||||
|
||||
$this
|
||||
->setDateFrom($date)
|
||||
->setDateTo($date + $duration)
|
||||
->setAllDayDateFrom($allday_min)
|
||||
->setAllDayDateTo($allday_min + $allday_duration);
|
||||
|
||||
return $this;
|
||||
return array(
|
||||
'dateFrom' => $date,
|
||||
'dateTo' => $date + $duration,
|
||||
'allDayDateFrom' => $allday_min,
|
||||
'allDayDateTo' => $allday_min + $allday_duration,
|
||||
);
|
||||
}
|
||||
|
||||
public function newStub(PhabricatorUser $actor, $sequence) {
|
||||
|
@ -591,6 +625,101 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
|
|||
return null;
|
||||
}
|
||||
|
||||
public function getICSFilename() {
|
||||
return $this->getMonogram().'.ics';
|
||||
}
|
||||
|
||||
public function newIntermediateEventNode(PhabricatorUser $viewer) {
|
||||
$base_uri = new PhutilURI(PhabricatorEnv::getProductionURI('/'));
|
||||
$domain = $base_uri->getDomain();
|
||||
|
||||
$uid = $this->getPHID().'@'.$domain;
|
||||
|
||||
$created = $this->getDateCreated();
|
||||
$created = PhutilCalendarAbsoluteDateTime::newFromEpoch($created);
|
||||
|
||||
$modified = $this->getDateModified();
|
||||
$modified = PhutilCalendarAbsoluteDateTime::newFromEpoch($modified);
|
||||
|
||||
$date_start = $this->getDateFrom();
|
||||
$date_start = PhutilCalendarAbsoluteDateTime::newFromEpoch($date_start);
|
||||
|
||||
$date_end = $this->getDateTo();
|
||||
$date_end = PhutilCalendarAbsoluteDateTime::newFromEpoch($date_end);
|
||||
|
||||
if ($this->getIsAllDay()) {
|
||||
$date_start->setIsAllDay(true);
|
||||
$date_end->setIsAllDay(true);
|
||||
}
|
||||
|
||||
$host_phid = $this->getHostPHID();
|
||||
|
||||
$invitees = $this->getInvitees();
|
||||
foreach ($invitees as $key => $invitee) {
|
||||
if ($invitee->isUninvited()) {
|
||||
unset($invitees[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
$phids = array();
|
||||
$phids[] = $host_phid;
|
||||
foreach ($invitees as $invitee) {
|
||||
$phids[] = $invitee->getInviteePHID();
|
||||
}
|
||||
|
||||
$handles = $viewer->loadHandles($phids);
|
||||
|
||||
$host_handle = $handles[$host_phid];
|
||||
$host_name = $host_handle->getFullName();
|
||||
$host_uri = $host_handle->getURI();
|
||||
$host_uri = PhabricatorEnv::getURI($host_uri);
|
||||
|
||||
$organizer = id(new PhutilCalendarUserNode())
|
||||
->setName($host_name)
|
||||
->setURI($host_uri);
|
||||
|
||||
$attendees = array();
|
||||
foreach ($invitees as $invitee) {
|
||||
$invitee_phid = $invitee->getInviteePHID();
|
||||
$invitee_handle = $handles[$invitee_phid];
|
||||
$invitee_name = $invitee_handle->getFullName();
|
||||
$invitee_uri = $invitee_handle->getURI();
|
||||
$invitee_uri = PhabricatorEnv::getURI($invitee_uri);
|
||||
|
||||
switch ($invitee->getStatus()) {
|
||||
case PhabricatorCalendarEventInvitee::STATUS_ATTENDING:
|
||||
$status = PhutilCalendarUserNode::STATUS_ACCEPTED;
|
||||
break;
|
||||
case PhabricatorCalendarEventInvitee::STATUS_DECLINED:
|
||||
$status = PhutilCalendarUserNode::STATUS_DECLINED;
|
||||
break;
|
||||
case PhabricatorCalendarEventInvitee::STATUS_INVITED:
|
||||
default:
|
||||
$status = PhutilCalendarUserNode::STATUS_INVITED;
|
||||
break;
|
||||
}
|
||||
|
||||
$attendees[] = id(new PhutilCalendarUserNode())
|
||||
->setName($invitee_name)
|
||||
->setURI($invitee_uri)
|
||||
->setStatus($status);
|
||||
}
|
||||
|
||||
$node = id(new PhutilCalendarEventNode())
|
||||
->setUID($uid)
|
||||
->setName($this->getName())
|
||||
->setDescription($this->getDescription())
|
||||
->setCreatedDateTime($created)
|
||||
->setModifiedDateTime($modified)
|
||||
->setStartDateTime($date_start)
|
||||
->setEndDateTime($date_end)
|
||||
->setOrganizer($organizer)
|
||||
->setAttendees($attendees);
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* -( Markup Interface )--------------------------------------------------- */
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ final class CelerityHighContrastPostprocessor
|
|||
'thinblueborder' => '#BFCFDA',
|
||||
'lightblueborder' => '#8C98B8',
|
||||
'blueborder' => '#626E82',
|
||||
'timeline' => '#8C98B8',
|
||||
|
||||
'lightgreyborder' => '#555',
|
||||
'greyborder' => '#333',
|
||||
|
|
|
@ -38,6 +38,9 @@ abstract class ConduitParameterType extends Phobject {
|
|||
return $this->getParameterValue($request, $key);
|
||||
}
|
||||
|
||||
final public function getKeys($key) {
|
||||
return $this->getParameterKeys($key);
|
||||
}
|
||||
|
||||
final public function getDefaultValue() {
|
||||
return $this->getParameterDefault();
|
||||
|
@ -86,6 +89,10 @@ abstract class ConduitParameterType extends Phobject {
|
|||
return $request[$key];
|
||||
}
|
||||
|
||||
protected function getParameterKeys($key) {
|
||||
return array($key);
|
||||
}
|
||||
|
||||
abstract protected function getParameterTypeName();
|
||||
|
||||
|
||||
|
|
|
@ -44,7 +44,6 @@ final class PhabricatorConfigApplication extends PhabricatorApplication {
|
|||
'edit/(?P<key>[\w\.\-]+)/' => 'PhabricatorConfigEditController',
|
||||
'group/(?P<key>[^/]+)/' => 'PhabricatorConfigGroupController',
|
||||
'version/' => 'PhabricatorConfigVersionController',
|
||||
'welcome/' => 'PhabricatorConfigWelcomeController',
|
||||
'database/'.
|
||||
'(?:(?P<database>[^/]+)/'.
|
||||
'(?:(?P<table>[^/]+)/'.
|
||||
|
|
|
@ -74,6 +74,9 @@ abstract class PhabricatorSetupCheck extends Phobject {
|
|||
$cache = PhabricatorCaches::getSetupCache();
|
||||
$cache->setKey('phabricator.setup.issue-keys', $keys);
|
||||
|
||||
$server_cache = PhabricatorCaches::getServerStateCache();
|
||||
$server_cache->setKey('phabricator.in-flight', 1);
|
||||
|
||||
if ($update_database) {
|
||||
$db_cache = new PhabricatorKeyValueDatabaseCache();
|
||||
try {
|
||||
|
@ -192,6 +195,22 @@ abstract class PhabricatorSetupCheck extends Phobject {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if we've survived through setup on at least one normal request
|
||||
* without fataling.
|
||||
*
|
||||
* If we've made it through setup without hitting any fatals, we switch
|
||||
* to render a more friendly error page when encountering issues like
|
||||
* database connection failures. This gives users a smoother experience in
|
||||
* the face of intermittent failures.
|
||||
*
|
||||
* @return bool True if we've made it through setup since the last restart.
|
||||
*/
|
||||
final public static function isInFlight() {
|
||||
$cache = PhabricatorCaches::getServerStateCache();
|
||||
return (bool)$cache->getKey('phabricator.in-flight');
|
||||
}
|
||||
|
||||
final public static function loadAllChecks() {
|
||||
return id(new PhutilClassMapQuery())
|
||||
->setAncestorClass(__CLASS__)
|
||||
|
|
|
@ -153,6 +153,14 @@ final class PhabricatorConfigClusterRepositoriesController
|
|||
|
||||
$versions = idx($repository_versions, $repository_phid, array());
|
||||
|
||||
// Filter out any versions for devices which are no longer active.
|
||||
foreach ($versions as $key => $version) {
|
||||
$version_device_phid = $version->getDevicePHID();
|
||||
if (empty($active_devices[$version_device_phid])) {
|
||||
unset($versions[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
$leaders = 0;
|
||||
foreach ($versions as $version) {
|
||||
if ($version->getRepositoryVersion() == $leader_version) {
|
||||
|
|
|
@ -7,33 +7,47 @@ abstract class PhabricatorConfigController extends PhabricatorController {
|
|||
}
|
||||
|
||||
public function buildSideNavView($filter = null, $for_app = false) {
|
||||
$user = $this->getRequest()->getUser();
|
||||
|
||||
$guide_href = new PhutilURI('/guides/');
|
||||
$nav = new AphrontSideNavFilterView();
|
||||
$nav->setBaseURI(new PhutilURI($this->getApplicationURI()));
|
||||
$nav->addLabel(pht('Configuration'));
|
||||
$nav->addFilter('/', pht('Core Settings'));
|
||||
$nav->addFilter('application/', pht('Application Settings'));
|
||||
$nav->addFilter('history/', pht('Settings History'));
|
||||
$nav->addFilter('version/', pht('Version Information'));
|
||||
$nav->addFilter('all/', pht('All Settings'));
|
||||
$nav->addFilter('/',
|
||||
pht('Core Settings'), null, 'fa-gear');
|
||||
$nav->addFilter('application/',
|
||||
pht('Application Settings'), null, 'fa-globe');
|
||||
$nav->addFilter('history/',
|
||||
pht('Settings History'), null, 'fa-history');
|
||||
$nav->addFilter('version/',
|
||||
pht('Version Information'), null, 'fa-download');
|
||||
$nav->addFilter('all/',
|
||||
pht('All Settings'), null, 'fa-list-ul');
|
||||
$nav->addLabel(pht('Setup'));
|
||||
$nav->addFilter('issue/', pht('Setup Issues'));
|
||||
$nav->addFilter('welcome/', pht('Installation Guide'));
|
||||
$nav->addFilter('issue/',
|
||||
pht('Setup Issues'), null, 'fa-warning');
|
||||
$nav->addFilter(null,
|
||||
pht('Installation Guide'), $guide_href, 'fa-book');
|
||||
$nav->addLabel(pht('Database'));
|
||||
$nav->addFilter('database/', pht('Database Status'));
|
||||
$nav->addFilter('dbissue/', pht('Database Issues'));
|
||||
$nav->addFilter('database/',
|
||||
pht('Database Status'), null, 'fa-heartbeat');
|
||||
$nav->addFilter('dbissue/',
|
||||
pht('Database Issues'), null, 'fa-exclamation-circle');
|
||||
$nav->addLabel(pht('Cache'));
|
||||
$nav->addFilter('cache/', pht('Cache Status'));
|
||||
$nav->addFilter('cache/',
|
||||
pht('Cache Status'), null, 'fa-home');
|
||||
$nav->addLabel(pht('Cluster'));
|
||||
$nav->addFilter('cluster/databases/', pht('Database Servers'));
|
||||
$nav->addFilter('cluster/notifications/', pht('Notification Servers'));
|
||||
$nav->addFilter('cluster/repositories/', pht('Repository Servers'));
|
||||
$nav->addFilter('cluster/databases/',
|
||||
pht('Database Servers'), null, 'fa-database');
|
||||
$nav->addFilter('cluster/notifications/',
|
||||
pht('Notification Servers'), null, 'fa-bell-o');
|
||||
$nav->addFilter('cluster/repositories/',
|
||||
pht('Repository Servers'), null, 'fa-code');
|
||||
$nav->addLabel(pht('Modules'));
|
||||
|
||||
$modules = PhabricatorConfigModule::getAllModules();
|
||||
foreach ($modules as $key => $module) {
|
||||
$nav->addFilter('module/'.$key.'/', $module->getModuleName());
|
||||
$nav->addFilter('module/'.$key.'/',
|
||||
$module->getModuleName(), null, 'fa-puzzle-piece');
|
||||
}
|
||||
|
||||
return $nav;
|
||||
|
|
|
@ -1,411 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorConfigWelcomeController
|
||||
extends PhabricatorConfigController {
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $request->getViewer();
|
||||
|
||||
$nav = $this->buildSideNavView();
|
||||
$nav->selectFilter('welcome/');
|
||||
|
||||
$title = pht('Installation Guide');
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader($title)
|
||||
->setProfileHeader(true);
|
||||
|
||||
$crumbs = $this
|
||||
->buildApplicationCrumbs()
|
||||
->addTextCrumb($title)
|
||||
->setBorder(true);
|
||||
|
||||
$content = id(new PhabricatorConfigPageView())
|
||||
->setHeader($header)
|
||||
->setContent($this->buildWelcomeScreen($request));
|
||||
|
||||
return $this->newPage()
|
||||
->setTitle($title)
|
||||
->setCrumbs($crumbs)
|
||||
->setNavigation($nav)
|
||||
->appendChild($content)
|
||||
->addClass('white-background');
|
||||
}
|
||||
|
||||
public function buildWelcomeScreen(AphrontRequest $request) {
|
||||
$viewer = $request->getUser();
|
||||
$this->requireResource('config-welcome-css');
|
||||
|
||||
$content = pht(
|
||||
"=== Install Phabricator ===\n\n".
|
||||
"You have successfully installed Phabricator. This screen will guide ".
|
||||
"you through configuration and orientation. ".
|
||||
"These steps are optional, and you can go through them in any order. ".
|
||||
"If you want to get back to this screen later on, you can find it in ".
|
||||
"the **Config** application under **Welcome Screen**.");
|
||||
|
||||
$setup = array();
|
||||
|
||||
$setup[] = $this->newItem(
|
||||
$request,
|
||||
'fa-check-square-o green',
|
||||
$content);
|
||||
|
||||
$issues_resolved = !PhabricatorSetupCheck::getOpenSetupIssueKeys();
|
||||
|
||||
$setup_href = PhabricatorEnv::getURI('/config/issue/');
|
||||
if ($issues_resolved) {
|
||||
$content = pht(
|
||||
"=== Resolve Setup Issues ===\n\n".
|
||||
"You've resolved (or ignored) all outstanding setup issues. ".
|
||||
"You can review issues in the **Config** application, under ".
|
||||
"**[[ %s | Setup Issues ]]**.",
|
||||
$setup_href);
|
||||
$icon = 'fa-check-square-o green';
|
||||
} else {
|
||||
$content = pht(
|
||||
"=== Resolve Setup Issues ===\n\n".
|
||||
"You have some unresolved setup issues to take care of. Click ".
|
||||
"the link in the yellow banner at the top of the screen to see ".
|
||||
"them, or find them in the **Config** application under ".
|
||||
"**[[ %s | Setup Issues ]]**. ".
|
||||
"Although most setup issues should be resolved, sometimes an issue ".
|
||||
"is not applicable to an install. ".
|
||||
"If you don't intend to fix a setup issue (or don't want to fix ".
|
||||
"it for now), you can use the \"Ignore\" action to mark it as ".
|
||||
"something you don't plan to deal with.",
|
||||
$setup_href);
|
||||
$icon = 'fa-warning red';
|
||||
}
|
||||
|
||||
$setup[] = $this->newItem(
|
||||
$request,
|
||||
$icon,
|
||||
$content);
|
||||
|
||||
$configs = id(new PhabricatorAuthProviderConfigQuery())
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->execute();
|
||||
|
||||
$auth_href = PhabricatorEnv::getURI('/auth/');
|
||||
$have_auth = (bool)$configs;
|
||||
if ($have_auth) {
|
||||
$content = pht(
|
||||
"=== Login and Registration ===\n\n".
|
||||
"You've configured at least one authentication provider, so users ".
|
||||
"can register or log in. ".
|
||||
"To configure more providers or adjust settings, use the ".
|
||||
"**[[ %s | Auth Application ]]**.",
|
||||
$auth_href);
|
||||
$icon = 'fa-check-square-o green';
|
||||
} else {
|
||||
$content = pht(
|
||||
"=== Login and Registration ===\n\n".
|
||||
"You haven't configured any authentication providers yet. ".
|
||||
"Authentication providers allow users to register accounts and ".
|
||||
"log in to Phabricator. You can configure Phabricator to accept ".
|
||||
"credentials like username and password, LDAP, or Google OAuth. ".
|
||||
"You can configure authentication using the ".
|
||||
"**[[ %s | Auth Application ]]**.",
|
||||
$auth_href);
|
||||
$icon = 'fa-warning red';
|
||||
}
|
||||
|
||||
$setup[] = $this->newItem(
|
||||
$request,
|
||||
$icon,
|
||||
$content);
|
||||
|
||||
$config_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) {
|
||||
$content = pht(
|
||||
"=== Configure Phabricator Settings ===\n\n".
|
||||
"You've configured at least one setting from the web interface. ".
|
||||
"To configure more settings later, use the ".
|
||||
"**[[ %s | Config Application ]]**.",
|
||||
$config_href);
|
||||
$icon = 'fa-check-square-o green';
|
||||
} else {
|
||||
$content = pht(
|
||||
"=== Configure Phabricator Settings ===\n\n".
|
||||
'Many aspects of Phabricator are configurable. To explore and '.
|
||||
'adjust settings, use the **[[ %s | Config Application ]]**.',
|
||||
$config_href);
|
||||
$icon = 'fa-info-circle';
|
||||
}
|
||||
|
||||
$setup[] = $this->newItem(
|
||||
$request,
|
||||
$icon,
|
||||
$content);
|
||||
|
||||
$settings_href = PhabricatorEnv::getURI('/settings/');
|
||||
|
||||
$preferences = id(new PhabricatorUserPreferencesQuery())
|
||||
->setViewer($viewer)
|
||||
->withUsers(array($viewer))
|
||||
->executeOne();
|
||||
|
||||
$have_settings = ($preferences && $preferences->getPreferences());
|
||||
|
||||
if ($have_settings) {
|
||||
$content = pht(
|
||||
"=== Adjust Account Settings ===\n\n".
|
||||
"You've adjusted at least one setting on your account. ".
|
||||
"To make more adjustments, visit the ".
|
||||
"**[[ %s | Settings Application ]]**.",
|
||||
$settings_href);
|
||||
$icon = 'fa-check-square-o green';
|
||||
} else {
|
||||
$content = pht(
|
||||
"=== Adjust Account Settings ===\n\n".
|
||||
'You can configure settings for your account by clicking the '.
|
||||
'wrench icon in the main menu bar, or visiting the '.
|
||||
'**[[ %s | Settings Application ]]** directly.',
|
||||
$settings_href);
|
||||
$icon = 'fa-info-circle';
|
||||
}
|
||||
|
||||
$setup[] = $this->newItem(
|
||||
$request,
|
||||
$icon,
|
||||
$content);
|
||||
|
||||
$dashboard_href = PhabricatorEnv::getURI('/dashboard/');
|
||||
$have_dashboard = (bool)PhabricatorDashboardInstall::getDashboard(
|
||||
$viewer,
|
||||
PhabricatorHomeApplication::DASHBOARD_DEFAULT,
|
||||
'PhabricatorHomeApplication');
|
||||
if ($have_dashboard) {
|
||||
$content = pht(
|
||||
"=== Customize Home Page ===\n\n".
|
||||
"You've installed a default dashboard to replace this welcome screen ".
|
||||
"on the home page. ".
|
||||
"You can still visit the welcome screen here at any time if you ".
|
||||
"have steps you want to complete later, or if you feel lonely. ".
|
||||
"If you've changed your mind about the dashboard you installed, ".
|
||||
"you can install a different default dashboard with the ".
|
||||
"**[[ %s | Dashboards Application ]]**.",
|
||||
$dashboard_href);
|
||||
$icon = 'fa-check-square-o green';
|
||||
} else {
|
||||
$content = pht(
|
||||
"=== Customize Home Page ===\n\n".
|
||||
"When you're done setting things up, you can create a custom ".
|
||||
"dashboard and install it. Your dashboard will replace this ".
|
||||
"welcome screen on the Phabricator home page. ".
|
||||
"Dashboards can show users the information that's most important to ".
|
||||
"your organization. You can configure them to display things like: ".
|
||||
"a custom welcome message, a feed of recent activity, or a list of ".
|
||||
"open tasks, waiting reviews, recent commits, and so on. ".
|
||||
"After you install a default dashboard, it will replace this page. ".
|
||||
"You can find this page later by visiting the **Config** ".
|
||||
"application, under **Welcome Page**. ".
|
||||
"To get started building a dashboard, use the ".
|
||||
"**[[ %s | Dashboards Application ]]**. ",
|
||||
$dashboard_href);
|
||||
$icon = 'fa-info-circle';
|
||||
}
|
||||
|
||||
$setup[] = $this->newItem(
|
||||
$request,
|
||||
$icon,
|
||||
$content);
|
||||
|
||||
$apps_href = PhabricatorEnv::getURI('/applications/');
|
||||
$content = pht(
|
||||
"=== Explore Applications ===\n\n".
|
||||
"Phabricator is a large suite of applications that work together to ".
|
||||
"help you develop software, manage tasks, and communicate. A few of ".
|
||||
"the most commonly used applications are pinned to the left navigation ".
|
||||
"bar by default.\n\n".
|
||||
"To explore all of the Phabricator applications, adjust settings, or ".
|
||||
"uninstall applications you don't plan to use, visit the ".
|
||||
"**[[ %s | Applications Application ]]**. You can also click the ".
|
||||
"**Applications** button in the left navigation menu, or search for an ".
|
||||
"application by name in the main menu bar. ",
|
||||
$apps_href);
|
||||
|
||||
$explore = array();
|
||||
$explore[] = $this->newItem(
|
||||
$request,
|
||||
'fa-globe',
|
||||
$content);
|
||||
|
||||
// TODO: Restore some sort of "Support" link here, but just nuke it for
|
||||
// now as we figure stuff out.
|
||||
|
||||
$differential_uri = PhabricatorEnv::getURI('/differential/');
|
||||
$differential_create_uri = PhabricatorEnv::getURI(
|
||||
'/differential/diff/create/');
|
||||
$differential_all_uri = PhabricatorEnv::getURI('/differential/query/all/');
|
||||
|
||||
$differential_user_guide = PhabricatorEnv::getDoclink(
|
||||
'Differential User Guide');
|
||||
$differential_vs_uri = PhabricatorEnv::getDoclink(
|
||||
'User Guide: Review vs Audit');
|
||||
|
||||
$quick = array();
|
||||
$quick[] = $this->newItem(
|
||||
$request,
|
||||
'fa-gear',
|
||||
pht(
|
||||
"=== Quick Start: Code Review ===\n\n".
|
||||
"Review code with **[[ %s | Differential ]]**. ".
|
||||
"Engineers can use Differential to share, review, and approve ".
|
||||
"changes to source code. ".
|
||||
"To get started with code review:\n\n".
|
||||
" - **[[ %s | Create a Revision ]]** //(Copy and paste a diff from ".
|
||||
" the command line into the web UI to quickly get a feel for ".
|
||||
" review.)//\n".
|
||||
" - **[[ %s | View All Revisions ]]**\n\n".
|
||||
"For more information, see these articles in the documentation:\n\n".
|
||||
" - **[[ %s | Differential User Guide ]]**, for a general overview ".
|
||||
" of Differential.\n".
|
||||
" - **[[ %s | User Guide: Review vs Audit ]]**, for a discussion ".
|
||||
" of different code review workflows.",
|
||||
$differential_uri,
|
||||
$differential_create_uri,
|
||||
$differential_all_uri,
|
||||
$differential_user_guide,
|
||||
$differential_vs_uri));
|
||||
|
||||
|
||||
$maniphest_uri = PhabricatorEnv::getURI('/maniphest/');
|
||||
$maniphest_create_uri = PhabricatorEnv::getURI('/maniphest/task/edit/');
|
||||
$maniphest_all_uri = PhabricatorEnv::getURI('/maniphest/query/all/');
|
||||
$quick[] = $this->newItem(
|
||||
$request,
|
||||
'fa-anchor',
|
||||
pht(
|
||||
"=== Quick Start: Bugs and Tasks ===\n\n".
|
||||
"Track bugs and tasks in Phabricator with ".
|
||||
"**[[ %s | Maniphest ]]**. ".
|
||||
"Users in all roles can use Maniphest to manage current and ".
|
||||
"planned work and to track bugs and issues. ".
|
||||
"To get started with bugs and tasks:\n\n".
|
||||
" - **[[ %s | Create a Task ]]**\n".
|
||||
" - **[[ %s | View All Tasks ]]**\n",
|
||||
$maniphest_uri,
|
||||
$maniphest_create_uri,
|
||||
$maniphest_all_uri));
|
||||
|
||||
|
||||
$pholio_uri = PhabricatorEnv::getURI('/pholio/');
|
||||
$pholio_create_uri = PhabricatorEnv::getURI('/pholio/new/');
|
||||
$pholio_all_uri = PhabricatorEnv::getURI('/pholio/query/all/');
|
||||
|
||||
$quick[] = $this->newItem(
|
||||
$request,
|
||||
'fa-camera-retro',
|
||||
pht(
|
||||
"=== Quick Start: Design Review ===\n\n".
|
||||
"Review proposed designs with **[[ %s | Pholio ]]**. ".
|
||||
"Designers can use Pholio to share images of what they're working on ".
|
||||
"and show off things they've made. ".
|
||||
"To get started with design review:\n\n".
|
||||
" - **[[ %s | Create a Mock ]]**\n".
|
||||
" - **[[ %s | View All Mocks ]]**",
|
||||
$pholio_uri,
|
||||
$pholio_create_uri,
|
||||
$pholio_all_uri));
|
||||
|
||||
|
||||
$diffusion_uri = PhabricatorEnv::getURI('/diffusion/edit/');
|
||||
$diffusion_create_uri = PhabricatorEnv::getURI('/diffusion/create/');
|
||||
$diffusion_all_uri = PhabricatorEnv::getURI('/diffusion/query/all/');
|
||||
|
||||
$diffusion_user_guide = PhabricatorEnv::getDoclink('Diffusion User Guide');
|
||||
$diffusion_setup_guide = PhabricatorEnv::getDoclink(
|
||||
'Diffusion User Guide: Repository Hosting');
|
||||
|
||||
$quick[] = $this->newItem(
|
||||
$request,
|
||||
'fa-code',
|
||||
pht(
|
||||
"=== Quick Start: Repositories ===\n\n".
|
||||
"Manage and browse source code repositories with ".
|
||||
"**[[ %s | Diffusion ]]**. ".
|
||||
"Engineers can use Diffusion to browse and audit source code. ".
|
||||
"You can configure Phabricator to host repositories, or have it ".
|
||||
"track existing repositories hosted elsewhere (like GitHub, ".
|
||||
"Bitbucket, or an internal server). ".
|
||||
"To get started with repositories:\n\n".
|
||||
" - **[[ %s | Create a New Repository ]]**\n".
|
||||
" - **[[ %s | View All Repositories ]]**\n\n".
|
||||
"For more information, see these articles in the documentation:\n\n".
|
||||
" - **[[ %s | Diffusion User Guide ]]**, for a general overview of ".
|
||||
" Diffusion.\n".
|
||||
" - **[[ %s | Diffusion User Guide: Repository Hosting ]]**, ".
|
||||
" for instructions on configuring repository hosting.\n\n".
|
||||
"Phabricator supports Git, Mercurial and Subversion.",
|
||||
$diffusion_uri,
|
||||
$diffusion_create_uri,
|
||||
$diffusion_all_uri,
|
||||
$diffusion_user_guide,
|
||||
$diffusion_setup_guide));
|
||||
|
||||
$setup_header = new PHUIRemarkupView(
|
||||
$viewer, pht('=Setup and Configuration'));
|
||||
|
||||
$explore_header = new PHUIRemarkupView(
|
||||
$viewer, pht('=Explore Phabricator'));
|
||||
|
||||
$quick_header = new PHUIRemarkupView(
|
||||
$viewer, pht('=Quick Start Guide'));
|
||||
|
||||
$document = id(new PHUIDocumentViewPro())
|
||||
->setFluid(true)
|
||||
->appendChild($setup_header)
|
||||
->appendChild($setup)
|
||||
->appendChild($explore_header)
|
||||
->appendChild($explore)
|
||||
->appendChild($quick_header)
|
||||
->appendChild($quick);
|
||||
|
||||
return id(new PHUIBoxView())
|
||||
->appendChild($document);
|
||||
}
|
||||
|
||||
private function newItem(AphrontRequest $request, $icon, $content) {
|
||||
$viewer = $request->getUser();
|
||||
|
||||
$icon = id(new PHUIIconView())
|
||||
->setIcon($icon.' fa-2x');
|
||||
|
||||
$content = new PHUIRemarkupView($viewer, $content);
|
||||
|
||||
$icon = phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'config-welcome-icon',
|
||||
),
|
||||
$icon);
|
||||
|
||||
$content = phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'config-welcome-content',
|
||||
),
|
||||
$content);
|
||||
|
||||
$view = phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'config-welcome-box grouped',
|
||||
),
|
||||
array(
|
||||
$icon,
|
||||
$content,
|
||||
));
|
||||
|
||||
return $view;
|
||||
}
|
||||
|
||||
}
|
|
@ -25,11 +25,21 @@ final class PhabricatorConfigResponse extends AphrontStandaloneHTMLResponse {
|
|||
}
|
||||
|
||||
protected function getResponseBodyClass() {
|
||||
return 'setup-fatal';
|
||||
if (PhabricatorSetupCheck::isInFlight()) {
|
||||
return 'setup-fatal in-flight';
|
||||
} else {
|
||||
return 'setup-fatal';
|
||||
}
|
||||
}
|
||||
|
||||
protected function getResponseBody() {
|
||||
return $this->view->render();
|
||||
$view = $this->view;
|
||||
|
||||
if (PhabricatorSetupCheck::isInFlight()) {
|
||||
return $view->renderInFlight();
|
||||
} else {
|
||||
return $view->render();
|
||||
}
|
||||
}
|
||||
|
||||
protected function buildPlainTextResponseString() {
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorInFlightErrorView extends AphrontView {
|
||||
|
||||
private $message;
|
||||
|
||||
public function setMessage($message) {
|
||||
$this->message = $message;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getMessage() {
|
||||
return $this->message;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
return phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'in-flight-error-detail',
|
||||
),
|
||||
array(
|
||||
phutil_tag(
|
||||
'h1',
|
||||
array(
|
||||
'class' => 'in-flight-error-title',
|
||||
),
|
||||
pht('A Troublesome Encounter!')),
|
||||
phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'in-flight-error-body',
|
||||
),
|
||||
pht(
|
||||
'Woe! This request had its journey cut short by unexpected '.
|
||||
'circumstances (%s).',
|
||||
$this->getMessage())),
|
||||
));
|
||||
}
|
||||
|
||||
}
|
|
@ -13,6 +13,14 @@ final class PhabricatorSetupIssueView extends AphrontView {
|
|||
return $this->issue;
|
||||
}
|
||||
|
||||
public function renderInFlight() {
|
||||
$issue = $this->getIssue();
|
||||
|
||||
return id(new PhabricatorInFlightErrorView())
|
||||
->setMessage($issue->getName())
|
||||
->render();
|
||||
}
|
||||
|
||||
public function render() {
|
||||
$issue = $this->getIssue();
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ final class PhabricatorConpherenceApplication extends PhabricatorApplication {
|
|||
'search/(?:query/(?P<queryKey>[^/]+)/)?'
|
||||
=> 'ConpherenceRoomListController',
|
||||
'panel/' => 'ConpherenceNotificationPanelController',
|
||||
'widget/(?P<id>[1-9]\d*)/' => 'ConpherenceWidgetController',
|
||||
'participant/(?P<id>[1-9]\d*)/' => 'ConpherenceParticipantController',
|
||||
'update/(?P<id>[1-9]\d*)/' => 'ConpherenceUpdateController',
|
||||
),
|
||||
);
|
||||
|
|
|
@ -13,8 +13,9 @@ final class ConpherenceCreateThreadConduitAPIMethod
|
|||
|
||||
protected function defineParamTypes() {
|
||||
return array(
|
||||
'title' => 'optional string',
|
||||
'message' => 'required string',
|
||||
'title' => 'required string',
|
||||
'topic' => 'optional string',
|
||||
'message' => 'optional string',
|
||||
'participantPHIDs' => 'required list<phids>',
|
||||
);
|
||||
}
|
||||
|
@ -27,8 +28,8 @@ final class ConpherenceCreateThreadConduitAPIMethod
|
|||
return array(
|
||||
'ERR_EMPTY_PARTICIPANT_PHIDS' => pht(
|
||||
'You must specify participant phids.'),
|
||||
'ERR_EMPTY_MESSAGE' => pht(
|
||||
'You must specify a message.'),
|
||||
'ERR_EMPTY_TITLE' => pht(
|
||||
'You must specify a title.'),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -36,19 +37,21 @@ final class ConpherenceCreateThreadConduitAPIMethod
|
|||
$participant_phids = $request->getValue('participantPHIDs', array());
|
||||
$message = $request->getValue('message');
|
||||
$title = $request->getValue('title');
|
||||
$topic = $request->getValue('topic');
|
||||
|
||||
list($errors, $conpherence) = ConpherenceEditor::createThread(
|
||||
$request->getUser(),
|
||||
$participant_phids,
|
||||
$title,
|
||||
$message,
|
||||
$request->newContentSource());
|
||||
$request->newContentSource(),
|
||||
$topic);
|
||||
|
||||
if ($errors) {
|
||||
foreach ($errors as $error_code) {
|
||||
switch ($error_code) {
|
||||
case ConpherenceEditor::ERROR_EMPTY_MESSAGE:
|
||||
throw new ConduitException('ERR_EMPTY_MESSAGE');
|
||||
case ConpherenceEditor::ERROR_EMPTY_TITLE:
|
||||
throw new ConduitException('ERR_EMPTY_TITLE');
|
||||
break;
|
||||
case ConpherenceEditor::ERROR_EMPTY_PARTICIPANTS:
|
||||
throw new ConduitException('ERR_EMPTY_PARTICIPANT_PHIDS');
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class ConpherenceWidgetConfigConstants extends ConpherenceConstants {
|
||||
|
||||
const UPDATE_URI = '/conpherence/update/';
|
||||
|
||||
public static function getWidgetPaneBehaviorConfig() {
|
||||
return array(
|
||||
'widgetBaseUpdateURI' => self::UPDATE_URI,
|
||||
'widgetRegistry' => self::getWidgetRegistry(),
|
||||
);
|
||||
}
|
||||
|
||||
public static function getWidgetRegistry() {
|
||||
return array(
|
||||
'conpherence-message-pane' => array(
|
||||
'name' => pht('Thread'),
|
||||
'icon' => 'fa-comment',
|
||||
'deviceOnly' => true,
|
||||
'hasCreate' => false,
|
||||
),
|
||||
'widgets-people' => array(
|
||||
'name' => pht('Participants'),
|
||||
'icon' => 'fa-users',
|
||||
'deviceOnly' => false,
|
||||
'hasCreate' => true,
|
||||
'createData' => array(
|
||||
'refreshFromResponse' => true,
|
||||
'action' => ConpherenceUpdateActions::ADD_PERSON,
|
||||
'customHref' => null,
|
||||
),
|
||||
),
|
||||
'widgets-settings' => array(
|
||||
'name' => pht('Notifications'),
|
||||
'icon' => 'fa-wrench',
|
||||
'deviceOnly' => false,
|
||||
'hasCreate' => false,
|
||||
),
|
||||
'widgets-edit' => array(
|
||||
'name' => pht('Edit Room'),
|
||||
'icon' => 'fa-pencil',
|
||||
'deviceOnly' => false,
|
||||
'hasCreate' => false,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -14,80 +14,96 @@ abstract class ConpherenceController extends PhabricatorController {
|
|||
|
||||
public function buildApplicationMenu() {
|
||||
$nav = new PHUIListView();
|
||||
$conpherence = $this->conpherence;
|
||||
|
||||
// Local Links
|
||||
if ($conpherence) {
|
||||
$nav->addMenuItem(
|
||||
id(new PHUIListItemView())
|
||||
->setName(pht('Edit Room'))
|
||||
->setType(PHUIListItemView::TYPE_LINK)
|
||||
->setHref(
|
||||
$this->getApplicationURI('update/'.$conpherence->getID()).'/')
|
||||
->setWorkflow(true));
|
||||
|
||||
$nav->addMenuItem(
|
||||
id(new PHUIListItemView())
|
||||
->setName(pht('Add Participants'))
|
||||
->setType(PHUIListItemView::TYPE_LINK)
|
||||
->setHref('#')
|
||||
->addSigil('conpherence-widget-adder')
|
||||
->setMetadata(array('widget' => 'widgets-people')));
|
||||
}
|
||||
|
||||
// Global Links
|
||||
$nav->newLabel(pht('Conpherence'));
|
||||
$nav->newLink(
|
||||
pht('New Room'),
|
||||
$this->getApplicationURI('new/'));
|
||||
|
||||
$nav->addMenuItem(
|
||||
id(new PHUIListItemView())
|
||||
->setName(pht('Add Participants'))
|
||||
->setType(PHUIListItemView::TYPE_LINK)
|
||||
->setHref('#')
|
||||
->addSigil('conpherence-widget-adder')
|
||||
->setMetadata(array('widget' => 'widgets-people')));
|
||||
$nav->newLink(
|
||||
pht('Search Rooms'),
|
||||
$this->getApplicationURI('search/'));
|
||||
|
||||
return $nav;
|
||||
}
|
||||
|
||||
protected function buildApplicationCrumbs() {
|
||||
return $this->buildConpherenceApplicationCrumbs();
|
||||
}
|
||||
|
||||
protected function buildConpherenceApplicationCrumbs($is_rooms = false) {
|
||||
$crumbs = parent::buildApplicationCrumbs();
|
||||
|
||||
if ($is_rooms) {
|
||||
$crumbs
|
||||
->addAction(
|
||||
id(new PHUIListItemView())
|
||||
->setName(pht('New Room'))
|
||||
->setHref($this->getApplicationURI('new/'))
|
||||
->setIcon('fa-plus-square')
|
||||
->setWorkflow(true));
|
||||
} else {
|
||||
$crumbs
|
||||
->addAction(
|
||||
id(new PHUIListItemView())
|
||||
->setName(pht('New Room'))
|
||||
->setHref($this->getApplicationURI('new/'))
|
||||
->setIcon('fa-plus-square')
|
||||
->setWorkflow(true))
|
||||
->addAction(
|
||||
id(new PHUIListItemView())
|
||||
->setName(pht('Room'))
|
||||
->setHref('#')
|
||||
->setIcon('fa-bars')
|
||||
->setStyle('display: none;')
|
||||
->addClass('device-widgets-selector')
|
||||
->addSigil('device-widgets-selector'));
|
||||
}
|
||||
return $crumbs;
|
||||
}
|
||||
|
||||
protected function buildHeaderPaneContent(
|
||||
ConpherenceThread $conpherence,
|
||||
array $policy_objects) {
|
||||
assert_instances_of($policy_objects, 'PhabricatorPolicy');
|
||||
$viewer = $this->getViewer();
|
||||
$header = null;
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$data = $conpherence->getDisplayData($this->getViewer());
|
||||
$crumbs->addCrumb(
|
||||
id(new PHUICrumbView())
|
||||
->setName($data['title'])
|
||||
->setHref('/'.$conpherence->getMonogram()));
|
||||
if ($conpherence->getID()) {
|
||||
$data = $conpherence->getDisplayData($this->getViewer());
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader($data['title'])
|
||||
->setSubheader($data['topic'])
|
||||
->addClass((!$data['topic']) ? 'conpherence-no-topic' : null);
|
||||
|
||||
return hsprintf(
|
||||
'%s',
|
||||
array(
|
||||
phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'header-loading-mask',
|
||||
),
|
||||
''),
|
||||
$crumbs,
|
||||
));
|
||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||
$viewer,
|
||||
$conpherence,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
|
||||
$header->addActionItem(
|
||||
id(new PHUIIconCircleView())
|
||||
->setHref(
|
||||
$this->getApplicationURI('update/'.$conpherence->getID()).'/')
|
||||
->setIcon('fa-pencil')
|
||||
->addClass('hide-on-device')
|
||||
->setColor('violet')
|
||||
->setWorkflow(true));
|
||||
|
||||
$header->addActionItem(
|
||||
id(new PHUIIconCircleView())
|
||||
->setHref(
|
||||
$this->getApplicationURI('update/'.$conpherence->getID()).'/'.
|
||||
'?action='.ConpherenceUpdateActions::NOTIFICATIONS)
|
||||
->setIcon('fa-gear')
|
||||
->addClass('hide-on-device')
|
||||
->setColor('pink')
|
||||
->setWorkflow(true));
|
||||
|
||||
$widget_key = PhabricatorConpherenceWidgetVisibleSetting::SETTINGKEY;
|
||||
$widget_view = (bool)$viewer->getUserSetting($widget_key, false);
|
||||
|
||||
Javelin::initBehavior(
|
||||
'toggle-widget',
|
||||
array(
|
||||
'show' => (int)$widget_view,
|
||||
'settingsURI' => '/settings/adjust/?key='.$widget_key,
|
||||
));
|
||||
|
||||
$header->addActionItem(
|
||||
id(new PHUIIconCircleView())
|
||||
->addSigil('conpherence-widget-toggle')
|
||||
->setIcon('fa-group')
|
||||
->setHref('#')
|
||||
->addClass('conpherence-participant-toggle'));
|
||||
}
|
||||
|
||||
return $header;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,16 +16,19 @@ final class ConpherenceNewRoomController extends ConpherenceController {
|
|||
$editor = new ConpherenceEditor();
|
||||
$xactions = array();
|
||||
|
||||
$xactions[] = id(new ConpherenceTransaction())
|
||||
->setTransactionType(ConpherenceTransaction::TYPE_TITLE)
|
||||
->setNewValue($request->getStr('title'));
|
||||
|
||||
$participants = $request->getArr('participants');
|
||||
$participants[] = $user->getPHID();
|
||||
$participants = array_unique($participants);
|
||||
$xactions[] = id(new ConpherenceTransaction())
|
||||
->setTransactionType(ConpherenceTransaction::TYPE_PARTICIPANTS)
|
||||
->setNewValue(array('+' => $participants));
|
||||
|
||||
$xactions[] = id(new ConpherenceTransaction())
|
||||
->setTransactionType(ConpherenceTransaction::TYPE_TITLE)
|
||||
->setNewValue($request->getStr('title'));
|
||||
->setTransactionType(ConpherenceTransaction::TYPE_TOPIC)
|
||||
->setNewValue($request->getStr('topic'));
|
||||
$xactions[] = id(new ConpherenceTransaction())
|
||||
->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY)
|
||||
->setNewValue($request->getStr('viewPolicy'));
|
||||
|
@ -93,6 +96,11 @@ final class ConpherenceNewRoomController extends ConpherenceController {
|
|||
->setLabel(pht('Name'))
|
||||
->setName('title')
|
||||
->setValue($request->getStr('title')))
|
||||
->appendChild(
|
||||
id(new AphrontFormTextControl())
|
||||
->setLabel(pht('Topic'))
|
||||
->setName('topic')
|
||||
->setValue($request->getStr('topic')))
|
||||
->appendChild(
|
||||
id(new AphrontFormTokenizerControl())
|
||||
->setName('participants')
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
final class ConpherenceParticipantController extends ConpherenceController {
|
||||
|
||||
public function shouldAllowPublic() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $request->getViewer();
|
||||
|
||||
$conpherence_id = $request->getURIData('id');
|
||||
if (!$conpherence_id) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$conpherence = id(new ConpherenceThreadQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($conpherence_id))
|
||||
->needParticipants(true)
|
||||
->executeOne();
|
||||
|
||||
if (!$conpherence) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$uri = $this->getApplicationURI('update/'.$conpherence->getID().'/');
|
||||
$content = id(new ConpherenceParticipantView())
|
||||
->setUser($this->getViewer())
|
||||
->setConpherence($conpherence)
|
||||
->setUpdateURI($uri);
|
||||
|
||||
$content = array('widgets' => $content);
|
||||
|
||||
return id(new AphrontAjaxResponse())->setContent($content);
|
||||
}
|
||||
|
||||
}
|
|
@ -18,10 +18,6 @@ final class ConpherenceRoomListController extends ConpherenceController {
|
|||
return $this->delegateToController($controller);
|
||||
}
|
||||
|
||||
protected function buildApplicationCrumbs() {
|
||||
return $this->buildConpherenceApplicationCrumbs($is_rooms = true);
|
||||
}
|
||||
|
||||
public function buildApplicationMenu() {
|
||||
return $this->buildRoomsSideNavView(true)->getMenu();
|
||||
}
|
||||
|
|
|
@ -107,7 +107,7 @@ final class ConpherenceUpdateController
|
|||
break;
|
||||
case ConpherenceUpdateActions::REMOVE_PERSON:
|
||||
if (!$request->isContinueRequest()) {
|
||||
// do nothing; we'll display a confirmation dialogue instead
|
||||
// do nothing; we'll display a confirmation dialog instead
|
||||
break;
|
||||
}
|
||||
$person_phid = $request->getStr('remove_person');
|
||||
|
@ -127,22 +127,16 @@ final class ConpherenceUpdateController
|
|||
}
|
||||
$participant->setSettings(array('notifications' => $notifications));
|
||||
$participant->save();
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI('/'.$conpherence->getMonogram());
|
||||
|
||||
$label = PhabricatorConpherenceNotificationsSetting::getSettingLabel(
|
||||
$notifications);
|
||||
|
||||
$result = pht(
|
||||
'Updated notification settings to "%s".',
|
||||
$label);
|
||||
|
||||
return id(new AphrontAjaxResponse())
|
||||
->setContent($result);
|
||||
break;
|
||||
case ConpherenceUpdateActions::METADATA:
|
||||
$top = $request->getInt('image_y');
|
||||
$left = $request->getInt('image_x');
|
||||
$file_id = $request->getInt('file_id');
|
||||
$title = $request->getStr('title');
|
||||
$topic = $request->getStr('topic');
|
||||
if ($file_id) {
|
||||
$orig_file = id(new PhabricatorFileQuery())
|
||||
->setViewer($user)
|
||||
|
@ -190,9 +184,13 @@ final class ConpherenceUpdateController
|
|||
->setNewValue($image_phid);
|
||||
}
|
||||
$title = $request->getStr('title');
|
||||
$topic = $request->getStr('topic');
|
||||
$xactions[] = id(new ConpherenceTransaction())
|
||||
->setTransactionType(ConpherenceTransaction::TYPE_TITLE)
|
||||
->setNewValue($title);
|
||||
$xactions[] = id(new ConpherenceTransaction())
|
||||
->setTransactionType(ConpherenceTransaction::TYPE_TOPIC)
|
||||
->setNewValue($topic);
|
||||
$xactions[] = id(new ConpherenceTransaction())
|
||||
->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY)
|
||||
->setNewValue($request->getStr('viewPolicy'));
|
||||
|
@ -269,29 +267,97 @@ final class ConpherenceUpdateController
|
|||
}
|
||||
|
||||
switch ($action) {
|
||||
case ConpherenceUpdateActions::NOTIFICATIONS:
|
||||
$dialog = $this->renderPreferencesDialog($conpherence);
|
||||
break;
|
||||
case ConpherenceUpdateActions::ADD_PERSON:
|
||||
$dialogue = $this->renderAddPersonDialogue($conpherence);
|
||||
$dialog = $this->renderAddPersonDialog($conpherence);
|
||||
break;
|
||||
case ConpherenceUpdateActions::REMOVE_PERSON:
|
||||
$dialogue = $this->renderRemovePersonDialogue($conpherence);
|
||||
$dialog = $this->renderRemovePersonDialog($conpherence);
|
||||
break;
|
||||
case ConpherenceUpdateActions::METADATA:
|
||||
default:
|
||||
$dialogue = $this->renderMetadataDialogue($conpherence, $error_view);
|
||||
$dialog = $this->renderMetadataDialog($conpherence, $error_view);
|
||||
break;
|
||||
}
|
||||
|
||||
return id(new AphrontDialogResponse())
|
||||
->setDialog($dialogue
|
||||
return
|
||||
$dialog
|
||||
->setUser($user)
|
||||
->setWidth(AphrontDialogView::WIDTH_FORM)
|
||||
->setSubmitURI($this->getApplicationURI('update/'.$conpherence_id.'/'))
|
||||
->addSubmitButton()
|
||||
->addCancelButton($this->getApplicationURI($conpherence->getID().'/')));
|
||||
->addCancelButton($this->getApplicationURI($conpherence->getID().'/'));
|
||||
|
||||
}
|
||||
|
||||
private function renderAddPersonDialogue(
|
||||
private function renderPreferencesDialog(
|
||||
ConpherenceThread $conpherence) {
|
||||
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
|
||||
$participant = $conpherence->getParticipantIfExists($user->getPHID());
|
||||
if (!$participant) {
|
||||
$can_join = PhabricatorPolicyFilter::hasCapability(
|
||||
$user,
|
||||
$conpherence,
|
||||
PhabricatorPolicyCapability::CAN_JOIN);
|
||||
if ($can_join) {
|
||||
$text = pht(
|
||||
'Notification settings are available after joining the room.');
|
||||
} else if ($user->isLoggedIn()) {
|
||||
$text = pht(
|
||||
'Notification settings not applicable to rooms you can not join.');
|
||||
} else {
|
||||
$text = pht(
|
||||
'Notification settings are available after logging in and joining '.
|
||||
'the room.');
|
||||
}
|
||||
return id(new AphrontDialogView())
|
||||
->setTitle(pht('Room Preferences'))
|
||||
->appendParagraph($text);
|
||||
}
|
||||
|
||||
$notification_key = PhabricatorConpherenceNotificationsSetting::SETTINGKEY;
|
||||
$notification_default = $user->getUserSetting($notification_key);
|
||||
|
||||
$settings = $participant->getSettings();
|
||||
$notifications = idx(
|
||||
$settings,
|
||||
'notifications',
|
||||
$notification_default);
|
||||
|
||||
$form = id(new AphrontFormView())
|
||||
->setUser($user)
|
||||
->setFullWidth(true)
|
||||
->appendControl(
|
||||
id(new AphrontFormRadioButtonControl())
|
||||
->addButton(
|
||||
PhabricatorConpherenceNotificationsSetting::VALUE_CONPHERENCE_EMAIL,
|
||||
PhabricatorConpherenceNotificationsSetting::getSettingLabel(
|
||||
PhabricatorConpherenceNotificationsSetting::VALUE_CONPHERENCE_EMAIL),
|
||||
'')
|
||||
->addButton(
|
||||
PhabricatorConpherenceNotificationsSetting::VALUE_CONPHERENCE_NOTIFY,
|
||||
PhabricatorConpherenceNotificationsSetting::getSettingLabel(
|
||||
PhabricatorConpherenceNotificationsSetting::VALUE_CONPHERENCE_NOTIFY),
|
||||
'')
|
||||
->setName('notifications')
|
||||
->setValue($notifications));
|
||||
|
||||
return id(new AphrontDialogView())
|
||||
->setTitle(pht('Room Preferences'))
|
||||
->addHiddenInput('action', 'notifications')
|
||||
->addHiddenInput(
|
||||
'latest_transaction_id',
|
||||
$request->getInt('latest_transaction_id'))
|
||||
->appendForm($form);
|
||||
|
||||
}
|
||||
|
||||
private function renderAddPersonDialog(
|
||||
ConpherenceThread $conpherence) {
|
||||
|
||||
$request = $this->getRequest();
|
||||
|
@ -322,7 +388,7 @@ final class ConpherenceUpdateController
|
|||
return $view;
|
||||
}
|
||||
|
||||
private function renderRemovePersonDialogue(
|
||||
private function renderRemovePersonDialog(
|
||||
ConpherenceThread $conpherence) {
|
||||
|
||||
$request = $this->getRequest();
|
||||
|
@ -405,7 +471,7 @@ final class ConpherenceUpdateController
|
|||
return $dialog;
|
||||
}
|
||||
|
||||
private function renderMetadataDialogue(
|
||||
private function renderMetadataDialog(
|
||||
ConpherenceThread $conpherence,
|
||||
$error_view) {
|
||||
|
||||
|
@ -419,7 +485,12 @@ final class ConpherenceUpdateController
|
|||
id(new AphrontFormTextControl())
|
||||
->setLabel(pht('Title'))
|
||||
->setName('title')
|
||||
->setValue($conpherence->getTitle()));
|
||||
->setValue($conpherence->getTitle()))
|
||||
->appendChild(
|
||||
id(new AphrontFormTextControl())
|
||||
->setLabel(pht('Topic'))
|
||||
->setName('topic')
|
||||
->setValue($conpherence->getTopic()));
|
||||
|
||||
$nopic = $this->getRequest()->getExists('nopic');
|
||||
$image = $conpherence->getImage(ConpherenceImageData::SIZE_ORIG);
|
||||
|
@ -526,7 +597,7 @@ final class ConpherenceUpdateController
|
|||
->setAfterTransactionID($latest_transaction_id)
|
||||
->needCropPics(true)
|
||||
->needParticipantCache($need_participant_cache)
|
||||
->needWidgetData($need_widget_data)
|
||||
->needParticipants(true)
|
||||
->needTransactions($need_transactions)
|
||||
->withIDs(array($conpherence_id))
|
||||
->executeOne();
|
||||
|
@ -548,11 +619,10 @@ final class ConpherenceUpdateController
|
|||
$rendered_transactions = idx($data, 'transactions');
|
||||
$new_latest_transaction_id = idx($data, 'latest_transaction_id');
|
||||
|
||||
$widget_uri = $this->getApplicationURI('update/'.$conpherence->getID().'/');
|
||||
$update_uri = $this->getApplicationURI('update/'.$conpherence->getID().'/');
|
||||
$nav_item = null;
|
||||
$header = null;
|
||||
$people_widget = null;
|
||||
$file_widget = null;
|
||||
if (!$minimal_display) {
|
||||
switch ($action) {
|
||||
case ConpherenceUpdateActions::METADATA:
|
||||
|
@ -571,10 +641,10 @@ final class ConpherenceUpdateController
|
|||
$nav_item = hsprintf('%s', $nav_item);
|
||||
break;
|
||||
case ConpherenceUpdateActions::ADD_PERSON:
|
||||
$people_widget = id(new ConpherencePeopleWidgetView())
|
||||
$people_widget = id(new ConpherenceParticipantView())
|
||||
->setUser($user)
|
||||
->setConpherence($conpherence)
|
||||
->setUpdateURI($widget_uri);
|
||||
->setUpdateURI($update_uri);
|
||||
$people_widget = hsprintf('%s', $people_widget->render());
|
||||
break;
|
||||
case ConpherenceUpdateActions::REMOVE_PERSON:
|
||||
|
@ -595,7 +665,6 @@ final class ConpherenceUpdateController
|
|||
'nav_item' => $nav_item,
|
||||
'conpherence_phid' => $conpherence->getPHID(),
|
||||
'header' => $header,
|
||||
'file_widget' => $file_widget,
|
||||
'people_widget' => $people_widget,
|
||||
'aphlictDropdownData' => array(
|
||||
$dropdown_query->getNotificationData(),
|
||||
|
|
|
@ -9,12 +9,6 @@ final class ConpherenceViewController extends
|
|||
return true;
|
||||
}
|
||||
|
||||
protected function buildApplicationCrumbs() {
|
||||
$crumbs = $this->buildConpherenceApplicationCrumbs();
|
||||
$crumbs->setBorder(true);
|
||||
return $crumbs;
|
||||
}
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$user = $request->getUser();
|
||||
|
||||
|
@ -160,7 +154,7 @@ final class ConpherenceViewController extends
|
|||
$button_text = pht('Send');
|
||||
} else if ($user->isLoggedIn()) {
|
||||
$action = ConpherenceUpdateActions::JOIN_ROOM;
|
||||
$button_text = pht('Join');
|
||||
$button_text = pht('Join Room');
|
||||
} else {
|
||||
// user not logged in so give them a login button.
|
||||
$login_href = id(new PhutilURI('/auth/start/'))
|
||||
|
|
|
@ -1,188 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class ConpherenceWidgetController extends ConpherenceController {
|
||||
|
||||
public function shouldAllowPublic() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
|
||||
$conpherence_id = $request->getURIData('id');
|
||||
if (!$conpherence_id) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
$conpherence = id(new ConpherenceThreadQuery())
|
||||
->setViewer($user)
|
||||
->withIDs(array($conpherence_id))
|
||||
->needWidgetData(true)
|
||||
->executeOne();
|
||||
if (!$conpherence) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
$this->setConpherence($conpherence);
|
||||
|
||||
switch ($request->getStr('widget')) {
|
||||
case 'widgets-people':
|
||||
$content = $this->renderPeopleWidgetPaneContent();
|
||||
break;
|
||||
case 'widgets-settings':
|
||||
$content = $this->renderSettingsWidgetPaneContent();
|
||||
break;
|
||||
default:
|
||||
$widgets = $this->renderWidgetPaneContent();
|
||||
$content = $widgets;
|
||||
break;
|
||||
}
|
||||
return id(new AphrontAjaxResponse())->setContent($content);
|
||||
}
|
||||
|
||||
private function renderWidgetPaneContent() {
|
||||
$conpherence = $this->getConpherence();
|
||||
|
||||
$widgets = array();
|
||||
$new_icon = id(new PHUIIconView())
|
||||
->setIcon('fa-plus')
|
||||
->setHref($this->getWidgetURI())
|
||||
->setMetadata(array('widget' => null))
|
||||
->addSigil('conpherence-widget-adder');
|
||||
$header = javelin_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => '#',
|
||||
'sigil' => 'widgets-selector',
|
||||
),
|
||||
pht('Participants'));
|
||||
|
||||
$widgets[] = phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'widgets-header',
|
||||
),
|
||||
id(new PHUIHeaderView())
|
||||
->setHeader($header)
|
||||
->addActionItem($new_icon));
|
||||
$user = $this->getRequest()->getUser();
|
||||
// now the widget bodies
|
||||
$widgets[] = javelin_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'widgets-body',
|
||||
'id' => 'widgets-people',
|
||||
'sigil' => 'widgets-people',
|
||||
),
|
||||
$this->renderPeopleWidgetPaneContent());
|
||||
$widgets[] = phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'widgets-body',
|
||||
'id' => 'widgets-settings',
|
||||
'style' => 'display: none',
|
||||
),
|
||||
$this->renderSettingsWidgetPaneContent());
|
||||
$widgets[] = phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'widgets-body',
|
||||
'id' => 'widgets-edit',
|
||||
'style' => 'display: none',
|
||||
));
|
||||
|
||||
// without this implosion we get "," between each element in our widgets
|
||||
// array
|
||||
return array('widgets' => phutil_implode_html('', $widgets));
|
||||
}
|
||||
|
||||
private function renderPeopleWidgetPaneContent() {
|
||||
return id(new ConpherencePeopleWidgetView())
|
||||
->setUser($this->getViewer())
|
||||
->setConpherence($this->getConpherence())
|
||||
->setUpdateURI($this->getWidgetURI());
|
||||
}
|
||||
|
||||
|
||||
private function renderSettingsWidgetPaneContent() {
|
||||
$viewer = $this->getViewer();
|
||||
$conpherence = $this->getConpherence();
|
||||
$participant = $conpherence->getParticipantIfExists($viewer->getPHID());
|
||||
if (!$participant) {
|
||||
$can_join = PhabricatorPolicyFilter::hasCapability(
|
||||
$viewer,
|
||||
$conpherence,
|
||||
PhabricatorPolicyCapability::CAN_JOIN);
|
||||
if ($can_join) {
|
||||
$text = pht(
|
||||
'Notification settings are available after joining the room.');
|
||||
} else if ($viewer->isLoggedIn()) {
|
||||
$text = pht(
|
||||
'Notification settings not applicable to rooms you can not join.');
|
||||
} else {
|
||||
$text = pht(
|
||||
'Notification settings are available after logging in and joining '.
|
||||
'the room.');
|
||||
}
|
||||
return phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'no-settings',
|
||||
),
|
||||
$text);
|
||||
}
|
||||
$notification_key = PhabricatorConpherenceNotificationsSetting::SETTINGKEY;
|
||||
$notification_default = $viewer->getUserSetting($notification_key);
|
||||
|
||||
$settings = $participant->getSettings();
|
||||
$notifications = idx(
|
||||
$settings,
|
||||
'notifications',
|
||||
$notification_default);
|
||||
$options = id(new AphrontFormRadioButtonControl())
|
||||
->addButton(
|
||||
PhabricatorConpherenceNotificationsSetting::VALUE_CONPHERENCE_EMAIL,
|
||||
PhabricatorConpherenceNotificationsSetting::getSettingLabel(
|
||||
PhabricatorConpherenceNotificationsSetting::VALUE_CONPHERENCE_EMAIL),
|
||||
'')
|
||||
->addButton(
|
||||
PhabricatorConpherenceNotificationsSetting::VALUE_CONPHERENCE_NOTIFY,
|
||||
PhabricatorConpherenceNotificationsSetting::getSettingLabel(
|
||||
PhabricatorConpherenceNotificationsSetting::VALUE_CONPHERENCE_NOTIFY),
|
||||
'')
|
||||
->setName('notifications')
|
||||
->setValue($notifications);
|
||||
|
||||
$layout = array(
|
||||
$options,
|
||||
phutil_tag(
|
||||
'input',
|
||||
array(
|
||||
'type' => 'hidden',
|
||||
'name' => 'action',
|
||||
'value' => 'notifications',
|
||||
)),
|
||||
phutil_tag(
|
||||
'button',
|
||||
array(
|
||||
'type' => 'submit',
|
||||
'class' => 'notifications-update',
|
||||
),
|
||||
pht('Save')),
|
||||
);
|
||||
|
||||
return phabricator_form(
|
||||
$viewer,
|
||||
array(
|
||||
'method' => 'POST',
|
||||
'action' => $this->getWidgetURI(),
|
||||
'sigil' => 'notifications-update',
|
||||
),
|
||||
$layout);
|
||||
}
|
||||
|
||||
private function getWidgetURI() {
|
||||
$conpherence = $this->getConpherence();
|
||||
return $this->getApplicationURI('update/'.$conpherence->getID().'/');
|
||||
}
|
||||
|
||||
}
|
|
@ -18,7 +18,8 @@ final class ConpherenceEditor extends PhabricatorApplicationTransactionEditor {
|
|||
array $participant_phids,
|
||||
$title,
|
||||
$message,
|
||||
PhabricatorContentSource $source) {
|
||||
PhabricatorContentSource $source,
|
||||
$topic) {
|
||||
|
||||
$conpherence = ConpherenceThread::initializeNewRoom($creator);
|
||||
$files = array();
|
||||
|
@ -59,6 +60,11 @@ final class ConpherenceEditor extends PhabricatorApplicationTransactionEditor {
|
|||
->setTransactionType(ConpherenceTransaction::TYPE_TITLE)
|
||||
->setNewValue($title);
|
||||
}
|
||||
if (strlen($topic)) {
|
||||
$xactions[] = id(new ConpherenceTransaction())
|
||||
->setTransactionType(ConpherenceTransaction::TYPE_TOPIC)
|
||||
->setNewValue($topic);
|
||||
}
|
||||
|
||||
$xactions[] = id(new ConpherenceTransaction())
|
||||
->setTransactionType(PhabricatorTransactions::TYPE_COMMENT)
|
||||
|
@ -118,6 +124,7 @@ final class ConpherenceEditor extends PhabricatorApplicationTransactionEditor {
|
|||
$types[] = PhabricatorTransactions::TYPE_COMMENT;
|
||||
|
||||
$types[] = ConpherenceTransaction::TYPE_TITLE;
|
||||
$types[] = ConpherenceTransaction::TYPE_TOPIC;
|
||||
$types[] = ConpherenceTransaction::TYPE_PARTICIPANTS;
|
||||
$types[] = ConpherenceTransaction::TYPE_FILES;
|
||||
$types[] = ConpherenceTransaction::TYPE_PICTURE;
|
||||
|
@ -136,6 +143,8 @@ final class ConpherenceEditor extends PhabricatorApplicationTransactionEditor {
|
|||
switch ($xaction->getTransactionType()) {
|
||||
case ConpherenceTransaction::TYPE_TITLE:
|
||||
return $object->getTitle();
|
||||
case ConpherenceTransaction::TYPE_TOPIC:
|
||||
return $object->getTopic();
|
||||
case ConpherenceTransaction::TYPE_PICTURE:
|
||||
return $object->getImagePHID(ConpherenceImageData::SIZE_ORIG);
|
||||
case ConpherenceTransaction::TYPE_PICTURE_CROP:
|
||||
|
@ -156,6 +165,7 @@ final class ConpherenceEditor extends PhabricatorApplicationTransactionEditor {
|
|||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case ConpherenceTransaction::TYPE_TITLE:
|
||||
case ConpherenceTransaction::TYPE_TOPIC:
|
||||
case ConpherenceTransaction::TYPE_PICTURE_CROP:
|
||||
return $xaction->getNewValue();
|
||||
case ConpherenceTransaction::TYPE_PICTURE:
|
||||
|
@ -250,6 +260,9 @@ final class ConpherenceEditor extends PhabricatorApplicationTransactionEditor {
|
|||
case ConpherenceTransaction::TYPE_TITLE:
|
||||
$object->setTitle($xaction->getNewValue());
|
||||
break;
|
||||
case ConpherenceTransaction::TYPE_TOPIC:
|
||||
$object->setTopic($xaction->getNewValue());
|
||||
break;
|
||||
case ConpherenceTransaction::TYPE_PICTURE:
|
||||
$object->setImagePHID(
|
||||
$xaction->getNewValue(),
|
||||
|
@ -484,6 +497,7 @@ final class ConpherenceEditor extends PhabricatorApplicationTransactionEditor {
|
|||
PhabricatorPolicyCapability::CAN_VIEW);
|
||||
break;
|
||||
case ConpherenceTransaction::TYPE_TITLE:
|
||||
case ConpherenceTransaction::TYPE_TOPIC:
|
||||
PhabricatorPolicyFilter::requireCapability(
|
||||
$this->requireActor(),
|
||||
$object,
|
||||
|
@ -609,6 +623,17 @@ final class ConpherenceEditor extends PhabricatorApplicationTransactionEditor {
|
|||
protected function shouldPublishFeedStory(
|
||||
PhabricatorLiskDAO $object,
|
||||
array $xactions) {
|
||||
|
||||
foreach ($xactions as $xaction) {
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case ConpherenceTransaction::TYPE_TITLE:
|
||||
case ConpherenceTransaction::TYPE_TOPIC:
|
||||
case ConpherenceTransaction::TYPE_PICTURE:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@ final class ConpherenceThreadQuery
|
|||
private $ids;
|
||||
private $participantPHIDs;
|
||||
private $needParticipants;
|
||||
private $needWidgetData;
|
||||
private $needCropPics;
|
||||
private $needOrigPics;
|
||||
private $needTransactions;
|
||||
|
@ -35,11 +34,6 @@ final class ConpherenceThreadQuery
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function needWidgetData($need_widget_data) {
|
||||
$this->needWidgetData = $need_widget_data;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function needCropPics($need) {
|
||||
$this->needCropPics = $need;
|
||||
return $this;
|
||||
|
@ -116,18 +110,15 @@ final class ConpherenceThreadQuery
|
|||
if ($this->needParticipantCache) {
|
||||
$this->loadCoreHandles($conpherences, 'getRecentParticipantPHIDs');
|
||||
}
|
||||
if ($this->needWidgetData || $this->needParticipants) {
|
||||
if ($this->needParticipants) {
|
||||
$this->loadCoreHandles($conpherences, 'getParticipantPHIDs');
|
||||
}
|
||||
if ($this->needTransactions) {
|
||||
$this->loadTransactionsAndHandles($conpherences);
|
||||
}
|
||||
if ($this->needFilePHIDs || $this->needWidgetData) {
|
||||
if ($this->needFilePHIDs) {
|
||||
$this->loadFilePHIDs($conpherences);
|
||||
}
|
||||
if ($this->needWidgetData) {
|
||||
$this->loadWidgetData($conpherences);
|
||||
}
|
||||
if ($this->needOrigPics || $this->needCropPics) {
|
||||
$this->initImages($conpherences);
|
||||
}
|
||||
|
@ -297,101 +288,6 @@ final class ConpherenceThreadQuery
|
|||
return $this;
|
||||
}
|
||||
|
||||
private function loadWidgetData(array $conpherences) {
|
||||
$participant_phids = array();
|
||||
$file_phids = array();
|
||||
foreach ($conpherences as $conpherence) {
|
||||
$participant_phids[] = array_keys($conpherence->getParticipants());
|
||||
$file_phids[] = $conpherence->getFilePHIDs();
|
||||
}
|
||||
$participant_phids = array_mergev($participant_phids);
|
||||
$file_phids = array_mergev($file_phids);
|
||||
|
||||
$epochs = CalendarTimeUtil::getCalendarEventEpochs(
|
||||
$this->getViewer());
|
||||
$start_epoch = $epochs['start_epoch'];
|
||||
$end_epoch = $epochs['end_epoch'];
|
||||
|
||||
$events = array();
|
||||
if ($participant_phids) {
|
||||
// TODO: All of this Calendar code is probably extra-broken, but none
|
||||
// of it is currently reachable in the UI.
|
||||
$events = id(new PhabricatorCalendarEventQuery())
|
||||
->setViewer($this->getViewer())
|
||||
->withInvitedPHIDs($participant_phids)
|
||||
->withIsCancelled(false)
|
||||
->withDateRange($start_epoch, $end_epoch)
|
||||
->execute();
|
||||
$events = mpull($events, null, 'getPHID');
|
||||
}
|
||||
|
||||
$invitees = array();
|
||||
foreach ($events as $event_phid => $event) {
|
||||
foreach ($event->getInvitees() as $invitee) {
|
||||
$invitees[$invitee->getInviteePHID()][$event_phid] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// attached files
|
||||
$files = array();
|
||||
$file_author_phids = array();
|
||||
$authors = array();
|
||||
if ($file_phids) {
|
||||
$files = id(new PhabricatorFileQuery())
|
||||
->setViewer($this->getViewer())
|
||||
->withPHIDs($file_phids)
|
||||
->execute();
|
||||
$files = mpull($files, null, 'getPHID');
|
||||
$file_author_phids = mpull($files, 'getAuthorPHID', 'getPHID');
|
||||
$authors = id(new PhabricatorHandleQuery())
|
||||
->setViewer($this->getViewer())
|
||||
->withPHIDs($file_author_phids)
|
||||
->execute();
|
||||
$authors = mpull($authors, null, 'getPHID');
|
||||
}
|
||||
|
||||
foreach ($conpherences as $phid => $conpherence) {
|
||||
$participant_phids = array_keys($conpherence->getParticipants());
|
||||
$widget_data = array();
|
||||
|
||||
$event_phids = array();
|
||||
$participant_invites = array_select_keys($invitees, $participant_phids);
|
||||
foreach ($participant_invites as $invite_set) {
|
||||
$event_phids += $invite_set;
|
||||
}
|
||||
$thread_events = array_select_keys($events, array_keys($event_phids));
|
||||
$thread_events = msort($thread_events, 'getDateFrom');
|
||||
$widget_data['events'] = $thread_events;
|
||||
|
||||
$conpherence_files = array();
|
||||
$files_authors = array();
|
||||
foreach ($conpherence->getFilePHIDs() as $curr_phid) {
|
||||
$curr_file = idx($files, $curr_phid);
|
||||
if (!$curr_file) {
|
||||
// this file was deleted or user doesn't have permission to see it
|
||||
// this is generally weird
|
||||
continue;
|
||||
}
|
||||
$conpherence_files[$curr_phid] = $curr_file;
|
||||
// some files don't have authors so be careful
|
||||
$current_author = null;
|
||||
$current_author_phid = idx($file_author_phids, $curr_phid);
|
||||
if ($current_author_phid) {
|
||||
$current_author = $authors[$current_author_phid];
|
||||
}
|
||||
$files_authors[$curr_phid] = $current_author;
|
||||
}
|
||||
$widget_data += array(
|
||||
'files' => $conpherence_files,
|
||||
'files_authors' => $files_authors,
|
||||
);
|
||||
|
||||
$conpherence->attachWidgetData($widget_data);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function loadOrigPics(array $conpherences) {
|
||||
return $this->loadPics(
|
||||
$conpherences,
|
||||
|
|
|
@ -58,12 +58,12 @@ final class ConpherenceThreadSearchEngine
|
|||
protected function getBuiltinQueryNames() {
|
||||
$names = array();
|
||||
|
||||
$names['all'] = pht('All Rooms');
|
||||
|
||||
if ($this->requireViewer()->isLoggedIn()) {
|
||||
$names['participant'] = pht('Joined Rooms');
|
||||
}
|
||||
|
||||
$names['all'] = pht('All Rooms');
|
||||
|
||||
return $names;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ final class ConpherenceThread extends ConpherenceDAO
|
|||
PhabricatorDestructibleInterface {
|
||||
|
||||
protected $title;
|
||||
protected $topic;
|
||||
protected $imagePHIDs = array();
|
||||
protected $messageCount;
|
||||
protected $recentParticipantPHIDs = array();
|
||||
|
@ -20,7 +21,6 @@ final class ConpherenceThread extends ConpherenceDAO
|
|||
private $transactions = self::ATTACHABLE;
|
||||
private $handles = self::ATTACHABLE;
|
||||
private $filePHIDs = self::ATTACHABLE;
|
||||
private $widgetData = self::ATTACHABLE;
|
||||
private $images = self::ATTACHABLE;
|
||||
|
||||
public static function initializeNewRoom(PhabricatorUser $sender) {
|
||||
|
@ -29,6 +29,7 @@ final class ConpherenceThread extends ConpherenceDAO
|
|||
return id(new ConpherenceThread())
|
||||
->setMessageCount(0)
|
||||
->setTitle('')
|
||||
->setTopic('')
|
||||
->attachParticipants(array())
|
||||
->attachFilePHIDs(array())
|
||||
->attachImages(array())
|
||||
|
@ -46,6 +47,7 @@ final class ConpherenceThread extends ConpherenceDAO
|
|||
),
|
||||
self::CONFIG_COLUMN_SCHEMA => array(
|
||||
'title' => 'text255?',
|
||||
'topic' => 'text255',
|
||||
'messageCount' => 'uint64',
|
||||
'mailKey' => 'text20',
|
||||
'joinPolicy' => 'policy',
|
||||
|
@ -164,14 +166,6 @@ final class ConpherenceThread extends ConpherenceDAO
|
|||
return $this->assertAttached($this->filePHIDs);
|
||||
}
|
||||
|
||||
public function attachWidgetData(array $widget_data) {
|
||||
$this->widgetData = $widget_data;
|
||||
return $this;
|
||||
}
|
||||
public function getWidgetData() {
|
||||
return $this->assertAttached($this->widgetData);
|
||||
}
|
||||
|
||||
public function loadImageURI($size) {
|
||||
$file = $this->getImage($size);
|
||||
|
||||
|
@ -342,9 +336,11 @@ final class ConpherenceThread extends ConpherenceDAO
|
|||
$unread_count = $this->getMessageCount() - $user_seen_count;
|
||||
|
||||
$title = $this->getDisplayTitle($viewer);
|
||||
$topic = $this->getTopic();
|
||||
|
||||
return array(
|
||||
'title' => $title,
|
||||
'topic' => $topic,
|
||||
'subtitle' => $subtitle,
|
||||
'unread_count' => $unread_count,
|
||||
'epoch' => $this->getDateModified(),
|
||||
|
|
|
@ -4,6 +4,7 @@ final class ConpherenceTransaction extends PhabricatorApplicationTransaction {
|
|||
|
||||
const TYPE_FILES = 'files';
|
||||
const TYPE_TITLE = 'title';
|
||||
const TYPE_TOPIC = 'topic';
|
||||
const TYPE_PARTICIPANTS = 'participants';
|
||||
const TYPE_DATE_MARKER = 'date-marker';
|
||||
const TYPE_PICTURE = 'picture';
|
||||
|
@ -39,6 +40,7 @@ final class ConpherenceTransaction extends PhabricatorApplicationTransaction {
|
|||
case self::TYPE_PARTICIPANTS:
|
||||
return ($old === null);
|
||||
case self::TYPE_TITLE:
|
||||
case self::TYPE_TOPIC:
|
||||
case self::TYPE_PICTURE:
|
||||
case self::TYPE_DATE_MARKER:
|
||||
return false;
|
||||
|
@ -59,6 +61,7 @@ final class ConpherenceTransaction extends PhabricatorApplicationTransaction {
|
|||
|
||||
switch ($this->getTransactionType()) {
|
||||
case self::TYPE_TITLE:
|
||||
case self::TYPE_TOPIC:
|
||||
case PhabricatorTransactions::TYPE_VIEW_POLICY:
|
||||
case PhabricatorTransactions::TYPE_EDIT_POLICY:
|
||||
case PhabricatorTransactions::TYPE_JOIN_POLICY:
|
||||
|
@ -120,6 +123,55 @@ final class ConpherenceTransaction extends PhabricatorApplicationTransaction {
|
|||
return parent::getTitle();
|
||||
}
|
||||
|
||||
public function getTitleForFeed() {
|
||||
$author_phid = $this->getAuthorPHID();
|
||||
$object_phid = $this->getObjectPHID();
|
||||
|
||||
$old = $this->getOldValue();
|
||||
$new = $this->getNewValue();
|
||||
|
||||
$type = $this->getTransactionType();
|
||||
switch ($type) {
|
||||
case self::TYPE_TITLE:
|
||||
if (strlen($old) && strlen($new)) {
|
||||
return pht(
|
||||
'%s renamed %s from "%s" to "%s".',
|
||||
$this->renderHandleLink($author_phid),
|
||||
$this->renderHandleLink($object_phid),
|
||||
$old,
|
||||
$new);
|
||||
} else {
|
||||
return pht(
|
||||
'%s created the room %s.',
|
||||
$this->renderHandleLink($author_phid),
|
||||
$this->renderHandleLink($object_phid));
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case self::TYPE_TOPIC:
|
||||
if (strlen($new)) {
|
||||
return pht(
|
||||
'%s set the topic of %s to "%s".',
|
||||
$this->renderHandleLink($author_phid),
|
||||
$this->renderHandleLink($object_phid),
|
||||
$new);
|
||||
} else if (strlen($old)) {
|
||||
return pht(
|
||||
'%s deleted the topic in %s',
|
||||
$this->renderHandleLink($author_phid),
|
||||
$this->renderHandleLink($object_phid));
|
||||
}
|
||||
break;
|
||||
case self::TYPE_PICTURE:
|
||||
return pht(
|
||||
'%s updated the room image for %s.',
|
||||
$this->renderHandleLink($author_phid),
|
||||
$this->renderHandleLink($object_phid));
|
||||
break;
|
||||
}
|
||||
return parent::getTitleForFeed();
|
||||
}
|
||||
|
||||
private function getRoomTitle() {
|
||||
$author_phid = $this->getAuthorPHID();
|
||||
|
||||
|
@ -147,6 +199,20 @@ final class ConpherenceTransaction extends PhabricatorApplicationTransaction {
|
|||
}
|
||||
return $title;
|
||||
break;
|
||||
case self::TYPE_TOPIC:
|
||||
if ($new) {
|
||||
$title = pht(
|
||||
'%s set the topic of this room to "%s".',
|
||||
$this->renderHandleLink($author_phid),
|
||||
$new);
|
||||
} else if ($old) {
|
||||
$title = pht(
|
||||
'%s deleted the room topic "%s"',
|
||||
$this->renderHandleLink($author_phid),
|
||||
$old);
|
||||
}
|
||||
return $title;
|
||||
break;
|
||||
case self::TYPE_PICTURE:
|
||||
return pht(
|
||||
'%s updated the room image.',
|
||||
|
|
|
@ -126,7 +126,6 @@ final class ConpherenceDurableColumnView extends AphrontTagView {
|
|||
$classes = array();
|
||||
$classes[] = 'conpherence-durable-column-header';
|
||||
$classes[] = 'phabricator-main-menu-background';
|
||||
$classes[] = 'sprite-main-header';
|
||||
|
||||
$loading_mask = phutil_tag(
|
||||
'div',
|
||||
|
@ -141,12 +140,16 @@ final class ConpherenceDurableColumnView extends AphrontTagView {
|
|||
'class' => implode(' ', $classes),
|
||||
),
|
||||
$this->buildHeader());
|
||||
$icon_bar = phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'conpherence-durable-column-icon-bar',
|
||||
),
|
||||
$this->buildIconBar());
|
||||
|
||||
$icon_bar = null;
|
||||
if ($this->conpherences) {
|
||||
$icon_bar = phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'conpherence-durable-column-icon-bar',
|
||||
),
|
||||
$this->buildIconBar());
|
||||
}
|
||||
|
||||
$transactions = $this->buildTransactions();
|
||||
|
||||
|
@ -283,66 +286,60 @@ final class ConpherenceDurableColumnView extends AphrontTagView {
|
|||
private function buildHeader() {
|
||||
$conpherence = $this->getSelectedConpherence();
|
||||
|
||||
if (!$conpherence) {
|
||||
$bubble_id = celerity_generate_unique_node_id();
|
||||
$dropdown_id = celerity_generate_unique_node_id();
|
||||
|
||||
$header = null;
|
||||
$settings_button = null;
|
||||
$settings_menu = null;
|
||||
$settings_list = new PHUIListView();
|
||||
$header_actions = $this->getHeaderActionsConfig($conpherence);
|
||||
foreach ($header_actions as $action) {
|
||||
$settings_list->addMenuItem(
|
||||
id(new PHUIListItemView())
|
||||
->setHref($action['href'])
|
||||
->setName($action['name'])
|
||||
->setIcon($action['icon'])
|
||||
->setDisabled($action['disabled'])
|
||||
->addSigil('conpherence-durable-column-header-action')
|
||||
->setMetadata(array(
|
||||
'action' => $action['key'],
|
||||
)));
|
||||
}
|
||||
|
||||
} else {
|
||||
$settings_menu = phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'id' => $dropdown_id,
|
||||
'class' => 'phabricator-main-menu-dropdown phui-list-sidenav '.
|
||||
'conpherence-settings-dropdown',
|
||||
'sigil' => 'phabricator-notification-menu',
|
||||
'style' => 'display: none',
|
||||
),
|
||||
$settings_list);
|
||||
|
||||
$bubble_id = celerity_generate_unique_node_id();
|
||||
$dropdown_id = celerity_generate_unique_node_id();
|
||||
Javelin::initBehavior(
|
||||
'aphlict-dropdown',
|
||||
array(
|
||||
'bubbleID' => $bubble_id,
|
||||
'dropdownID' => $dropdown_id,
|
||||
'local' => true,
|
||||
'containerDivID' => 'conpherence-durable-column',
|
||||
));
|
||||
|
||||
$settings_list = new PHUIListView();
|
||||
$header_actions = $this->getHeaderActionsConfig($conpherence);
|
||||
foreach ($header_actions as $action) {
|
||||
$settings_list->addMenuItem(
|
||||
id(new PHUIListItemView())
|
||||
->setHref($action['href'])
|
||||
->setName($action['name'])
|
||||
->setIcon($action['icon'])
|
||||
->setDisabled($action['disabled'])
|
||||
->addSigil('conpherence-durable-column-header-action')
|
||||
->setMetadata(array(
|
||||
'action' => $action['key'],
|
||||
)));
|
||||
}
|
||||
|
||||
$settings_menu = phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'id' => $dropdown_id,
|
||||
'class' => 'phabricator-main-menu-dropdown phui-list-sidenav '.
|
||||
'conpherence-settings-dropdown',
|
||||
'sigil' => 'phabricator-notification-menu',
|
||||
'style' => 'display: none',
|
||||
),
|
||||
$settings_list);
|
||||
|
||||
Javelin::initBehavior(
|
||||
'aphlict-dropdown',
|
||||
array(
|
||||
'bubbleID' => $bubble_id,
|
||||
'dropdownID' => $dropdown_id,
|
||||
'local' => true,
|
||||
'containerDivID' => 'conpherence-durable-column',
|
||||
));
|
||||
|
||||
$item = id(new PHUIListItemView())
|
||||
->setName(pht('Room Actions'))
|
||||
->setIcon('fa-bars')
|
||||
->addClass('core-menu-item')
|
||||
->addSigil('conpherence-settings-menu')
|
||||
->setID($bubble_id)
|
||||
->setHref('#')
|
||||
->setAural(pht('Room Actions'))
|
||||
->setOrder(300);
|
||||
$settings_button = id(new PHUIListView())
|
||||
->addMenuItem($item)
|
||||
->addClass('phabricator-dark-menu')
|
||||
->addClass('phabricator-application-menu');
|
||||
$item = id(new PHUIListItemView())
|
||||
->setName(pht('Room Actions'))
|
||||
->setIcon('fa-bars')
|
||||
->addClass('core-menu-item')
|
||||
->addSigil('conpherence-settings-menu')
|
||||
->setID($bubble_id)
|
||||
->setHref('#')
|
||||
->setAural(pht('Room Actions'))
|
||||
->setOrder(300);
|
||||
$settings_button = id(new PHUIListView())
|
||||
->addMenuItem($item)
|
||||
->addClass('phabricator-dark-menu')
|
||||
->addClass('phabricator-application-menu');
|
||||
|
||||
$header = null;
|
||||
if ($conpherence) {
|
||||
$data = $conpherence->getDisplayData($this->getUser());
|
||||
$header = phutil_tag(
|
||||
'span',
|
||||
|
@ -351,7 +348,7 @@ final class ConpherenceDurableColumnView extends AphrontTagView {
|
|||
$this->getPolicyIcon($conpherence, $this->getPolicyObjects()),
|
||||
$data['title'],
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
phutil_tag(
|
||||
|
@ -372,42 +369,46 @@ final class ConpherenceDurableColumnView extends AphrontTagView {
|
|||
));
|
||||
}
|
||||
|
||||
private function getHeaderActionsConfig(ConpherenceThread $conpherence) {
|
||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||
$this->getUser(),
|
||||
$conpherence,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
private function getHeaderActionsConfig($conpherence) {
|
||||
|
||||
return array(
|
||||
array(
|
||||
$actions = array();
|
||||
if ($conpherence) {
|
||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||
$this->getUser(),
|
||||
$conpherence,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
$actions[] = array(
|
||||
'name' => pht('Add Participants'),
|
||||
'disabled' => !$can_edit,
|
||||
'href' => '/conpherence/update/'.$conpherence->getID().'/',
|
||||
'icon' => 'fa-plus',
|
||||
'key' => ConpherenceUpdateActions::ADD_PERSON,
|
||||
),
|
||||
array(
|
||||
);
|
||||
$actions[] = array(
|
||||
'name' => pht('Edit Room'),
|
||||
'disabled' => !$can_edit,
|
||||
'href' => '/conpherence/update/'.$conpherence->getID().'/?nopic',
|
||||
'icon' => 'fa-pencil',
|
||||
'key' => ConpherenceUpdateActions::METADATA,
|
||||
),
|
||||
array(
|
||||
);
|
||||
$actions[] = array(
|
||||
'name' => pht('View in Conpherence'),
|
||||
'disabled' => false,
|
||||
'href' => '/'.$conpherence->getMonogram(),
|
||||
'icon' => 'fa-comments',
|
||||
'key' => 'go_conpherence',
|
||||
),
|
||||
array(
|
||||
'name' => pht('Hide Column'),
|
||||
'disabled' => false,
|
||||
'href' => '#',
|
||||
'icon' => 'fa-times',
|
||||
'key' => 'hide_column',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
$actions[] = array(
|
||||
'name' => pht('Hide Column'),
|
||||
'disabled' => false,
|
||||
'href' => '#',
|
||||
'icon' => 'fa-times',
|
||||
'key' => 'hide_column',
|
||||
);
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
private function buildTransactions() {
|
||||
|
|
|
@ -55,17 +55,24 @@ final class ConpherenceLayoutView extends AphrontView {
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function getWidgetColumnVisible() {
|
||||
$widget_key = PhabricatorConpherenceWidgetVisibleSetting::SETTINGKEY;
|
||||
$user = $this->getUser();
|
||||
return (bool)$user->getUserSetting($widget_key, false);
|
||||
}
|
||||
|
||||
public function render() {
|
||||
require_celerity_resource('conpherence-menu-css');
|
||||
require_celerity_resource('conpherence-message-pane-css');
|
||||
require_celerity_resource('conpherence-widget-pane-css');
|
||||
require_celerity_resource('conpherence-participant-pane-css');
|
||||
|
||||
$layout_id = celerity_generate_unique_node_id();
|
||||
$layout_id = 'conpherence-main-layout';
|
||||
|
||||
$selected_id = null;
|
||||
$selected_thread_id = null;
|
||||
$selected_thread_phid = null;
|
||||
$can_edit_selected = null;
|
||||
$nux = null;
|
||||
if ($this->thread) {
|
||||
$selected_id = $this->thread->getPHID().'-nav-item';
|
||||
$selected_thread_id = $this->thread->getID();
|
||||
|
@ -74,6 +81,8 @@ final class ConpherenceLayoutView extends AphrontView {
|
|||
$this->getUser(),
|
||||
$this->thread,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
} else {
|
||||
$nux = $this->buildNUXView();
|
||||
}
|
||||
$this->initBehavior('conpherence-menu',
|
||||
array(
|
||||
|
@ -90,14 +99,16 @@ final class ConpherenceLayoutView extends AphrontView {
|
|||
'hasWidgets' => false,
|
||||
));
|
||||
|
||||
$class = null;
|
||||
$classes = array();
|
||||
if (!$this->getUser()->isLoggedIn()) {
|
||||
$class = 'conpherence-logged-out';
|
||||
$classes[] = 'conpherence-logged-out';
|
||||
}
|
||||
|
||||
$this->initBehavior(
|
||||
'conpherence-widget-pane',
|
||||
ConpherenceWidgetConfigConstants::getWidgetPaneBehaviorConfig());
|
||||
if (!$this->getWidgetColumnVisible()) {
|
||||
$classes[] = 'hide-widgets';
|
||||
}
|
||||
|
||||
$this->initBehavior('conpherence-participant-pane');
|
||||
|
||||
return javelin_tag(
|
||||
'div',
|
||||
|
@ -105,7 +116,7 @@ final class ConpherenceLayoutView extends AphrontView {
|
|||
'id' => $layout_id,
|
||||
'sigil' => 'conpherence-layout',
|
||||
'class' => 'conpherence-layout '.
|
||||
$class.
|
||||
implode(' ', $classes).
|
||||
' conpherence-role-'.$this->role,
|
||||
),
|
||||
array(
|
||||
|
@ -138,28 +149,13 @@ final class ConpherenceLayoutView extends AphrontView {
|
|||
'sigil' => 'conpherence-no-threads',
|
||||
'style' => 'display: none;',
|
||||
),
|
||||
array(
|
||||
phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'text',
|
||||
),
|
||||
pht('You are not in any rooms yet.')),
|
||||
javelin_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => '/conpherence/new/',
|
||||
'class' => 'button grey',
|
||||
'sigil' => 'workflow',
|
||||
),
|
||||
pht('Create a Room')),
|
||||
)),
|
||||
$nux),
|
||||
javelin_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'conpherence-widget-pane',
|
||||
'id' => 'conpherence-widget-pane',
|
||||
'sigil' => 'conpherence-widget-pane',
|
||||
'class' => 'conpherence-participant-pane',
|
||||
'id' => 'conpherence-participant-pane',
|
||||
'sigil' => 'conpherence-participant-pane',
|
||||
),
|
||||
array(
|
||||
phutil_tag(
|
||||
|
@ -209,4 +205,55 @@ final class ConpherenceLayoutView extends AphrontView {
|
|||
));
|
||||
}
|
||||
|
||||
private function buildNUXView() {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$engine = new ConpherenceThreadSearchEngine();
|
||||
$engine->setViewer($viewer);
|
||||
$saved = $engine->buildSavedQueryFromBuiltin('all');
|
||||
$query = $engine->buildQueryFromSavedQuery($saved);
|
||||
$pager = $engine->newPagerForSavedQuery($saved);
|
||||
$pager->setPageSize(10);
|
||||
$results = $engine->executeQuery($query, $pager);
|
||||
$view = $engine->renderResults($results, $saved);
|
||||
|
||||
$create_button = id(new PHUIButtonView())
|
||||
->setTag('a')
|
||||
->setText(pht('New Room'))
|
||||
->setHref('/conpherence/new/')
|
||||
->setWorkflow(true)
|
||||
->setColor(PHUIButtonView::GREEN);
|
||||
|
||||
if ($results) {
|
||||
$create_button->setIcon('fa-comments');
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader(pht('Joinable Rooms'))
|
||||
->addActionLink($create_button);
|
||||
|
||||
$box = id(new PHUIObjectBoxView())
|
||||
->setHeader($header)
|
||||
->setObjectList($view->getObjectList());
|
||||
if ($viewer->isLoggedIn()) {
|
||||
$info = id(new PHUIInfoView())
|
||||
->appendChild(pht('You have not joined any rooms yet.'))
|
||||
->setSeverity(PHUIInfoView::SEVERITY_NOTICE);
|
||||
$box->setInfoView($info);
|
||||
}
|
||||
|
||||
return $box;
|
||||
} else {
|
||||
|
||||
$view = id(new PHUIBigInfoView())
|
||||
->setIcon('fa-comments')
|
||||
->setTitle(pht('Welcome to Conpherence'))
|
||||
->setDescription(
|
||||
pht('Conpherence lets you create public or private rooms to '.
|
||||
'communicate with others.'))
|
||||
->addAction($create_button);
|
||||
|
||||
return $view;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -63,9 +63,11 @@ final class ConpherenceMenuItemView extends AphrontTagView {
|
|||
}
|
||||
|
||||
protected function getTagAttributes() {
|
||||
$classes = array('conpherence-menu-item-view');
|
||||
$classes = array();
|
||||
$classes[] = 'conpherence-menu-item-view';
|
||||
$classes[] = 'phui-list-item-href';
|
||||
return array(
|
||||
'class' => $classes,
|
||||
'class' => implode(' ', $classes),
|
||||
'href' => $this->href,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,19 +1,34 @@
|
|||
<?php
|
||||
|
||||
final class ConpherencePeopleWidgetView extends ConpherenceWidgetView {
|
||||
final class ConpherenceParticipantView extends AphrontView {
|
||||
|
||||
private $conpherence;
|
||||
private $updateURI;
|
||||
|
||||
public function setConpherence(ConpherenceThread $conpherence) {
|
||||
$this->conpherence = $conpherence;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setUpdateURI($uri) {
|
||||
$this->updateURI = $uri;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
$conpherence = $this->getConpherence();
|
||||
$widget_data = $conpherence->getWidgetData();
|
||||
$viewer = $this->getUser();
|
||||
$conpherence = $this->conpherence;
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$participants = $conpherence->getParticipants();
|
||||
$count = new PhutilNumber(count($participants));
|
||||
$handles = $conpherence->getHandles();
|
||||
$handles = array_intersect_key($handles, $participants);
|
||||
$head_handles = array_select_keys($handles, array($viewer->getPHID()));
|
||||
$handle_list = mpull($handles, 'getName');
|
||||
natcasesort($handle_list);
|
||||
$handles = mpull($handles, null, 'getName');
|
||||
$handles = array_select_keys($handles, $handle_list);
|
||||
|
||||
$head_handles = mpull($head_handles, null, 'getName');
|
||||
$handles = $head_handles + $handles;
|
||||
|
||||
|
@ -28,7 +43,8 @@ final class ConpherencePeopleWidgetView extends ConpherenceWidgetView {
|
|||
|
||||
if (($user_phid == $viewer->getPHID()) || $can_edit) {
|
||||
$icon = id(new PHUIIconView())
|
||||
->setIcon('fa-times lightbluetext');
|
||||
->setIcon('fa-times')
|
||||
->addClass('lightbluetext');
|
||||
$remove_html = javelin_tag(
|
||||
'a',
|
||||
array(
|
||||
|
@ -67,7 +83,30 @@ final class ConpherencePeopleWidgetView extends ConpherenceWidgetView {
|
|||
));
|
||||
}
|
||||
|
||||
return $body;
|
||||
$new_icon = id(new PHUIIconView())
|
||||
->setIcon('fa-plus-square')
|
||||
->setHref($this->updateURI)
|
||||
->setMetadata(array('widget' => null))
|
||||
->addSigil('conpherence-widget-adder');
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader(pht('Participants (%d)', $count))
|
||||
->addClass('widgets-header')
|
||||
->addActionItem($new_icon);
|
||||
|
||||
$content = javelin_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'widgets-body',
|
||||
'id' => 'widgets-people',
|
||||
'sigil' => 'widgets-people',
|
||||
),
|
||||
array(
|
||||
$header,
|
||||
$body,
|
||||
));
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
}
|
|
@ -31,6 +31,9 @@ final class ConpherenceThreadListView extends AphrontView {
|
|||
|
||||
$this->addRoomsToMenu($menu, $this->threads, $policy_objects);
|
||||
|
||||
$menu = phutil_tag_div('phabricator-side-menu', $menu);
|
||||
$menu = phutil_tag_div('phui-basic-nav', $menu);
|
||||
|
||||
return $menu;
|
||||
}
|
||||
|
||||
|
@ -96,14 +99,7 @@ final class ConpherenceThreadListView extends AphrontView {
|
|||
array $rooms,
|
||||
array $policy_objects) {
|
||||
|
||||
$header = $this->renderMenuItemHeader(
|
||||
pht('Rooms'),
|
||||
'conpherence-room-list-header');
|
||||
$header->appendChild(
|
||||
id(new PHUIIconView())
|
||||
->setIcon('fa-search')
|
||||
->setHref('/conpherence/search/')
|
||||
->setText(pht('Search')));
|
||||
$header = $this->renderMenuItemHeader();
|
||||
$menu->addMenuItem($header);
|
||||
|
||||
if (empty($rooms)) {
|
||||
|
@ -191,11 +187,53 @@ final class ConpherenceThreadListView extends AphrontView {
|
|||
return $menu;
|
||||
}
|
||||
|
||||
private function renderMenuItemHeader($title, $class = null) {
|
||||
private function renderMenuItemHeader() {
|
||||
$rooms = phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'class' => 'room-list-href',
|
||||
'href' => '/conpherence/search/',
|
||||
),
|
||||
pht('Rooms'));
|
||||
|
||||
$new_icon = id(new PHUIIconView())
|
||||
->setIcon('fa-plus-square')
|
||||
->addSigil('has-tooltip')
|
||||
->setHref('/conpherence/new/')
|
||||
->setWorkflow(true)
|
||||
->setMetaData(array(
|
||||
'tip' => pht('New Room'),
|
||||
));
|
||||
|
||||
$search_icon = id(new PHUIIconView())
|
||||
->setIcon('fa-search')
|
||||
->addSigil('has-tooltip')
|
||||
->setHref('/conpherence/search/')
|
||||
->setMetaData(array(
|
||||
'tip' => pht('Search Rooms'),
|
||||
));
|
||||
|
||||
$icons = phutil_tag(
|
||||
'span',
|
||||
array(
|
||||
'class' => 'room-list-icons',
|
||||
),
|
||||
array(
|
||||
$new_icon,
|
||||
$search_icon,
|
||||
));
|
||||
|
||||
$new_icon = id(new PHUIIconView())
|
||||
->setIcon('fa-plus-square')
|
||||
->setHref('/conpherence/new/')
|
||||
->setWorkflow(true);
|
||||
|
||||
$custom = phutil_tag_div('grouped', array($rooms, $icons));
|
||||
|
||||
$item = id(new PHUIListItemView())
|
||||
->setType(PHUIListItemView::TYPE_LABEL)
|
||||
->setName($title)
|
||||
->addClass($class);
|
||||
->setType(PHUIListItemView::TYPE_CUSTOM)
|
||||
->setName($custom)
|
||||
->addClass('conpherence-room-list-header');
|
||||
return $item;
|
||||
}
|
||||
|
||||
|
|
|
@ -133,16 +133,6 @@ final class ConpherenceTransactionView extends AphrontView {
|
|||
$transaction = $this->getConpherenceTransaction();
|
||||
$info = array();
|
||||
|
||||
if ($this->getFullDisplay() && $transaction->getContentSource()) {
|
||||
$content_source = id(new PhabricatorContentSourceView())
|
||||
->setContentSource($transaction->getContentSource())
|
||||
->setUser($viewer)
|
||||
->render();
|
||||
if ($content_source) {
|
||||
$info[] = $content_source;
|
||||
}
|
||||
}
|
||||
|
||||
Javelin::initBehavior('phabricator-tooltips');
|
||||
$tip = phabricator_datetime($transaction->getDateCreated(), $viewer);
|
||||
$label = phabricator_time($transaction->getDateCreated(), $viewer);
|
||||
|
@ -184,8 +174,6 @@ final class ConpherenceTransactionView extends AphrontView {
|
|||
$label);
|
||||
}
|
||||
|
||||
$info = phutil_implode_html(" \xC2\xB7 ", $info);
|
||||
|
||||
return phutil_tag(
|
||||
'span',
|
||||
array(
|
||||
|
@ -243,6 +231,7 @@ final class ConpherenceTransactionView extends AphrontView {
|
|||
$content = $transaction->getTitle();
|
||||
break;
|
||||
case ConpherenceTransaction::TYPE_TITLE:
|
||||
case ConpherenceTransaction::TYPE_TOPIC:
|
||||
case ConpherenceTransaction::TYPE_PICTURE:
|
||||
case ConpherenceTransaction::TYPE_PICTURE_CROP:
|
||||
case ConpherenceTransaction::TYPE_PARTICIPANTS:
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
<?php
|
||||
|
||||
abstract class ConpherenceWidgetView extends AphrontView {
|
||||
|
||||
private $conpherence;
|
||||
private $updateURI;
|
||||
|
||||
public function setUpdateURI($update_uri) {
|
||||
$this->updateURI = $update_uri;
|
||||
return $this;
|
||||
}
|
||||
public function getUpdateURI() {
|
||||
return $this->updateURI;
|
||||
}
|
||||
|
||||
public function setConpherence(ConpherenceThread $conpherence) {
|
||||
$this->conpherence = $conpherence;
|
||||
return $this;
|
||||
}
|
||||
public function getConpherence() {
|
||||
return $this->conpherence;
|
||||
}
|
||||
|
||||
}
|
|
@ -1511,13 +1511,6 @@ final class DifferentialTransactionEditor
|
|||
$packages = PhabricatorOwnersPackage::loadAffectedPackages(
|
||||
$repository,
|
||||
$this->affectedPaths);
|
||||
|
||||
foreach ($packages as $key => $package) {
|
||||
if ($package->isArchived()) {
|
||||
unset($packages[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$packages) {
|
||||
return array();
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ final class HeraldDifferentialRevisionAdapter
|
|||
'Test rules which run when a revision is created or updated.');
|
||||
}
|
||||
|
||||
public function newTestAdapter($object) {
|
||||
public function newTestAdapter(PhabricatorUser $viewer, $object) {
|
||||
return self::newLegacyAdapter(
|
||||
$object,
|
||||
$object->loadActiveDiff());
|
||||
|
|
|
@ -105,7 +105,11 @@ final class DiffusionBrowseQueryConduitAPIMethod
|
|||
|
||||
$count = 0;
|
||||
$results = array();
|
||||
foreach (explode("\0", rtrim($stdout)) as $line) {
|
||||
$lines = empty($stdout)
|
||||
? array()
|
||||
: explode("\0", rtrim($stdout));
|
||||
|
||||
foreach ($lines as $line) {
|
||||
// NOTE: Limit to 5 components so we parse filenames with spaces in them
|
||||
// correctly.
|
||||
// NOTE: The output uses a mixture of tabs and one-or-more spaces to
|
||||
|
|
|
@ -8,7 +8,6 @@ final class HeraldCommitAdapter
|
|||
protected $revision;
|
||||
|
||||
protected $commit;
|
||||
protected $commitData;
|
||||
private $commitDiff;
|
||||
|
||||
protected $affectedPaths;
|
||||
|
@ -35,6 +34,23 @@ final class HeraldCommitAdapter
|
|||
'Test rules which run after a commit is discovered and imported.');
|
||||
}
|
||||
|
||||
public function newTestAdapter(PhabricatorUser $viewer, $object) {
|
||||
$object = id(new DiffusionCommitQuery())
|
||||
->setViewer($viewer)
|
||||
->withPHIDs(array($object->getPHID()))
|
||||
->needCommitData(true)
|
||||
->executeOne();
|
||||
if (!$object) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Failed to reload commit ("%s") to fetch commit data.',
|
||||
$object->getPHID()));
|
||||
}
|
||||
|
||||
return id(clone $this)
|
||||
->setObject($object);
|
||||
}
|
||||
|
||||
protected function initializeNewAdapter() {
|
||||
$this->commit = $this->newObject();
|
||||
}
|
||||
|
@ -100,33 +116,6 @@ final class HeraldCommitAdapter
|
|||
return pht('This rule can trigger for **repositories** and **projects**.');
|
||||
}
|
||||
|
||||
public function setCommit(PhabricatorRepositoryCommit $commit) {
|
||||
$viewer = PhabricatorUser::getOmnipotentUser();
|
||||
|
||||
$repository = id(new PhabricatorRepositoryQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($commit->getRepositoryID()))
|
||||
->executeOne();
|
||||
if (!$repository) {
|
||||
throw new Exception(pht('Unable to load repository!'));
|
||||
}
|
||||
|
||||
$data = id(new PhabricatorRepositoryCommitData())->loadOneWhere(
|
||||
'commitID = %d',
|
||||
$commit->getID());
|
||||
if (!$data) {
|
||||
throw new Exception(pht('Unable to load commit data!'));
|
||||
}
|
||||
|
||||
$this->commit = clone $commit;
|
||||
$this->commit->attachRepository($repository);
|
||||
$this->commit->attachCommitData($data);
|
||||
|
||||
$this->commitData = $data;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getHeraldName() {
|
||||
return $this->commit->getMonogram();
|
||||
}
|
||||
|
@ -171,7 +160,10 @@ final class HeraldCommitAdapter
|
|||
public function loadDifferentialRevision() {
|
||||
if ($this->affectedRevision === null) {
|
||||
$this->affectedRevision = false;
|
||||
$data = $this->commitData;
|
||||
|
||||
$commit = $this->getObject();
|
||||
$data = $commit->getCommitData();
|
||||
|
||||
$revision_id = $data->getCommitDetail('differential.revisionID');
|
||||
if ($revision_id) {
|
||||
// NOTE: The Herald rule owner might not actually have access to
|
||||
|
|
|
@ -104,7 +104,7 @@ final class DiffusionRepositoryClusterEngine extends Phobject {
|
|||
// We identify all the cluster leaders and reset their version to 0.
|
||||
// We identify all the cluster followers and demote them.
|
||||
|
||||
// This allows the cluter to start over again at version 0 but keep the
|
||||
// This allows the cluster to start over again at version 0 but keep the
|
||||
// same leaders.
|
||||
|
||||
if ($versions) {
|
||||
|
|
|
@ -48,4 +48,32 @@ abstract class DoorkeeperBridge extends Phobject {
|
|||
return null;
|
||||
}
|
||||
|
||||
final protected function saveExternalObject(
|
||||
DoorkeeperObjectRef $ref,
|
||||
DoorkeeperExternalObject $obj) {
|
||||
|
||||
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
|
||||
try {
|
||||
$obj->save();
|
||||
} catch (AphrontDuplicateKeyQueryException $ex) {
|
||||
|
||||
// In various cases, we may race another process importing the same
|
||||
// data. If we do, we'll collide on the object key. Load the object
|
||||
// the other process created and use that.
|
||||
$obj = id(new DoorkeeperExternalObjectQuery())
|
||||
->setViewer($this->getViewer())
|
||||
->withObjectKeys(array($ref->getObjectKey()))
|
||||
->executeOne();
|
||||
if (!$obj) {
|
||||
throw new PhutilProxyException(
|
||||
pht('Failed to load external object after collision.'),
|
||||
$ex);
|
||||
}
|
||||
|
||||
$ref->attachExternalObject($obj);
|
||||
}
|
||||
unset($unguarded);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -113,10 +113,7 @@ final class DoorkeeperBridgeAsana extends DoorkeeperBridge {
|
|||
}
|
||||
|
||||
$this->fillObjectFromData($obj, $result);
|
||||
|
||||
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
|
||||
$obj->save();
|
||||
unset($unguarded);
|
||||
$this->saveExternalObject($ref, $obj);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -78,10 +78,7 @@ final class DoorkeeperBridgeGitHubIssue
|
|||
$obj = $ref->getExternalObject();
|
||||
|
||||
$this->fillObjectFromData($obj, $result);
|
||||
|
||||
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
|
||||
$obj->save();
|
||||
unset($unguarded);
|
||||
$this->saveExternalObject($ref, $obj);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -101,10 +101,7 @@ final class DoorkeeperBridgeGitHubUser
|
|||
|
||||
$obj = $ref->getExternalObject();
|
||||
$this->fillObjectFromData($obj, $spec);
|
||||
|
||||
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
|
||||
$obj->save();
|
||||
unset($unguarded);
|
||||
$this->saveExternalObject($ref, $obj);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -104,10 +104,7 @@ final class DoorkeeperBridgeJIRA extends DoorkeeperBridge {
|
|||
}
|
||||
|
||||
$this->fillObjectFromData($obj, $result);
|
||||
|
||||
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
|
||||
$obj->save();
|
||||
unset($unguarded);
|
||||
$this->saveExternalObject($ref, $obj);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -55,11 +55,27 @@ final class PhabricatorVersionedDraft extends PhabricatorDraftDAO {
|
|||
return $draft;
|
||||
}
|
||||
|
||||
return id(new PhabricatorVersionedDraft())
|
||||
->setObjectPHID($object_phid)
|
||||
->setAuthorPHID($viewer_phid)
|
||||
->setVersion((int)$version)
|
||||
->save();
|
||||
try {
|
||||
return id(new self())
|
||||
->setObjectPHID($object_phid)
|
||||
->setAuthorPHID($viewer_phid)
|
||||
->setVersion((int)$version)
|
||||
->save();
|
||||
} catch (AphrontDuplicateKeyQueryException $ex) {
|
||||
$duplicate_exception = $ex;
|
||||
}
|
||||
|
||||
// In rare cases we can race ourselves, and at one point there was a bug
|
||||
// which caused the browser to submit two preview requests at exactly
|
||||
// the same time. If the insert failed with a duplicate key exception,
|
||||
// try to load the colliding row to recover from it.
|
||||
|
||||
$draft = self::loadDraft($object_phid, $viewer_phid);
|
||||
if ($draft) {
|
||||
return $draft;
|
||||
}
|
||||
|
||||
throw $duplicate_exception;
|
||||
}
|
||||
|
||||
public static function purgeDrafts(
|
||||
|
|
|
@ -18,10 +18,6 @@ final class PhabricatorGuideApplication extends PhabricatorApplication {
|
|||
return 'fa-map-o';
|
||||
}
|
||||
|
||||
public function isPrototype() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getApplicationGroup() {
|
||||
return self::GROUP_UTILITIES;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ abstract class PhabricatorGuideController extends PhabricatorController {
|
|||
$nav->setBaseURI(new PhutilURI($this->getApplicationURI()));
|
||||
$nav->addLabel(pht('Guides'));
|
||||
|
||||
$modules = PhabricatorGuideModule::getAllModules();
|
||||
$modules = PhabricatorGuideModule::getEnabledModules();
|
||||
foreach ($modules as $key => $module) {
|
||||
$nav->addFilter($key.'/', $module->getModuleName());
|
||||
}
|
||||
|
|
|
@ -7,10 +7,11 @@ final class PhabricatorGuideModuleController
|
|||
$viewer = $this->getViewer();
|
||||
$key = $request->getURIData('module');
|
||||
|
||||
$all_modules = PhabricatorGuideModule::getEnabledModules();
|
||||
|
||||
if (!$key) {
|
||||
$key = 'welcome';
|
||||
$key = key($all_modules);
|
||||
}
|
||||
$all_modules = PhabricatorGuideModule::getAllModules();
|
||||
|
||||
$nav = $this->buildSideNavView();
|
||||
$nav->selectFilter($key.'/');
|
||||
|
|
|
@ -14,6 +14,13 @@ final class PhabricatorGuideInstallModule extends PhabricatorGuideModule {
|
|||
return 20;
|
||||
}
|
||||
|
||||
public function getIsModuleEnabled() {
|
||||
if (PhabricatorEnv::getEnvConfig('cluster.instance')) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function renderModuleStatus(AphrontRequest $request) {
|
||||
$viewer = $request->getViewer();
|
||||
|
||||
|
@ -25,13 +32,11 @@ final class PhabricatorGuideInstallModule extends PhabricatorGuideModule {
|
|||
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.');
|
||||
}
|
||||
|
@ -41,7 +46,6 @@ final class PhabricatorGuideInstallModule extends PhabricatorGuideModule {
|
|||
->setHref($href)
|
||||
->setIcon($icon)
|
||||
->setIconBackground($icon_bg)
|
||||
->setSkipHref($skip)
|
||||
->setDescription($description);
|
||||
$guide_items->addItem($item);
|
||||
|
||||
|
@ -55,13 +59,11 @@ final class PhabricatorGuideInstallModule extends PhabricatorGuideModule {
|
|||
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.');
|
||||
|
@ -72,7 +74,6 @@ final class PhabricatorGuideInstallModule extends PhabricatorGuideModule {
|
|||
->setHref($href)
|
||||
->setIcon($icon)
|
||||
->setIconBackground($icon_bg)
|
||||
->setSkipHref($skip)
|
||||
->setDescription($description);
|
||||
$guide_items->addItem($item);
|
||||
|
||||
|
@ -88,13 +89,11 @@ final class PhabricatorGuideInstallModule extends PhabricatorGuideModule {
|
|||
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.');
|
||||
}
|
||||
|
@ -104,7 +103,6 @@ final class PhabricatorGuideInstallModule extends PhabricatorGuideModule {
|
|||
->setHref($href)
|
||||
->setIcon($icon)
|
||||
->setIconBackground($icon_bg)
|
||||
->setSkipHref($skip)
|
||||
->setDescription($description);
|
||||
$guide_items->addItem($item);
|
||||
|
||||
|
@ -120,13 +118,11 @@ final class PhabricatorGuideInstallModule extends PhabricatorGuideModule {
|
|||
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');
|
||||
}
|
||||
|
@ -136,25 +132,21 @@ final class PhabricatorGuideInstallModule extends PhabricatorGuideModule {
|
|||
->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;
|
||||
$href = PhabricatorEnv::getURI('/config/edit/notification.servers/');
|
||||
$have_notifications = PhabricatorEnv::getEnvConfig('notification.servers');
|
||||
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.');
|
||||
}
|
||||
|
@ -164,12 +156,23 @@ final class PhabricatorGuideInstallModule extends PhabricatorGuideModule {
|
|||
->setHref($href)
|
||||
->setIcon($icon)
|
||||
->setIconBackground($icon_bg)
|
||||
->setSkipHref($skip)
|
||||
->setDescription($description);
|
||||
|
||||
$guide_items->addItem($item);
|
||||
|
||||
return $guide_items;
|
||||
$intro = pht(
|
||||
'Phabricator has been successfully installed. 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 '.
|
||||
'{icon globe} **Applications** under {icon map-o} **Guides**.');
|
||||
|
||||
$intro = new PHUIRemarkupView($viewer, $intro);
|
||||
|
||||
$intro = id(new PHUIDocumentViewPro())
|
||||
->appendChild($intro);
|
||||
|
||||
return array($intro, $guide_items);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ abstract class PhabricatorGuideModule extends Phobject {
|
|||
abstract public function getModuleKey();
|
||||
abstract public function getModuleName();
|
||||
abstract public function getModulePosition();
|
||||
abstract public function getIsModuleEnabled();
|
||||
abstract public function renderModuleStatus(AphrontRequest $request);
|
||||
|
||||
final public static function getAllModules() {
|
||||
|
@ -15,4 +16,13 @@ abstract class PhabricatorGuideModule extends Phobject {
|
|||
->execute();
|
||||
}
|
||||
|
||||
final public static function getEnabledModules() {
|
||||
return id(new PhutilClassMapQuery())
|
||||
->setAncestorClass(__CLASS__)
|
||||
->setUniqueMethod('getModuleKey')
|
||||
->setSortMethod('getModulePosition')
|
||||
->setFilterMethod('getIsModuleEnabled')
|
||||
->execute();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -14,78 +14,29 @@ final class PhabricatorGuideQuickStartModule extends PhabricatorGuideModule {
|
|||
return 30;
|
||||
}
|
||||
|
||||
public function getIsModuleEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function renderModuleStatus(AphrontRequest $request) {
|
||||
$viewer = $request->getViewer();
|
||||
$instance = PhabricatorEnv::getEnvConfig('cluster.instance');
|
||||
|
||||
$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;
|
||||
$repository_check = id(new PhabricatorRepositoryQuery())
|
||||
->setViewer($viewer)
|
||||
->execute();
|
||||
$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.');
|
||||
|
@ -96,24 +47,23 @@ final class PhabricatorGuideQuickStartModule extends PhabricatorGuideModule {
|
|||
->setHref($href)
|
||||
->setIcon($icon)
|
||||
->setIconBackground($icon_bg)
|
||||
->setSkipHref($skip)
|
||||
->setDescription($description);
|
||||
$guide_items->addItem($item);
|
||||
|
||||
|
||||
$title = pht('Create a Project');
|
||||
$project_check = true;
|
||||
$project_check = id(new PhabricatorProjectQuery())
|
||||
->setViewer($viewer)
|
||||
->execute();
|
||||
$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.');
|
||||
|
@ -124,24 +74,49 @@ final class PhabricatorGuideQuickStartModule extends PhabricatorGuideModule {
|
|||
->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) {
|
||||
$title = pht('Create a Task');
|
||||
$task_check = id(new ManiphestTaskQuery())
|
||||
->setViewer($viewer)
|
||||
->execute();
|
||||
$href = PhabricatorEnv::getURI('/maniphest/');
|
||||
if ($task_check) {
|
||||
$icon = 'fa-check';
|
||||
$icon_bg = 'bg-green';
|
||||
$description = pht(
|
||||
"You've created at least one task.");
|
||||
} else {
|
||||
$icon = 'fa-anchor';
|
||||
$icon_bg = 'bg-sky';
|
||||
$description =
|
||||
pht('Create some work for the interns in Maniphest.');
|
||||
}
|
||||
|
||||
$item = id(new PhabricatorGuideItemView())
|
||||
->setTitle($title)
|
||||
->setHref($href)
|
||||
->setIcon($icon)
|
||||
->setIconBackground($icon_bg)
|
||||
->setDescription($description);
|
||||
$guide_items->addItem($item);
|
||||
|
||||
$title = pht('Build a Dashboard');
|
||||
$have_dashboard = (bool)PhabricatorDashboardInstall::getDashboard(
|
||||
$viewer,
|
||||
PhabricatorHomeApplication::DASHBOARD_DEFAULT,
|
||||
'PhabricatorHomeApplication');
|
||||
$href = PhabricatorEnv::getURI('/dashboard/');
|
||||
if ($have_dashboard) {
|
||||
$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.');
|
||||
}
|
||||
|
@ -151,24 +126,21 @@ final class PhabricatorGuideQuickStartModule extends PhabricatorGuideModule {
|
|||
->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) {
|
||||
$wordmark = PhabricatorEnv::getEnvConfig('ui.logo');
|
||||
$href = PhabricatorEnv::getURI('/config/edit/ui.logo/');
|
||||
if ($wordmark) {
|
||||
$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.');
|
||||
|
@ -179,11 +151,65 @@ final class PhabricatorGuideQuickStartModule extends PhabricatorGuideModule {
|
|||
->setHref($href)
|
||||
->setIcon($icon)
|
||||
->setIconBackground($icon_bg)
|
||||
->setSkipHref($skip)
|
||||
->setDescription($description);
|
||||
$guide_items->addItem($item);
|
||||
|
||||
return $guide_items;
|
||||
$title = pht('Explore Applications');
|
||||
$href = PhabricatorEnv::getURI('/applications/');
|
||||
$icon = 'fa-globe';
|
||||
$icon_bg = 'bg-sky';
|
||||
$description =
|
||||
pht('See all the applications included in Phabricator.');
|
||||
|
||||
$item = id(new PhabricatorGuideItemView())
|
||||
->setTitle($title)
|
||||
->setHref($href)
|
||||
->setIcon($icon)
|
||||
->setIconBackground($icon_bg)
|
||||
->setDescription($description);
|
||||
$guide_items->addItem($item);
|
||||
|
||||
if (!$instance) {
|
||||
$title = pht('Invite Collaborators');
|
||||
$people_check = id(new PhabricatorPeopleQuery())
|
||||
->setViewer($viewer)
|
||||
->execute();
|
||||
$people = count($people_check);
|
||||
$href = PhabricatorEnv::getURI('/people/invite/send/');
|
||||
if ($people > 1) {
|
||||
$icon = 'fa-check';
|
||||
$icon_bg = 'bg-green';
|
||||
$description = pht(
|
||||
'Your invitations have been accepted. You will not be alone on '.
|
||||
'this journey.');
|
||||
} else {
|
||||
$icon = 'fa-group';
|
||||
$icon_bg = 'bg-sky';
|
||||
$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)
|
||||
->setDescription($description);
|
||||
$guide_items->addItem($item);
|
||||
|
||||
$intro = pht(
|
||||
'If your new to Phabricator, these optional steps can help you learn '.
|
||||
'the basics. Conceptually, Phabricator is structured as a graph, and '.
|
||||
'repositories, tasks, and projects are all independent from each other. '.
|
||||
'Feel free to set up Phabricator for how you work best, and explore '.
|
||||
'these features at your own pace.');
|
||||
|
||||
$intro = new PHUIRemarkupView($viewer, $intro);
|
||||
$intro = id(new PHUIDocumentViewPro())
|
||||
->appendChild($intro);
|
||||
|
||||
return array($intro, $guide_items);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorGuideWelcomeModule extends PhabricatorGuideModule {
|
||||
|
||||
public function getModuleKey() {
|
||||
return 'welcome';
|
||||
}
|
||||
|
||||
public function getModuleName() {
|
||||
return pht('Welcome');
|
||||
}
|
||||
|
||||
public function getModulePosition() {
|
||||
return 10;
|
||||
}
|
||||
|
||||
public function renderModuleStatus(AphrontRequest $request) {
|
||||
$viewer = $request->getViewer();
|
||||
|
||||
$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**.');
|
||||
|
||||
$content = new PHUIRemarkupView($viewer, $content);
|
||||
|
||||
return id(new PHUIDocumentViewPro())
|
||||
->appendChild($content);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -224,7 +224,7 @@ abstract class HeraldAdapter extends Phobject {
|
|||
return $this->isTestAdapterForObject($object);
|
||||
}
|
||||
|
||||
public function newTestAdapter($object) {
|
||||
public function newTestAdapter(PhabricatorUser $viewer, $object) {
|
||||
return id(clone $this)
|
||||
->setObject($object);
|
||||
}
|
||||
|
|
|
@ -142,7 +142,9 @@ final class HeraldTestConsoleController extends HeraldController {
|
|||
|
||||
if ($request->isFormPost() && $adapter_key) {
|
||||
if (isset($can_select[$adapter_key])) {
|
||||
$adapter = $can_select[$adapter_key]->newTestAdapter($object);
|
||||
$adapter = $can_select[$adapter_key]->newTestAdapter(
|
||||
$viewer,
|
||||
$object);
|
||||
$this->setTestAdapter($adapter);
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -209,7 +209,7 @@ final class PhabricatorHomeMainController extends PhabricatorHomeController {
|
|||
$content = pht(<<<EOT
|
||||
Welcome to Phabricator, here are some links to get you started:
|
||||
- [[ /config/ | Configure Phabricator ]]
|
||||
- [[ /config/welcome/ | Quick Start Guide ]]
|
||||
- [[ /guides/ | Quick Start Guide ]]
|
||||
- [[ /diffusion/ | Create a Repository ]]
|
||||
- [[ /people/invite/send/ | Invite People ]]
|
||||
- [[ https://twitter.com/phabricator/ | Follow us on Twitter ]]
|
||||
|
@ -218,7 +218,7 @@ EOT
|
|||
} else {
|
||||
$content = pht(<<<EOT
|
||||
Welcome to Phabricator, here are some links to get you started:
|
||||
- [[ /config/welcome/ | Quick Start Guide ]]
|
||||
- [[ /guides/ | Quick Start Guide ]]
|
||||
- [[ /diffusion/ | Create a Repository ]]
|
||||
- [[ https://twitter.com/phabricator/ | Follow us on Twitter ]]
|
||||
EOT
|
||||
|
|
|
@ -27,6 +27,12 @@ final class PhabricatorApplicationDatasource
|
|||
if (!$uri) {
|
||||
continue;
|
||||
}
|
||||
$is_installed = PhabricatorApplication::isClassInstalledForViewer(
|
||||
get_class($application),
|
||||
$viewer);
|
||||
if (!$is_installed) {
|
||||
continue;
|
||||
}
|
||||
$name = $application->getName().' '.$application->getShortDescription();
|
||||
$img = 'phui-font-fa phui-icon-view '.$application->getIcon();
|
||||
$results[] = id(new PhabricatorTypeaheadResult())
|
||||
|
|
|
@ -358,6 +358,13 @@ final class PhabricatorOwnersPackageQuery
|
|||
$best_match = null;
|
||||
$include = false;
|
||||
|
||||
// If this package is archived, it's no longer a controlling package
|
||||
// for the given path. In particular, it can not force active packages
|
||||
// with weak dominion to give up control.
|
||||
if ($package->isArchived()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($package->getPaths() as $package_path) {
|
||||
if ($package_path->getRepositoryPHID() != $repository_phid) {
|
||||
// If this path is for some other repository, skip it.
|
||||
|
|
|
@ -211,10 +211,13 @@ final class PhabricatorOwnersPackage
|
|||
$conn,
|
||||
'SELECT pkg.id, pkg.dominion, p.excluded, p.path
|
||||
FROM %T pkg JOIN %T p ON p.packageID = pkg.id
|
||||
WHERE p.path IN (%Ls) %Q',
|
||||
WHERE p.path IN (%Ls) AND pkg.status IN (%Ls) %Q',
|
||||
$package->getTableName(),
|
||||
$path->getTableName(),
|
||||
$chunk,
|
||||
array(
|
||||
self::STATUS_ACTIVE,
|
||||
),
|
||||
$repository_clause);
|
||||
}
|
||||
$rows = array_mergev($rows);
|
||||
|
|
|
@ -21,40 +21,35 @@ final class PhamePostEditController extends PhamePostController {
|
|||
$post = id(new PhamePostQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($id))
|
||||
->requireCapabilities(
|
||||
array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
PhabricatorPolicyCapability::CAN_EDIT,
|
||||
))
|
||||
->executeOne();
|
||||
if (!$post) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
$blog_id = $post->getBlog()->getID();
|
||||
$blog = $post->getBlog();
|
||||
} else {
|
||||
$blog_id = head($request->getArr('blog'));
|
||||
if (!$blog_id) {
|
||||
$blog_id = $request->getStr('blog');
|
||||
}
|
||||
}
|
||||
|
||||
$query = id(new PhameBlogQuery())
|
||||
->setViewer($viewer)
|
||||
->requireCapabilities(
|
||||
array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
PhabricatorPolicyCapability::CAN_EDIT,
|
||||
));
|
||||
$query = id(new PhameBlogQuery())
|
||||
->setViewer($viewer)
|
||||
->requireCapabilities(
|
||||
array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
PhabricatorPolicyCapability::CAN_EDIT,
|
||||
));
|
||||
|
||||
if (ctype_digit($blog_id)) {
|
||||
$query->withIDs(array($blog_id));
|
||||
} else {
|
||||
$query->withPHIDs(array($blog_id));
|
||||
}
|
||||
if (ctype_digit($blog_id)) {
|
||||
$query->withIDs(array($blog_id));
|
||||
} else {
|
||||
$query->withPHIDs(array($blog_id));
|
||||
}
|
||||
|
||||
$blog = $query->executeOne();
|
||||
if (!$blog) {
|
||||
return new Aphront404Response();
|
||||
$blog = $query->executeOne();
|
||||
if (!$blog) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
}
|
||||
|
||||
$this->setBlog($blog);
|
||||
|
|
|
@ -306,12 +306,23 @@ final class PhrictionDocumentController
|
|||
->setWorkflow(true));
|
||||
}
|
||||
|
||||
return
|
||||
$action_view->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName(pht('View History'))
|
||||
->setIcon('fa-list')
|
||||
->setHref(PhrictionDocument::getSlugURI($slug, 'history')));
|
||||
$action_view->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName(pht('View History'))
|
||||
->setIcon('fa-list')
|
||||
->setHref(PhrictionDocument::getSlugURI($slug, 'history')));
|
||||
|
||||
$print_uri = PhrictionDocument::getSlugURI($slug).'?__print__=1';
|
||||
|
||||
$action_view->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName(pht('Printable Page'))
|
||||
->setIcon('fa-print')
|
||||
->setOpenInNewWindow(true)
|
||||
->setHref($print_uri));
|
||||
|
||||
return $action_view;
|
||||
|
||||
}
|
||||
|
||||
private function renderDocumentChildren($slug) {
|
||||
|
|
|
@ -9,6 +9,7 @@ final class PhrictionEditController
|
|||
|
||||
$current_version = null;
|
||||
if ($id) {
|
||||
$is_new = false;
|
||||
$document = id(new PhrictionDocumentQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($id))
|
||||
|
@ -54,9 +55,11 @@ final class PhrictionEditController
|
|||
if ($document) {
|
||||
$content = $document->getContent();
|
||||
$current_version = $content->getVersion();
|
||||
$is_new = false;
|
||||
} else {
|
||||
$document = PhrictionDocument::initializeNewDocument($viewer, $slug);
|
||||
$content = $document->getContent();
|
||||
$is_new = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -91,11 +94,7 @@ final class PhrictionEditController
|
|||
$draft_note->setSeverity(PHUIInfoView::SEVERITY_NOTICE);
|
||||
$draft_note->setTitle(pht('Recovered Draft'));
|
||||
$draft_note->appendChild(
|
||||
hsprintf(
|
||||
'<p>%s</p>',
|
||||
pht(
|
||||
'Showing a saved draft of your edits, you can %s.',
|
||||
$discard)));
|
||||
pht('Showing a saved draft of your edits, you can %s.', $discard));
|
||||
} else {
|
||||
$content_text = $content->getContent();
|
||||
$draft_note = null;
|
||||
|
@ -112,6 +111,15 @@ final class PhrictionEditController
|
|||
$v_cc = PhabricatorSubscribersQuery::loadSubscribersForPHID(
|
||||
$document->getPHID());
|
||||
|
||||
if ($is_new) {
|
||||
$v_projects = array();
|
||||
} else {
|
||||
$v_projects = PhabricatorEdgeQuery::loadDestinationPHIDs(
|
||||
$document->getPHID(),
|
||||
PhabricatorProjectObjectHasProjectEdgeType::EDGECONST);
|
||||
$v_projects = array_reverse($v_projects);
|
||||
}
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
|
||||
$title = $request->getStr('title');
|
||||
|
@ -120,7 +128,8 @@ final class PhrictionEditController
|
|||
$current_version = $request->getInt('contentVersion');
|
||||
$v_view = $request->getStr('viewPolicy');
|
||||
$v_edit = $request->getStr('editPolicy');
|
||||
$v_cc = $request->getArr('cc');
|
||||
$v_cc = $request->getArr('cc');
|
||||
$v_projects = $request->getArr('projects');
|
||||
|
||||
$xactions = array();
|
||||
$xactions[] = id(new PhrictionTransaction())
|
||||
|
@ -139,6 +148,12 @@ final class PhrictionEditController
|
|||
->setTransactionType(PhabricatorTransactions::TYPE_SUBSCRIBERS)
|
||||
->setNewValue(array('=' => $v_cc));
|
||||
|
||||
$proj_edge_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST;
|
||||
$xactions[] = id(new PhrictionTransaction())
|
||||
->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
|
||||
->setMetadataValue('edge:type', $proj_edge_type)
|
||||
->setNewValue(array('=' => array_fuse($v_projects)));
|
||||
|
||||
$editor = id(new PhrictionTransactionEditor())
|
||||
->setActor($viewer)
|
||||
->setContentSourceFromRequest($request)
|
||||
|
@ -230,6 +245,12 @@ final class PhrictionEditController
|
|||
->setName('content')
|
||||
->setID('document-textarea')
|
||||
->setUser($viewer))
|
||||
->appendControl(
|
||||
id(new AphrontFormTokenizerControl())
|
||||
->setLabel(pht('Tags'))
|
||||
->setName('projects')
|
||||
->setValue($v_projects)
|
||||
->setDatasource(new PhabricatorProjectDatasource()))
|
||||
->appendControl(
|
||||
id(new AphrontFormTokenizerControl())
|
||||
->setLabel(pht('Subscribers'))
|
||||
|
|
|
@ -80,13 +80,14 @@ final class PhrictionTransactionEditor
|
|||
public function getTransactionTypes() {
|
||||
$types = parent::getTransactionTypes();
|
||||
|
||||
$types[] = PhabricatorTransactions::TYPE_COMMENT;
|
||||
$types[] = PhrictionTransaction::TYPE_TITLE;
|
||||
$types[] = PhrictionTransaction::TYPE_CONTENT;
|
||||
$types[] = PhrictionTransaction::TYPE_DELETE;
|
||||
$types[] = PhrictionTransaction::TYPE_MOVE_TO;
|
||||
$types[] = PhrictionTransaction::TYPE_MOVE_AWAY;
|
||||
|
||||
$types[] = PhabricatorTransactions::TYPE_EDGE;
|
||||
$types[] = PhabricatorTransactions::TYPE_COMMENT;
|
||||
$types[] = PhabricatorTransactions::TYPE_VIEW_POLICY;
|
||||
$types[] = PhabricatorTransactions::TYPE_EDIT_POLICY;
|
||||
|
||||
|
@ -428,6 +429,13 @@ final class PhrictionTransactionEditor
|
|||
PhabricatorEnv::getProductionURI($this->contentDiffURI));
|
||||
}
|
||||
|
||||
$description = $object->getContent()->getDescription();
|
||||
if (strlen($description)) {
|
||||
$body->addTextSection(
|
||||
pht('EDIT NOTES'),
|
||||
$description);
|
||||
}
|
||||
|
||||
$body->addLinkSection(
|
||||
pht('DOCUMENT DETAIL'),
|
||||
PhabricatorEnv::getProductionURI(
|
||||
|
|
|
@ -17,8 +17,6 @@ final class PhrictionDocumentQuery
|
|||
const STATUS_OPEN = 'status-open';
|
||||
const STATUS_NONSTUB = 'status-nonstub';
|
||||
|
||||
const ORDER_CREATED = 'order-created';
|
||||
const ORDER_UPDATED = 'order-updated';
|
||||
const ORDER_HIERARCHY = 'order-hierarchy';
|
||||
|
||||
public function withIDs(array $ids) {
|
||||
|
@ -61,38 +59,15 @@ final class PhrictionDocumentQuery
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function setOrder($order) {
|
||||
switch ($order) {
|
||||
case self::ORDER_CREATED:
|
||||
$this->setOrderVector(array('id'));
|
||||
break;
|
||||
case self::ORDER_UPDATED:
|
||||
$this->setOrderVector(array('updated'));
|
||||
break;
|
||||
case self::ORDER_HIERARCHY:
|
||||
$this->setOrderVector(array('depth', 'title', 'updated'));
|
||||
break;
|
||||
default:
|
||||
throw new Exception(pht('Unknown order "%s".', $order));
|
||||
}
|
||||
|
||||
return $this;
|
||||
protected function loadPage() {
|
||||
return $this->loadStandardPage($this->newResultObject());
|
||||
}
|
||||
|
||||
protected function loadPage() {
|
||||
$table = new PhrictionDocument();
|
||||
$conn_r = $table->establishConnection('r');
|
||||
public function newResultObject() {
|
||||
return new PhrictionDocument();
|
||||
}
|
||||
|
||||
$rows = queryfx_all(
|
||||
$conn_r,
|
||||
'SELECT d.* FROM %T d %Q %Q %Q %Q',
|
||||
$table->getTableName(),
|
||||
$this->buildJoinClause($conn_r),
|
||||
$this->buildWhereClause($conn_r),
|
||||
$this->buildOrderClause($conn_r),
|
||||
$this->buildLimitClause($conn_r));
|
||||
|
||||
$documents = $table->loadAllFromArray($rows);
|
||||
protected function willFilterPage(array $documents) {
|
||||
|
||||
if ($documents) {
|
||||
$ancestor_slugs = array();
|
||||
|
@ -104,6 +79,8 @@ final class PhrictionDocumentQuery
|
|||
}
|
||||
|
||||
if ($ancestor_slugs) {
|
||||
$table = new PhrictionDocument();
|
||||
$conn_r = $table->establishConnection('r');
|
||||
$ancestors = queryfx_all(
|
||||
$conn_r,
|
||||
'SELECT * FROM %T WHERE slug IN (%Ls)',
|
||||
|
@ -122,11 +99,6 @@ final class PhrictionDocumentQuery
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $documents;
|
||||
}
|
||||
|
||||
protected function willFilterPage(array $documents) {
|
||||
// To view a Phriction document, you must also be able to view all of the
|
||||
// ancestor documents. Filter out documents which have ancestors that are
|
||||
// not visible.
|
||||
|
@ -190,58 +162,59 @@ final class PhrictionDocumentQuery
|
|||
return $documents;
|
||||
}
|
||||
|
||||
protected function buildJoinClause(AphrontDatabaseConnection $conn) {
|
||||
$join = '';
|
||||
protected function buildJoinClauseParts(AphrontDatabaseConnection $conn) {
|
||||
$joins = array();
|
||||
|
||||
if ($this->getOrderVector()->containsKey('updated')) {
|
||||
$content_dao = new PhrictionContent();
|
||||
$join = qsprintf(
|
||||
$joins[] = qsprintf(
|
||||
$conn,
|
||||
'JOIN %T c ON d.contentID = c.id',
|
||||
$content_dao->getTableName());
|
||||
}
|
||||
|
||||
return $join;
|
||||
return $joins;
|
||||
}
|
||||
protected function buildWhereClause(AphrontDatabaseConnection $conn) {
|
||||
$where = array();
|
||||
|
||||
if ($this->ids) {
|
||||
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
|
||||
$where = parent::buildWhereClauseParts($conn);
|
||||
|
||||
if ($this->ids !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'd.id IN (%Ld)',
|
||||
$this->ids);
|
||||
}
|
||||
|
||||
if ($this->phids) {
|
||||
if ($this->phids !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'd.phid IN (%Ls)',
|
||||
$this->phids);
|
||||
}
|
||||
|
||||
if ($this->slugs) {
|
||||
if ($this->slugs !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'd.slug IN (%Ls)',
|
||||
$this->slugs);
|
||||
}
|
||||
|
||||
if ($this->statuses) {
|
||||
if ($this->statuses !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'd.status IN (%Ld)',
|
||||
$this->statuses);
|
||||
}
|
||||
|
||||
if ($this->slugPrefix) {
|
||||
if ($this->slugPrefix !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'd.slug LIKE %>',
|
||||
$this->slugPrefix);
|
||||
}
|
||||
|
||||
if ($this->depths) {
|
||||
if ($this->depths !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'd.depth IN (%Ld)',
|
||||
|
@ -274,9 +247,16 @@ final class PhrictionDocumentQuery
|
|||
throw new Exception(pht("Unknown status '%s'!", $this->status));
|
||||
}
|
||||
|
||||
$where[] = $this->buildPagingClause($conn);
|
||||
return $where;
|
||||
}
|
||||
|
||||
return $this->formatWhereClause($where);
|
||||
public function getBuiltinOrders() {
|
||||
return array(
|
||||
self::ORDER_HIERARCHY => array(
|
||||
'vector' => array('depth', 'title', 'updated'),
|
||||
'name' => pht('Hierarchy'),
|
||||
),
|
||||
) + parent::getBuiltinOrders();
|
||||
}
|
||||
|
||||
public function getOrderableColumns() {
|
||||
|
@ -331,6 +311,9 @@ final class PhrictionDocumentQuery
|
|||
}
|
||||
}
|
||||
|
||||
protected function getPrimaryTableAlias() {
|
||||
return 'd';
|
||||
}
|
||||
|
||||
public function getQueryApplicationClass() {
|
||||
return 'PhabricatorPhrictionApplication';
|
||||
|
|
|
@ -11,52 +11,29 @@ final class PhrictionSearchEngine
|
|||
return 'PhabricatorPhrictionApplication';
|
||||
}
|
||||
|
||||
public function buildSavedQueryFromRequest(AphrontRequest $request) {
|
||||
$saved = new PhabricatorSavedQuery();
|
||||
|
||||
$saved->setParameter('status', $request->getStr('status'));
|
||||
$saved->setParameter('order', $request->getStr('order'));
|
||||
|
||||
return $saved;
|
||||
}
|
||||
|
||||
public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) {
|
||||
$query = id(new PhrictionDocumentQuery())
|
||||
public function newQuery() {
|
||||
return id(new PhrictionDocumentQuery())
|
||||
->needContent(true)
|
||||
->withStatus(PhrictionDocumentQuery::STATUS_NONSTUB);
|
||||
}
|
||||
|
||||
$status = $saved->getParameter('status');
|
||||
$status = idx($this->getStatusValues(), $status);
|
||||
if ($status) {
|
||||
$query->withStatus($status);
|
||||
}
|
||||
protected function buildQueryFromParameters(array $map) {
|
||||
$query = $this->newQuery();
|
||||
|
||||
$order = $saved->getParameter('order');
|
||||
$order = idx($this->getOrderValues(), $order);
|
||||
if ($order) {
|
||||
$query->setOrder($order);
|
||||
if ($map['status']) {
|
||||
$query->withStatus($map['status']);
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
public function buildSearchForm(
|
||||
AphrontFormView $form,
|
||||
PhabricatorSavedQuery $saved_query) {
|
||||
|
||||
$form
|
||||
->appendChild(
|
||||
id(new AphrontFormSelectControl())
|
||||
->setLabel(pht('Status'))
|
||||
->setName('status')
|
||||
->setOptions($this->getStatusOptions())
|
||||
->setValue($saved_query->getParameter('status')))
|
||||
->appendChild(
|
||||
id(new AphrontFormSelectControl())
|
||||
->setLabel(pht('Order'))
|
||||
->setName('order')
|
||||
->setOptions($this->getOrderOptions())
|
||||
->setValue($saved_query->getParameter('order')));
|
||||
protected function buildCustomSearchFields() {
|
||||
return array(
|
||||
id(new PhabricatorSearchSelectField())
|
||||
->setKey('status')
|
||||
->setLabel(pht('Status'))
|
||||
->setOptions($this->getStatusOptions()),
|
||||
);
|
||||
}
|
||||
|
||||
protected function getURI($path) {
|
||||
|
@ -66,7 +43,6 @@ final class PhrictionSearchEngine
|
|||
protected function getBuiltinQueryNames() {
|
||||
$names = array(
|
||||
'active' => pht('Active'),
|
||||
'updated' => pht('Updated'),
|
||||
'all' => pht('All'),
|
||||
);
|
||||
|
||||
|
@ -79,12 +55,11 @@ final class PhrictionSearchEngine
|
|||
$query->setQueryKey($query_key);
|
||||
|
||||
switch ($query_key) {
|
||||
case 'active':
|
||||
return $query->setParameter('status', 'active');
|
||||
case 'all':
|
||||
return $query;
|
||||
case 'updated':
|
||||
return $query->setParameter('order', 'updated');
|
||||
case 'active':
|
||||
return $query->setParameter(
|
||||
'status', PhrictionDocumentQuery::STATUS_OPEN);
|
||||
}
|
||||
|
||||
return parent::buildSavedQueryFromBuiltin($query_key);
|
||||
|
@ -92,29 +67,8 @@ final class PhrictionSearchEngine
|
|||
|
||||
private function getStatusOptions() {
|
||||
return array(
|
||||
'active' => pht('Show Active Documents'),
|
||||
'all' => pht('Show All Documents'),
|
||||
);
|
||||
}
|
||||
|
||||
private function getStatusValues() {
|
||||
return array(
|
||||
'active' => PhrictionDocumentQuery::STATUS_OPEN,
|
||||
'all' => PhrictionDocumentQuery::STATUS_NONSTUB,
|
||||
);
|
||||
}
|
||||
|
||||
private function getOrderOptions() {
|
||||
return array(
|
||||
'created' => pht('Date Created'),
|
||||
'updated' => pht('Date Updated'),
|
||||
);
|
||||
}
|
||||
|
||||
private function getOrderValues() {
|
||||
return array(
|
||||
'created' => PhrictionDocumentQuery::ORDER_CREATED,
|
||||
'updated' => PhrictionDocumentQuery::ORDER_UPDATED,
|
||||
PhrictionDocumentQuery::STATUS_OPEN => pht('Show Active Documents'),
|
||||
PhrictionDocumentQuery::STATUS_NONSTUB => pht('Show All Documents'),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,8 +7,9 @@ final class PhrictionDocument extends PhrictionDAO
|
|||
PhabricatorFlaggableInterface,
|
||||
PhabricatorTokenReceiverInterface,
|
||||
PhabricatorDestructibleInterface,
|
||||
PhabricatorApplicationTransactionInterface,
|
||||
PhabricatorFulltextInterface {
|
||||
PhabricatorFulltextInterface,
|
||||
PhabricatorProjectInterface,
|
||||
PhabricatorApplicationTransactionInterface {
|
||||
|
||||
protected $slug;
|
||||
protected $depth;
|
||||
|
|
|
@ -123,18 +123,23 @@ final class PhabricatorPhurlURLEditor
|
|||
foreach ($xactions as $xaction) {
|
||||
if ($xaction->getOldValue() != $xaction->getNewValue()) {
|
||||
$new_alias = $xaction->getNewValue();
|
||||
$debug_alias = new PHUIInvisibleCharacterView($new_alias);
|
||||
if (!preg_match('/[a-zA-Z]/', $new_alias)) {
|
||||
$errors[] = new PhabricatorApplicationTransactionValidationError(
|
||||
$type,
|
||||
pht('Invalid Alias'),
|
||||
pht('The alias must contain at least one letter.'),
|
||||
pht('The alias you provided (%s) must contain at least one '.
|
||||
'letter.',
|
||||
$debug_alias),
|
||||
$xaction);
|
||||
}
|
||||
if (preg_match('/[^a-z0-9]/i', $new_alias)) {
|
||||
$errors[] = new PhabricatorApplicationTransactionValidationError(
|
||||
$type,
|
||||
pht('Invalid Alias'),
|
||||
pht('The alias may only contain letters and numbers.'),
|
||||
pht('The alias you provided (%s) may only contain letters and '.
|
||||
'numbers.',
|
||||
$debug_alias),
|
||||
$xaction);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -126,7 +126,7 @@ final class PhabricatorProjectTransaction
|
|||
return 'fa-unlock';
|
||||
}
|
||||
case self::TYPE_ICON:
|
||||
return $new;
|
||||
return PhabricatorProjectIconSet::getIconIcon($new);
|
||||
case self::TYPE_IMAGE:
|
||||
return 'fa-photo';
|
||||
case self::TYPE_MEMBERS:
|
||||
|
|
|
@ -77,11 +77,6 @@ final class PhabricatorRepositoryCommitOwnersWorker
|
|||
continue;
|
||||
}
|
||||
|
||||
if ($package->isArchived()) {
|
||||
// Don't trigger audits if the package is archived.
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($package->getAuditingEnabled()) {
|
||||
$reasons = $this->checkAuditReasons(
|
||||
$commit,
|
||||
|
|
|
@ -1094,6 +1094,22 @@ abstract class PhabricatorApplicationSearchEngine extends Phobject {
|
|||
}
|
||||
}
|
||||
|
||||
$valid_constraints = array();
|
||||
foreach ($fields as $field) {
|
||||
foreach ($field->getValidConstraintKeys() as $key) {
|
||||
$valid_constraints[$key] = true;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($constraints as $key => $constraint) {
|
||||
if (empty($valid_constraints[$key])) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Constraint "%s" is not a valid constraint for this query.',
|
||||
$key));
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($fields as $field) {
|
||||
if (!$field->getValueExistsInConduitRequest($constraints)) {
|
||||
continue;
|
||||
|
|
|
@ -329,6 +329,11 @@ abstract class PhabricatorSearchField extends Phobject {
|
|||
$this->getConduitKey());
|
||||
}
|
||||
|
||||
public function getValidConstraintKeys() {
|
||||
return $this->getConduitParameterType()->getKeys(
|
||||
$this->getConduitKey());
|
||||
}
|
||||
|
||||
|
||||
/* -( Utility Methods )----------------------------------------------------- */
|
||||
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorConpherenceWidgetVisibleSetting
|
||||
extends PhabricatorInternalSetting {
|
||||
|
||||
const SETTINGKEY = 'conpherence-widget';
|
||||
|
||||
public function getSettingName() {
|
||||
return pht('Conpherence Widget Pane Visible');
|
||||
}
|
||||
|
||||
}
|
|
@ -34,15 +34,15 @@ final class PhabricatorMonospacedFontSetting
|
|||
throw new Exception(
|
||||
pht(
|
||||
'Monospaced font value "%s" is unsafe. You may only enter '.
|
||||
'letters, numbers, spaces, commas, periods, forward slashes '.
|
||||
'and double quotes.',
|
||||
'letters, numbers, spaces, commas, periods, hyphens, '.
|
||||
'forward slashes, and double quotes',
|
||||
$value));
|
||||
}
|
||||
}
|
||||
|
||||
public static function filterMonospacedCSSRule($monospaced) {
|
||||
// Prevent the user from doing dangerous things.
|
||||
return preg_replace('([^a-z0-9 ,"./]+)i', '', $monospaced);
|
||||
return preg_replace('([^a-z0-9 ,"./-]+)i', '', $monospaced);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ bug, not a configuration problem.
|
|||
However, some pages are slow because Phabricator legitimately needs to do a lot
|
||||
of work to generate them. For example, if you write a 100MB wiki document,
|
||||
Phabricator will need substantial time to process it, it will take a long time
|
||||
to download over the network, and your browser will proably not be able to
|
||||
to download over the network, and your browser will probably not be able to
|
||||
render it especially quickly.
|
||||
|
||||
We may be able to improve perfomance in some cases, but Phabricator is not
|
||||
|
|
|
@ -143,7 +143,7 @@ Almanac namespaces allow you to control who can create services and devices
|
|||
with certain names.
|
||||
|
||||
If you keep a list of cattle as devices with names like
|
||||
`cow001.herd.myranch.com`, `cow002.herd.myranch.moo`, you might have some
|
||||
`cow001.herd.myranch.moo`, `cow002.herd.myranch.moo`, you might have some
|
||||
applications which query for all devices in `*.herd.myranch.moo`, and thus
|
||||
want to limit who can create devices there in order to prevent mistakes.
|
||||
|
||||
|
|
|
@ -688,6 +688,32 @@ In general:
|
|||
- The `type` option can be set to `instructions` to indicate that an element
|
||||
is asking the user to make a choice or follow specific instructions.
|
||||
|
||||
Keystrokes
|
||||
==========
|
||||
|
||||
You can use `{key ...}` to render a stylized keystroke. For example, this:
|
||||
|
||||
```
|
||||
Press {key M} to view the starmap.
|
||||
```
|
||||
|
||||
...renders this:
|
||||
|
||||
> Press {key M} to view the starmap.
|
||||
|
||||
You can also render sequences with modifier keys. This:
|
||||
|
||||
```
|
||||
Use {key command option shift 3} to take a screenshot.
|
||||
Press {key down down-right right LP} to activate the hadoken technique.
|
||||
```
|
||||
|
||||
...renders this:
|
||||
|
||||
> Use {key command option shift 3} to take a screenshot.
|
||||
> Press {key down down-right right LP} to activate the hadoken technique.
|
||||
|
||||
|
||||
= Fullscreen Mode =
|
||||
|
||||
Remarkup editors provide a fullscreen composition mode. This can make it easier
|
||||
|
|
|
@ -47,7 +47,12 @@ final class PhabricatorStandardCustomFieldLink
|
|||
PhabricatorCursorPagedPolicyAwareQuery $query,
|
||||
$value) {
|
||||
|
||||
if (strlen($value)) {
|
||||
if (is_string($value) && !strlen($value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$value = (array)$value;
|
||||
if ($value) {
|
||||
$query->withApplicationSearchContainsConstraint(
|
||||
$this->newStringIndex(null),
|
||||
$value);
|
||||
|
|
8
src/infrastructure/env/PhabricatorEnv.php
vendored
8
src/infrastructure/env/PhabricatorEnv.php
vendored
|
@ -315,6 +315,14 @@ final class PhabricatorEnv extends Phobject {
|
|||
* @task read
|
||||
*/
|
||||
public static function getEnvConfig($key) {
|
||||
if (!self::$sourceStack) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Trying to read configuration "%s" before configuration has been '.
|
||||
'initialized.',
|
||||
$key));
|
||||
}
|
||||
|
||||
if (isset(self::$cache[$key])) {
|
||||
return self::$cache[$key];
|
||||
}
|
||||
|
|
|
@ -505,6 +505,7 @@ final class PhabricatorMarkupEngine extends Phobject {
|
|||
|
||||
$rules[] = new PhutilRemarkupDocumentLinkRule();
|
||||
$rules[] = new PhabricatorNavigationRemarkupRule();
|
||||
$rules[] = new PhabricatorKeyboardRemarkupRule();
|
||||
|
||||
if ($options['youtube']) {
|
||||
$rules[] = new PhabricatorYoutubeRemarkupRule();
|
||||
|
|
|
@ -0,0 +1,256 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorKeyboardRemarkupRule extends PhutilRemarkupRule {
|
||||
|
||||
public function getPriority() {
|
||||
return 200.0;
|
||||
}
|
||||
|
||||
public function apply($text) {
|
||||
return preg_replace_callback(
|
||||
'@{key\b((?:[^}\\\\]+|\\\\.)*)}@m',
|
||||
array($this, 'markupKeystrokes'),
|
||||
$text);
|
||||
}
|
||||
|
||||
public function markupKeystrokes(array $matches) {
|
||||
if (!$this->isFlatText($matches[0])) {
|
||||
return $matches[0];
|
||||
}
|
||||
|
||||
$keys = explode(' ', $matches[1]);
|
||||
foreach ($keys as $k => $v) {
|
||||
$v = trim($v, " \n");
|
||||
$v = preg_replace('/\\\\(.)/', '\\1', $v);
|
||||
if (!strlen($v)) {
|
||||
unset($keys[$k]);
|
||||
continue;
|
||||
}
|
||||
$keys[$k] = $v;
|
||||
}
|
||||
|
||||
$special = array(
|
||||
array(
|
||||
'name' => pht('Command'),
|
||||
'symbol' => "\xE2\x8C\x98",
|
||||
'aliases' => array(
|
||||
'cmd',
|
||||
'command',
|
||||
),
|
||||
),
|
||||
array(
|
||||
'name' => pht('Option'),
|
||||
'symbol' => "\xE2\x8C\xA5",
|
||||
'aliases' => array(
|
||||
'opt',
|
||||
'option',
|
||||
),
|
||||
),
|
||||
array(
|
||||
'name' => pht('Shift'),
|
||||
'symbol' => "\xE2\x87\xA7",
|
||||
'aliases' => array(
|
||||
'shift',
|
||||
),
|
||||
),
|
||||
array(
|
||||
'name' => pht('Escape'),
|
||||
'symbol' => "\xE2\x8E\x8B",
|
||||
'aliases' => array(
|
||||
'esc',
|
||||
'escape',
|
||||
),
|
||||
),
|
||||
array(
|
||||
'name' => pht('Up'),
|
||||
'symbol' => "\xE2\x86\x91",
|
||||
'heavy' => "\xE2\xAC\x86",
|
||||
'aliases' => array(
|
||||
'up',
|
||||
'arrow-up',
|
||||
'up-arrow',
|
||||
'north',
|
||||
),
|
||||
),
|
||||
array(
|
||||
'name' => pht('Tab'),
|
||||
'symbol' => "\xE2\x87\xA5",
|
||||
'aliases' => array(
|
||||
'tab',
|
||||
),
|
||||
),
|
||||
array(
|
||||
'name' => pht('Right'),
|
||||
'symbol' => "\xE2\x86\x92",
|
||||
'heavy' => "\xE2\x9E\xA1",
|
||||
'aliases' => array(
|
||||
'right',
|
||||
'right-arrow',
|
||||
'arrow-right',
|
||||
'east',
|
||||
),
|
||||
),
|
||||
array(
|
||||
'name' => pht('Left'),
|
||||
'symbol' => "\xE2\x86\x90",
|
||||
'heavy' => "\xE2\xAC\x85",
|
||||
'aliases' => array(
|
||||
'left',
|
||||
'left-arrow',
|
||||
'arrow-left',
|
||||
'west',
|
||||
),
|
||||
),
|
||||
array(
|
||||
'name' => pht('Down'),
|
||||
'symbol' => "\xE2\x86\x93",
|
||||
'heavy' => "\xE2\xAC\x87",
|
||||
'aliases' => array(
|
||||
'down',
|
||||
'down-arrow',
|
||||
'arrow-down',
|
||||
'south',
|
||||
),
|
||||
),
|
||||
array(
|
||||
'name' => pht('Up Right'),
|
||||
'symbol' => "\xE2\x86\x97",
|
||||
'heavy' => "\xE2\xAC\x88",
|
||||
'aliases' => array(
|
||||
'up-right',
|
||||
'upright',
|
||||
'up-right-arrow',
|
||||
'upright-arrow',
|
||||
'arrow-up-right',
|
||||
'arrow-upright',
|
||||
'northeast',
|
||||
'north-east',
|
||||
),
|
||||
),
|
||||
array(
|
||||
'name' => pht('Down Right'),
|
||||
'symbol' => "\xE2\x86\x98",
|
||||
'heavy' => "\xE2\xAC\x8A",
|
||||
'aliases' => array(
|
||||
'down-right',
|
||||
'downright',
|
||||
'down-right-arrow',
|
||||
'downright-arrow',
|
||||
'arrow-down-right',
|
||||
'arrow-downright',
|
||||
'southeast',
|
||||
'south-east',
|
||||
),
|
||||
),
|
||||
array(
|
||||
'name' => pht('Down Left'),
|
||||
'symbol' => "\xE2\x86\x99",
|
||||
'heavy' => "\xE2\xAC\x8B",
|
||||
'aliases' => array(
|
||||
'down-left',
|
||||
'downleft',
|
||||
'down-left-arrow',
|
||||
'downleft-arrow',
|
||||
'arrow-down-left',
|
||||
'arrow-downleft',
|
||||
'southwest',
|
||||
'south-west',
|
||||
),
|
||||
),
|
||||
array(
|
||||
'name' => pht('Up Left'),
|
||||
'symbol' => "\xE2\x86\x96",
|
||||
'heavy' => "\xE2\xAC\x89",
|
||||
'aliases' => array(
|
||||
'up-left',
|
||||
'upleft',
|
||||
'up-left-arrow',
|
||||
'upleft-arrow',
|
||||
'arrow-up-left',
|
||||
'arrow-upleft',
|
||||
'northwest',
|
||||
'north-west',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$map = array();
|
||||
foreach ($special as $spec) {
|
||||
foreach ($spec['aliases'] as $alias) {
|
||||
$map[$alias] = $spec;
|
||||
}
|
||||
}
|
||||
|
||||
$is_text = $this->getEngine()->isTextMode();
|
||||
$is_html_mail = $this->getEngine()->isHTMLMailMode();
|
||||
|
||||
if ($is_html_mail) {
|
||||
$key_style = array(
|
||||
'display: inline-block;',
|
||||
'min-width: 1em;',
|
||||
'padding: 4px 5px 5px;',
|
||||
'font-weight: normal;',
|
||||
'font-size: 0.8rem;',
|
||||
'text-align: center;',
|
||||
'text-decoration: none;',
|
||||
'line-height: 0.6rem;',
|
||||
'border-radius: 3px;',
|
||||
'box-shadow: inset 0 -1px 0 rgba(71, 87, 120, 0.08);',
|
||||
'user-select: none;',
|
||||
'background: #f7f7f7;',
|
||||
'border: 1px solid #C7CCD9;',
|
||||
);
|
||||
$key_style = implode(' ', $key_style);
|
||||
|
||||
$join_style = array(
|
||||
'padding: 0 4px;',
|
||||
'color: #92969D;',
|
||||
);
|
||||
$join_style = implode(' ', $join_style);
|
||||
} else {
|
||||
$key_style = null;
|
||||
$join_style = null;
|
||||
}
|
||||
|
||||
$parts = array();
|
||||
foreach ($keys as $k => $v) {
|
||||
$normal = phutil_utf8_strtolower($v);
|
||||
if (isset($map[$normal])) {
|
||||
$spec = $map[$normal];
|
||||
} else {
|
||||
$spec = array(
|
||||
'name' => null,
|
||||
'symbol' => $v,
|
||||
);
|
||||
}
|
||||
|
||||
if ($is_text) {
|
||||
$parts[] = '['.$spec['symbol'].']';
|
||||
} else {
|
||||
$parts[] = phutil_tag(
|
||||
'kbd',
|
||||
array(
|
||||
'title' => $spec['name'],
|
||||
'style' => $key_style,
|
||||
),
|
||||
$spec['symbol']);
|
||||
}
|
||||
}
|
||||
|
||||
if ($is_text) {
|
||||
$parts = implode(' + ', $parts);
|
||||
} else {
|
||||
$glue = phutil_tag(
|
||||
'span',
|
||||
array(
|
||||
'class' => 'kbd-join',
|
||||
'style' => $join_style,
|
||||
),
|
||||
'+');
|
||||
$parts = phutil_implode_html($glue, $parts);
|
||||
}
|
||||
|
||||
return $this->getEngine()->storeText($parts);
|
||||
}
|
||||
|
||||
}
|
|
@ -67,7 +67,7 @@ abstract class PhabricatorLiskDAO extends LiskDAO {
|
|||
$connection = $this->newBasicConnection($database, $mode, $namespace);
|
||||
}
|
||||
|
||||
// TODO: This should be testing if the mode is "r", but that would proably
|
||||
// TODO: This should be testing if the mode is "r", but that would probably
|
||||
// break a lot of things. Perform a more narrow test for readonly mode
|
||||
// until we have greater certainty that this works correctly most of the
|
||||
// time.
|
||||
|
|
|
@ -8,6 +8,8 @@ abstract class PhabricatorStorageManagementWorkflow
|
|||
private $force;
|
||||
private $patches;
|
||||
|
||||
private $didInitialize;
|
||||
|
||||
final public function getAPI() {
|
||||
return $this->api;
|
||||
}
|
||||
|
@ -176,12 +178,16 @@ abstract class PhabricatorStorageManagementWorkflow
|
|||
"%s\n",
|
||||
pht('DRYRUN: Would apply adjustments.'));
|
||||
return 0;
|
||||
} else if ($this->didInitialize) {
|
||||
// If we just initialized the database, continue without prompting. This
|
||||
// is nicer for first-time setup and there's no reasonable reason any
|
||||
// user would ever answer "no" to the prompt against an empty schema.
|
||||
} else if (!$this->force) {
|
||||
$console->writeOut(
|
||||
"\n%s\n",
|
||||
pht(
|
||||
"Found %s issues(s) with schemata, detailed above.\n\n".
|
||||
"You can review issues in more detail from the web interface, ".
|
||||
"Found %s adjustment(s) to apply, detailed above.\n\n".
|
||||
"You can review adjustments in more detail from the web interface, ".
|
||||
"in Config > Database Status. To better understand the adjustment ".
|
||||
"workflow, see \"Managing Storage Adjustments\" in the ".
|
||||
"documentation.\n\n".
|
||||
|
@ -189,7 +195,7 @@ abstract class PhabricatorStorageManagementWorkflow
|
|||
"migrations may take some time.",
|
||||
phutil_count($adjustments)));
|
||||
|
||||
$prompt = pht('Fix these schema issues?');
|
||||
$prompt = pht('Apply these schema adjustments?');
|
||||
if (!phutil_console_confirm($prompt, $default_no = true)) {
|
||||
return 1;
|
||||
}
|
||||
|
@ -197,7 +203,7 @@ abstract class PhabricatorStorageManagementWorkflow
|
|||
|
||||
$console->writeOut(
|
||||
"%s\n",
|
||||
pht('Fixing schema issues...'));
|
||||
pht('Applying schema adjustments...'));
|
||||
|
||||
$conn = $api->getConn(null);
|
||||
|
||||
|
@ -368,7 +374,7 @@ abstract class PhabricatorStorageManagementWorkflow
|
|||
if (!$failed) {
|
||||
$console->writeOut(
|
||||
"%s\n",
|
||||
pht('Completed fixing all schema issues.'));
|
||||
pht('Completed applying all schema adjustments.'));
|
||||
|
||||
$err = 0;
|
||||
} else {
|
||||
|
@ -800,6 +806,11 @@ abstract class PhabricatorStorageManagementWorkflow
|
|||
return 1;
|
||||
}
|
||||
|
||||
// If we're initializing storage for the first time, track it so that
|
||||
// we can give the user a nicer experience during the subsequent
|
||||
// adjustment phase.
|
||||
$this->didInitialize = true;
|
||||
|
||||
$legacy = $api->getLegacyPatches($this->patches);
|
||||
if ($legacy || $no_quickstart || $init_only) {
|
||||
|
||||
|
|
|
@ -95,9 +95,9 @@ final class AphrontSideNavFilterView extends AphrontView {
|
|||
return $this->menu;
|
||||
}
|
||||
|
||||
public function addFilter($key, $name, $uri = null) {
|
||||
public function addFilter($key, $name, $uri = null, $icon = null) {
|
||||
return $this->addThing(
|
||||
$key, $name, $uri, PHUIListItemView::TYPE_LINK);
|
||||
$key, $name, $uri, PHUIListItemView::TYPE_LINK, $icon);
|
||||
}
|
||||
|
||||
public function addButton($key, $name, $uri = null) {
|
||||
|
@ -105,11 +105,15 @@ final class AphrontSideNavFilterView extends AphrontView {
|
|||
$key, $name, $uri, PHUIListItemView::TYPE_BUTTON);
|
||||
}
|
||||
|
||||
private function addThing($key, $name, $uri, $type) {
|
||||
private function addThing($key, $name, $uri, $type, $icon) {
|
||||
$item = id(new PHUIListItemView())
|
||||
->setName($name)
|
||||
->setType($type);
|
||||
|
||||
if (strlen($icon)) {
|
||||
$item->setIcon($icon);
|
||||
}
|
||||
|
||||
|
||||
if (strlen($key)) {
|
||||
$item->setKey($key);
|
||||
|
|
|
@ -45,7 +45,9 @@ final class PHUIIconCircleView extends AphrontTagView {
|
|||
$classes[] = 'phui-icon-circle';
|
||||
|
||||
if ($this->color) {
|
||||
$classes[] = 'phui-icon-circle-'.$this->color;
|
||||
$classes[] = 'hover-'.$this->color;
|
||||
} else {
|
||||
$classes[] = 'hover-sky';
|
||||
}
|
||||
|
||||
if ($this->size) {
|
||||
|
@ -60,8 +62,7 @@ final class PHUIIconCircleView extends AphrontTagView {
|
|||
|
||||
protected function getTagContent() {
|
||||
return id(new PHUIIconView())
|
||||
->setIcon($this->icon)
|
||||
->addClass($this->color);
|
||||
->setIcon($this->icon);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
94
src/view/phui/PHUIInvisibleCharacterView.php
Normal file
94
src/view/phui/PHUIInvisibleCharacterView.php
Normal file
|
@ -0,0 +1,94 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* API for replacing whitespace characters and some control characters with
|
||||
* their printable representations. This is useful for debugging and
|
||||
* displaying more helpful error messages to users.
|
||||
*
|
||||
*/
|
||||
final class PHUIInvisibleCharacterView extends AphrontView {
|
||||
|
||||
private $inputText;
|
||||
private $plainText = false;
|
||||
|
||||
// This is a list of the common invisible characters that are
|
||||
// actually typeable. Other invisible characters will simply
|
||||
// be displayed as their hex representations.
|
||||
private static $invisibleChars = array(
|
||||
"\x00" => 'NULL',
|
||||
"\t" => 'TAB',
|
||||
"\n" => 'NEWLINE',
|
||||
"\x20" => 'SPACE',
|
||||
);
|
||||
|
||||
public function __construct($input_text) {
|
||||
$this->inputText = $input_text;
|
||||
}
|
||||
|
||||
public function setPlainText($plain_text) {
|
||||
$this->plainText = $plain_text;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getStringParts() {
|
||||
$input_text = $this->inputText;
|
||||
$text_array = phutil_utf8v($input_text);
|
||||
|
||||
for ($ii = 0; $ii < count($text_array); $ii++) {
|
||||
$char = $text_array[$ii];
|
||||
$char_hex = bin2hex($char);
|
||||
if (array_key_exists($char, self::$invisibleChars)) {
|
||||
$text_array[$ii] = array(
|
||||
'special' => true,
|
||||
'value' => '<'.self::$invisibleChars[$char].'>',
|
||||
);
|
||||
} else if (ord($char) < 32) {
|
||||
$text_array[$ii] = array(
|
||||
'special' => true,
|
||||
'value' => '<0x'.$char_hex.'>',
|
||||
);
|
||||
} else {
|
||||
$text_array[$ii] = array(
|
||||
'special' => false,
|
||||
'value' => $char,
|
||||
);
|
||||
}
|
||||
}
|
||||
return $text_array;
|
||||
}
|
||||
|
||||
private function renderHtmlArray() {
|
||||
$html_array = array();
|
||||
$parts = $this->getStringParts();
|
||||
foreach ($parts as $part) {
|
||||
if ($part['special']) {
|
||||
$html_array[] = phutil_tag(
|
||||
'span',
|
||||
array('class' => 'invisible-special'),
|
||||
$part['value']);
|
||||
} else {
|
||||
$html_array[] = $part['value'];
|
||||
}
|
||||
}
|
||||
return $html_array;
|
||||
}
|
||||
|
||||
private function renderPlainText() {
|
||||
$parts = $this->getStringParts();
|
||||
$res = '';
|
||||
foreach ($parts as $part) {
|
||||
$res .= $part['value'];
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
require_celerity_resource('phui-invisible-character-view-css');
|
||||
if ($this->plainText) {
|
||||
return $this->renderPlainText();
|
||||
} else {
|
||||
return $this->renderHtmlArray();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
52
src/view/phui/__tests__/PHUIInvisibleCharacterTestCase.php
Normal file
52
src/view/phui/__tests__/PHUIInvisibleCharacterTestCase.php
Normal file
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
|
||||
final class PHUIInvisibleCharacterTestCase extends PhabricatorTestCase {
|
||||
|
||||
public function testEmptyString() {
|
||||
$view = new PHUIInvisibleCharacterView('');
|
||||
$res = $view->render();
|
||||
$this->assertEqual($res, array());
|
||||
}
|
||||
|
||||
public function testEmptyPlainText() {
|
||||
$view = (new PHUIInvisibleCharacterView(''))
|
||||
->setPlainText(true);
|
||||
$res = $view->render();
|
||||
$this->assertEqual($res, '');
|
||||
}
|
||||
|
||||
public function testWithNamedChars() {
|
||||
$test_input = "\x00\n\t ";
|
||||
$view = (new PHUIInvisibleCharacterView($test_input))
|
||||
->setPlainText(true);
|
||||
$res = $view->render();
|
||||
$this->assertEqual($res, '<NULL><NEWLINE><TAB><SPACE>');
|
||||
}
|
||||
|
||||
public function testWithHexChars() {
|
||||
$test_input = "abc\x01";
|
||||
$view = (new PHUIInvisibleCharacterView($test_input))
|
||||
->setPlainText(true);
|
||||
$res = $view->render();
|
||||
$this->assertEqual($res, 'abc<0x01>');
|
||||
}
|
||||
|
||||
public function testWithNamedAsHex() {
|
||||
$test_input = "\x00\x0a\x09\x20";
|
||||
$view = (new PHUIInvisibleCharacterView($test_input))
|
||||
->setPlainText(true);
|
||||
$res = $view->render();
|
||||
$this->assertEqual($res, '<NULL><NEWLINE><TAB><SPACE>');
|
||||
}
|
||||
|
||||
public function testHtmlDecoration() {
|
||||
$test_input = "a\x00\n\t ";
|
||||
$view = new PHUIInvisibleCharacterView($test_input);
|
||||
$res = $view->render();
|
||||
$this->assertFalse($res[0] instanceof PhutilSafeHTML);
|
||||
$this->assertTrue($res[1] instanceof PhutilSafeHTML);
|
||||
$this->assertTrue($res[2] instanceof PhutilSafeHTML);
|
||||
$this->assertTrue($res[3] instanceof PhutilSafeHTML);
|
||||
$this->assertTrue($res[4] instanceof PhutilSafeHTML);
|
||||
}
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue