diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 2eeba419ee..8649bdf11b 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -9,8 +9,8 @@ return array( 'names' => array( 'conpherence.pkg.css' => '0b64e988', 'conpherence.pkg.js' => '6249a1cf', - 'core.pkg.css' => '9c725fa0', - 'core.pkg.js' => 'a2ead3fe', + 'core.pkg.css' => 'e75e4f9d', + 'core.pkg.js' => '2291d3b2', 'darkconsole.pkg.js' => 'e7393ebb', 'differential.pkg.css' => '9535a7e6', 'differential.pkg.js' => 'ddfeb49b', @@ -21,7 +21,7 @@ return array( 'maniphest.pkg.js' => '5ab2753f', 'rsrc/css/aphront/aphront-bars.css' => '231ac33c', 'rsrc/css/aphront/dark-console.css' => 'f54bf286', - 'rsrc/css/aphront/dialog-view.css' => '938f52c5', + 'rsrc/css/aphront/dialog-view.css' => '5e5aa60b', 'rsrc/css/aphront/list-filter-view.css' => '5d6f0526', 'rsrc/css/aphront/multi-column.css' => '84cc6640', 'rsrc/css/aphront/notification.css' => '3f6c89c9', @@ -34,8 +34,8 @@ 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' => 'f03e17be', - 'rsrc/css/application/base/notification-menu.css' => '1e055865', + 'rsrc/css/application/base/main-menu-view.css' => '8eac4166', + 'rsrc/css/application/base/notification-menu.css' => '6a697e43', 'rsrc/css/application/base/phabricator-application-launch-view.css' => '95351601', 'rsrc/css/application/base/phui-theme.css' => '798c69b8', 'rsrc/css/application/base/standard-page-view.css' => '894d8a25', @@ -96,7 +96,7 @@ return array( 'rsrc/css/application/policy/policy-transaction-detail.css' => '82100a43', 'rsrc/css/application/policy/policy.css' => '957ea14c', 'rsrc/css/application/ponder/ponder-view.css' => 'fbd45f96', - 'rsrc/css/application/project/project-card-view.css' => '9418c97d', + 'rsrc/css/application/project/project-card-view.css' => 'd27c67ae', 'rsrc/css/application/project/project-view.css' => '1e6f7072', 'rsrc/css/application/releeph/releeph-core.css' => '9b3c5733', 'rsrc/css/application/releeph/releeph-preview-branch.css' => 'b7a6f4a5', @@ -108,7 +108,7 @@ 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' => 'aebc1180', + 'rsrc/css/core/remarkup.css' => '4a2de2bb', 'rsrc/css/core/syntax.css' => '769d3498', 'rsrc/css/core/z-index.css' => '5e72c4e0', 'rsrc/css/diviner/diviner-shared.css' => 'aa3656aa', @@ -128,29 +128,29 @@ return array( 'rsrc/css/phui/object-item/phui-oi-flush-ui.css' => '9d9685d6', 'rsrc/css/phui/object-item/phui-oi-list-view.css' => 'bff632a4', 'rsrc/css/phui/object-item/phui-oi-simple-ui.css' => 'a8beebea', - 'rsrc/css/phui/phui-action-list.css' => 'e1d48300', + 'rsrc/css/phui/phui-action-list.css' => '5679229f', 'rsrc/css/phui/phui-action-panel.css' => '91c7b835', 'rsrc/css/phui/phui-badge.css' => '3baef8db', 'rsrc/css/phui/phui-basic-nav-view.css' => '7093573b', 'rsrc/css/phui/phui-big-info-view.css' => 'bd903741', 'rsrc/css/phui/phui-box.css' => '33b629f8', - 'rsrc/css/phui/phui-button.css' => '43f4912e', + 'rsrc/css/phui/phui-button.css' => '9718cb0c', 'rsrc/css/phui/phui-chart.css' => '6bf6f78e', 'rsrc/css/phui/phui-cms.css' => 'be43c8a8', 'rsrc/css/phui/phui-comment-form.css' => '48fbd65d', 'rsrc/css/phui/phui-comment-panel.css' => 'f50152ad', 'rsrc/css/phui/phui-crumbs-view.css' => 'f82868f2', 'rsrc/css/phui/phui-curtain-view.css' => '947bf1a4', - 'rsrc/css/phui/phui-document-pro.css' => 'c354e312', + 'rsrc/css/phui/phui-document-pro.css' => 'f56738ed', 'rsrc/css/phui/phui-document-summary.css' => '9ca48bdf', 'rsrc/css/phui/phui-document.css' => 'c32e8dec', 'rsrc/css/phui/phui-feed-story.css' => '44a9c8e9', 'rsrc/css/phui/phui-fontkit.css' => '9cda225e', - 'rsrc/css/phui/phui-form-view.css' => '04cc4771', + 'rsrc/css/phui/phui-form-view.css' => 'adca31ce', 'rsrc/css/phui/phui-form.css' => '2342b0e5', 'rsrc/css/phui/phui-head-thing.css' => 'fd311e5f', 'rsrc/css/phui/phui-header-view.css' => '6ec8f155', - 'rsrc/css/phui/phui-hovercard.css' => 'de1a2119', + 'rsrc/css/phui/phui-hovercard.css' => 'e904f5dc', 'rsrc/css/phui/phui-icon-set-selector.css' => '1ab67aad', 'rsrc/css/phui/phui-icon.css' => '09f46dd9', 'rsrc/css/phui/phui-image-mask.css' => 'a8498f9c', @@ -162,7 +162,7 @@ return array( 'rsrc/css/phui/phui-object-box.css' => '6b487c57', 'rsrc/css/phui/phui-pager.css' => 'bea33d23', 'rsrc/css/phui/phui-pinboard-view.css' => '2495140e', - 'rsrc/css/phui/phui-profile-menu.css' => '4768721a', + 'rsrc/css/phui/phui-profile-menu.css' => 'c71ecdcd', 'rsrc/css/phui/phui-property-list-view.css' => '6d8e58ac', 'rsrc/css/phui/phui-remarkup-preview.css' => '1a8f2591', 'rsrc/css/phui/phui-segment-bar-view.css' => '46342871', @@ -170,10 +170,10 @@ return array( 'rsrc/css/phui/phui-status.css' => 'd5263e49', 'rsrc/css/phui/phui-tag-view.css' => '84d65f26', 'rsrc/css/phui/phui-timeline-view.css' => 'bc523970', - 'rsrc/css/phui/phui-two-column-view.css' => '7babf5b9', + 'rsrc/css/phui/phui-two-column-view.css' => 'a0d3858a', 'rsrc/css/phui/workboards/phui-workboard-color.css' => 'b60ef38a', - 'rsrc/css/phui/workboards/phui-workboard.css' => '16441d5e', - 'rsrc/css/phui/workboards/phui-workcard.css' => '00979e40', + 'rsrc/css/phui/workboards/phui-workboard.css' => 'c88912ee', + 'rsrc/css/phui/workboards/phui-workcard.css' => 'cca5fa92', 'rsrc/css/phui/workboards/phui-workpanel.css' => 'a3a63478', 'rsrc/css/sprite-login.css' => '587d92d7', 'rsrc/css/sprite-tokens.css' => '9cdfd599', @@ -374,7 +374,7 @@ return array( 'rsrc/image/texture/table_header_hover.png' => '038ec3b9', 'rsrc/image/texture/table_header_tall.png' => 'd56b434f', 'rsrc/js/application/aphlict/Aphlict.js' => '5359e785', - 'rsrc/js/application/aphlict/behavior-aphlict-dropdown.js' => '2a171a9d', + 'rsrc/js/application/aphlict/behavior-aphlict-dropdown.js' => 'caade6f2', 'rsrc/js/application/aphlict/behavior-aphlict-listen.js' => 'fb20ac8d', 'rsrc/js/application/aphlict/behavior-aphlict-status.js' => '5e2634b9', 'rsrc/js/application/aphlict/behavior-desktop-notifications-control.js' => 'edd1ba66', @@ -443,7 +443,7 @@ return array( 'rsrc/js/application/projects/WorkboardCard.js' => 'c587b80f', 'rsrc/js/application/projects/WorkboardColumn.js' => '21df4ff5', 'rsrc/js/application/projects/WorkboardController.js' => '55baf5ed', - 'rsrc/js/application/projects/behavior-project-boards.js' => '14a1faae', + 'rsrc/js/application/projects/behavior-project-boards.js' => '93ae974f', 'rsrc/js/application/projects/behavior-project-create.js' => '065227cc', 'rsrc/js/application/projects/behavior-reorder-columns.js' => 'e1d25dfb', 'rsrc/js/application/releeph/releeph-preview-branch.js' => 'b2b4fbaf', @@ -453,7 +453,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' => 'b52947eb', + 'rsrc/js/application/transactions/behavior-comment-actions.js' => '9a6dd75c', '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', @@ -530,18 +530,18 @@ return array( 'rsrc/js/core/behavior-toggle-class.js' => '92b9ec77', 'rsrc/js/core/behavior-tokenizer.js' => 'b3a4b884', 'rsrc/js/core/behavior-tooltip.js' => '42fcb747', + 'rsrc/js/core/behavior-user-menu.js' => '31420f77', 'rsrc/js/core/behavior-watch-anchor.js' => '9f36c42d', 'rsrc/js/core/behavior-workflow.js' => '0a3f3021', 'rsrc/js/core/phtize.js' => 'd254d646', - 'rsrc/js/phui/behavior-phui-dropdown-menu.js' => '1aa4c968', + 'rsrc/js/phui/behavior-phui-dropdown-menu.js' => 'b95d6f7d', 'rsrc/js/phui/behavior-phui-file-upload.js' => 'b003d4fb', - 'rsrc/js/phui/behavior-phui-profile-menu.js' => '12884df9', 'rsrc/js/phui/behavior-phui-submenu.js' => 'a6f7a73b', 'rsrc/js/phui/behavior-phui-tab-group.js' => '0a0b10e9', 'rsrc/js/phuix/PHUIXActionListView.js' => 'b5c256b8', - 'rsrc/js/phuix/PHUIXActionView.js' => '8cf6d262', + 'rsrc/js/phuix/PHUIXActionView.js' => 'b3465b9b', 'rsrc/js/phuix/PHUIXAutocomplete.js' => '6d86ce8b', - 'rsrc/js/phuix/PHUIXDropdownMenu.js' => '82e270da', + 'rsrc/js/phuix/PHUIXDropdownMenu.js' => '8018ee50', 'rsrc/js/phuix/PHUIXFormControl.js' => 'bbece68d', 'rsrc/js/phuix/PHUIXIconView.js' => 'bff6884b', ), @@ -549,7 +549,7 @@ return array( 'almanac-css' => 'dbb9b3af', 'aphront-bars' => '231ac33c', 'aphront-dark-console-css' => 'f54bf286', - 'aphront-dialog-view-css' => '938f52c5', + 'aphront-dialog-view-css' => '5e5aa60b', 'aphront-list-filter-view-css' => '5d6f0526', 'aphront-multi-column-view-css' => '84cc6640', 'aphront-panel-view-css' => '8427b78d', @@ -596,7 +596,7 @@ return array( 'inline-comment-summary-css' => '51efda3a', 'javelin-aphlict' => '5359e785', 'javelin-behavior' => '61cbc29a', - 'javelin-behavior-aphlict-dropdown' => '2a171a9d', + 'javelin-behavior-aphlict-dropdown' => 'caade6f2', 'javelin-behavior-aphlict-listen' => 'fb20ac8d', 'javelin-behavior-aphlict-status' => '5e2634b9', 'javelin-behavior-aphront-basic-tokenizer' => 'b3a4b884', @@ -609,7 +609,7 @@ return array( 'javelin-behavior-bulk-job-reload' => 'edf8a145', 'javelin-behavior-calendar-month-view' => 'fe33e256', 'javelin-behavior-choose-control' => '327a00d1', - 'javelin-behavior-comment-actions' => 'b52947eb', + 'javelin-behavior-comment-actions' => '9a6dd75c', 'javelin-behavior-config-reorder-fields' => 'b6993408', 'javelin-behavior-conpherence-menu' => '7524fcfa', 'javelin-behavior-conpherence-participant-pane' => '8604caa8', @@ -687,15 +687,14 @@ return array( 'javelin-behavior-phabricator-watch-anchor' => '9f36c42d', 'javelin-behavior-pholio-mock-edit' => 'bee502c8', 'javelin-behavior-pholio-mock-view' => 'fbe497e7', - 'javelin-behavior-phui-dropdown-menu' => '1aa4c968', + 'javelin-behavior-phui-dropdown-menu' => 'b95d6f7d', 'javelin-behavior-phui-file-upload' => 'b003d4fb', 'javelin-behavior-phui-hovercards' => 'bcaccd64', - 'javelin-behavior-phui-profile-menu' => '12884df9', 'javelin-behavior-phui-submenu' => 'a6f7a73b', 'javelin-behavior-phui-tab-group' => '0a0b10e9', 'javelin-behavior-policy-control' => 'd0c516d5', 'javelin-behavior-policy-rule-editor' => '5e9f347c', - 'javelin-behavior-project-boards' => '14a1faae', + 'javelin-behavior-project-boards' => '93ae974f', 'javelin-behavior-project-create' => '065227cc', 'javelin-behavior-quicksand-blacklist' => '7927a7d3', 'javelin-behavior-read-only-warning' => 'ba158207', @@ -721,6 +720,7 @@ return array( 'javelin-behavior-toggle-widget' => '3dbf94d5', 'javelin-behavior-typeahead-browse' => '635de1ec', 'javelin-behavior-typeahead-search' => '93d0c9e3', + 'javelin-behavior-user-menu' => '31420f77', 'javelin-behavior-view-placeholder' => '47830651', 'javelin-behavior-workflow' => '0a3f3021', 'javelin-color' => '7e41274a', @@ -780,7 +780,7 @@ return array( 'paste-css' => '1898e534', 'path-typeahead' => 'f7fc67ec', 'people-profile-css' => '2473d929', - 'phabricator-action-list-view-css' => 'e1d48300', + 'phabricator-action-list-view-css' => '5679229f', 'phabricator-application-launch-view-css' => '95351601', 'phabricator-busy' => '59a7976a', 'phabricator-chatlog-css' => 'd295b020', @@ -798,15 +798,15 @@ return array( 'phabricator-flag-css' => 'bba8f811', 'phabricator-keyboard-shortcut' => '1ae869f2', 'phabricator-keyboard-shortcut-manager' => '4a021c10', - 'phabricator-main-menu-view' => 'f03e17be', + 'phabricator-main-menu-view' => '8eac4166', 'phabricator-nav-view-css' => 'b29426e9', 'phabricator-notification' => 'ccf1cbf8', 'phabricator-notification-css' => '3f6c89c9', - 'phabricator-notification-menu-css' => '1e055865', + 'phabricator-notification-menu-css' => '6a697e43', 'phabricator-object-selector-css' => '85ee8ce6', 'phabricator-phtize' => 'd254d646', 'phabricator-prefab' => '8d40ae75', - 'phabricator-remarkup-css' => 'aebc1180', + 'phabricator-remarkup-css' => '4a2de2bb', 'phabricator-search-results-css' => '64ad079a', 'phabricator-shaped-request' => '7cbe244b', 'phabricator-slowvote-css' => 'a94b7230', @@ -842,7 +842,7 @@ return array( 'phui-basic-nav-view-css' => '7093573b', 'phui-big-info-view-css' => 'bd903741', 'phui-box-css' => '33b629f8', - 'phui-button-css' => '43f4912e', + 'phui-button-css' => '9718cb0c', 'phui-calendar-css' => '477acfaa', 'phui-calendar-day-css' => '572b1893', 'phui-calendar-list-css' => 'fcc9fb41', @@ -855,16 +855,16 @@ return array( 'phui-curtain-view-css' => '947bf1a4', 'phui-document-summary-view-css' => '9ca48bdf', 'phui-document-view-css' => 'c32e8dec', - 'phui-document-view-pro-css' => 'c354e312', + 'phui-document-view-pro-css' => 'f56738ed', 'phui-feed-story-css' => '44a9c8e9', 'phui-font-icon-base-css' => '870a7360', 'phui-fontkit-css' => '9cda225e', 'phui-form-css' => '2342b0e5', - 'phui-form-view-css' => '04cc4771', + 'phui-form-view-css' => 'adca31ce', 'phui-head-thing-view-css' => 'fd311e5f', 'phui-header-view-css' => '6ec8f155', 'phui-hovercard' => '1bd28176', - 'phui-hovercard-view-css' => 'de1a2119', + 'phui-hovercard-view-css' => 'e904f5dc', 'phui-icon-set-selector-css' => '1ab67aad', 'phui-icon-view-css' => '09f46dd9', 'phui-image-mask-css' => 'a8498f9c', @@ -883,7 +883,7 @@ return array( 'phui-oi-simple-ui-css' => 'a8beebea', 'phui-pager-css' => 'bea33d23', 'phui-pinboard-view-css' => '2495140e', - 'phui-profile-menu-css' => '4768721a', + 'phui-profile-menu-css' => 'c71ecdcd', 'phui-property-list-view-css' => '6d8e58ac', 'phui-remarkup-preview-css' => '1a8f2591', 'phui-segment-bar-view-css' => '46342871', @@ -892,22 +892,22 @@ return array( 'phui-tag-view-css' => '84d65f26', 'phui-theme-css' => '798c69b8', 'phui-timeline-view-css' => 'bc523970', - 'phui-two-column-view-css' => '7babf5b9', + 'phui-two-column-view-css' => 'a0d3858a', 'phui-workboard-color-css' => 'b60ef38a', - 'phui-workboard-view-css' => '16441d5e', - 'phui-workcard-view-css' => '00979e40', + 'phui-workboard-view-css' => 'c88912ee', + 'phui-workcard-view-css' => 'cca5fa92', 'phui-workpanel-view-css' => 'a3a63478', 'phuix-action-list-view' => 'b5c256b8', - 'phuix-action-view' => '8cf6d262', + 'phuix-action-view' => 'b3465b9b', 'phuix-autocomplete' => '6d86ce8b', - 'phuix-dropdown-menu' => '82e270da', + 'phuix-dropdown-menu' => '8018ee50', 'phuix-form-control-view' => 'bbece68d', 'phuix-icon-view' => 'bff6884b', 'policy-css' => '957ea14c', 'policy-edit-css' => '815c66f7', 'policy-transaction-detail-css' => '82100a43', 'ponder-view-css' => 'fbd45f96', - 'project-card-view-css' => '9418c97d', + 'project-card-view-css' => 'd27c67ae', 'project-view-css' => '1e6f7072', 'releeph-core' => '9b3c5733', 'releeph-preview-branch' => 'b7a6f4a5', @@ -1030,11 +1030,6 @@ return array( 'javelin-dom', 'javelin-typeahead-normalizer', ), - '12884df9' => array( - 'javelin-behavior', - 'javelin-stratcom', - 'javelin-dom', - ), '13c739ea' => array( 'javelin-behavior', 'javelin-stratcom', @@ -1049,27 +1044,12 @@ return array( 'javelin-dom', 'javelin-history', ), - '14a1faae' => array( - 'javelin-behavior', - 'javelin-dom', - 'javelin-util', - 'javelin-vector', - 'javelin-stratcom', - 'javelin-workflow', - 'javelin-workboard-controller', - ), '185bbd53' => array( 'javelin-install', ), '19f9369b' => array( 'phui-oi-list-view-css', ), - '1aa4c968' => array( - 'javelin-behavior', - 'javelin-stratcom', - 'javelin-dom', - 'phuix-dropdown-menu', - ), '1ad0a787' => array( 'javelin-install', 'javelin-reactor', @@ -1127,17 +1107,6 @@ return array( 'javelin-install', 'javelin-util', ), - '2a171a9d' => array( - 'javelin-behavior', - 'javelin-request', - 'javelin-stratcom', - 'javelin-vector', - 'javelin-dom', - 'javelin-uri', - 'javelin-behavior-device', - 'phabricator-title', - 'phabricator-favicon', - ), '2b8de964' => array( 'javelin-install', 'javelin-util', @@ -1157,6 +1126,9 @@ return array( '2ee659ce' => array( 'javelin-install', ), + '31420f77' => array( + 'javelin-behavior', + ), '320810c8' => array( 'javelin-install', 'javelin-dom', @@ -1538,6 +1510,13 @@ return array( 'javelin-behavior', 'javelin-history', ), + '8018ee50' => array( + 'javelin-install', + 'javelin-util', + 'javelin-dom', + 'javelin-vector', + 'javelin-stratcom', + ), '805b806a' => array( 'javelin-magical-init', 'javelin-install', @@ -1545,13 +1524,6 @@ return array( 'javelin-vector', 'javelin-stratcom', ), - '82e270da' => array( - 'javelin-install', - 'javelin-util', - 'javelin-dom', - 'javelin-vector', - 'javelin-stratcom', - ), '834a1173' => array( 'javelin-behavior', 'javelin-scrollbar', @@ -1610,11 +1582,6 @@ return array( 'javelin-stratcom', 'javelin-behavior', ), - '8cf6d262' => array( - 'javelin-install', - 'javelin-dom', - 'javelin-util', - ), '8d3bc1b2' => array( 'javelin-dom', 'javelin-util', @@ -1633,6 +1600,9 @@ return array( 'javelin-stratcom', 'javelin-util', ), + '8eac4166' => array( + 'phui-theme-css', + ), '8ff5e24c' => array( 'javelin-behavior', 'javelin-stratcom', @@ -1654,6 +1624,15 @@ return array( 'javelin-stratcom', 'javelin-dom', ), + '93ae974f' => array( + 'javelin-behavior', + 'javelin-dom', + 'javelin-util', + 'javelin-vector', + 'javelin-stratcom', + 'javelin-workflow', + 'javelin-workboard-controller', + ), '93d0c9e3' => array( 'javelin-behavior', 'javelin-stratcom', @@ -1703,6 +1682,15 @@ return array( 'phabricator-phtize', 'changeset-view-manager', ), + '9a6dd75c' => array( + 'javelin-behavior', + 'javelin-stratcom', + 'javelin-workflow', + 'javelin-dom', + 'phuix-form-control-view', + 'phuix-icon-view', + 'javelin-behavior-phabricator-gesture', + ), '9a8cb501' => array( 'aphront-typeahead-control-css', 'phui-tag-view-css', @@ -1859,6 +1847,11 @@ return array( 'javelin-uri', 'javelin-request', ), + 'b3465b9b' => array( + 'javelin-install', + 'javelin-dom', + 'javelin-util', + ), 'b3a4b884' => array( 'javelin-behavior', 'phabricator-prefab', @@ -1872,15 +1865,6 @@ return array( 'javelin-typeahead-preloaded-source', 'javelin-util', ), - 'b52947eb' => array( - 'javelin-behavior', - 'javelin-stratcom', - 'javelin-workflow', - 'javelin-dom', - 'phuix-form-control-view', - 'phuix-icon-view', - 'javelin-behavior-phabricator-gesture', - ), 'b59e1e96' => array( 'javelin-behavior', 'javelin-stratcom', @@ -1911,6 +1895,12 @@ return array( 'javelin-json', 'phabricator-draggable-list', ), + 'b95d6f7d' => array( + 'javelin-behavior', + 'javelin-stratcom', + 'javelin-dom', + 'phuix-dropdown-menu', + ), 'ba158207' => array( 'javelin-behavior', 'javelin-uri', @@ -2003,6 +1993,17 @@ return array( 'javelin-stratcom', 'phabricator-phtize', ), + 'caade6f2' => array( + 'javelin-behavior', + 'javelin-request', + 'javelin-stratcom', + 'javelin-vector', + 'javelin-dom', + 'javelin-uri', + 'javelin-behavior-device', + 'phabricator-title', + 'phabricator-favicon', + ), 'ccf1cbf8' => array( 'javelin-install', 'javelin-dom', @@ -2168,9 +2169,6 @@ return array( 'javelin-workflow', 'javelin-json', ), - 'f03e17be' => array( - 'phui-theme-css', - ), 'f12cbc9f' => array( 'phui-oi-list-view-css', ), @@ -2429,6 +2427,9 @@ return array( 'conpherence-thread-manager', 'javelin-behavior-detect-timezone', 'javelin-behavior-setup-check-https', + 'javelin-behavior-aphlict-status', + 'javelin-behavior-user-menu', + 'phabricator-favicon', ), 'darkconsole.pkg.js' => array( 'javelin-behavior-dark-console', diff --git a/resources/celerity/packages.php b/resources/celerity/packages.php index caa4512e34..288bd69ed2 100644 --- a/resources/celerity/packages.php +++ b/resources/celerity/packages.php @@ -84,6 +84,9 @@ return array( 'conpherence-thread-manager', 'javelin-behavior-detect-timezone', 'javelin-behavior-setup-check-https', + 'javelin-behavior-aphlict-status', + 'javelin-behavior-user-menu', + 'phabricator-favicon', ), 'core.pkg.css' => array( 'phabricator-core-css', diff --git a/resources/sql/autopatches/20170119.menuitem.motivator.01.php b/resources/sql/autopatches/20170119.menuitem.motivator.01.php new file mode 100644 index 0000000000..16a16fe530 --- /dev/null +++ b/resources/sql/autopatches/20170119.menuitem.motivator.01.php @@ -0,0 +1,9 @@ +establishConnection('w'); + +queryfx( + $conn_w, + 'DELETE FROM %T WHERE menuItemKey = "motivator"', + $table->getTableName()); diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 617365f333..c828c6b04e 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -617,6 +617,7 @@ phutil_register_library_map(array( 'DiffusionCommitActionTransaction' => 'applications/diffusion/xaction/DiffusionCommitActionTransaction.php', 'DiffusionCommitAffectedFilesHeraldField' => 'applications/diffusion/herald/DiffusionCommitAffectedFilesHeraldField.php', 'DiffusionCommitAuditTransaction' => 'applications/diffusion/xaction/DiffusionCommitAuditTransaction.php', + 'DiffusionCommitAuditorsHeraldField' => 'applications/diffusion/herald/DiffusionCommitAuditorsHeraldField.php', 'DiffusionCommitAuditorsTransaction' => 'applications/diffusion/xaction/DiffusionCommitAuditorsTransaction.php', 'DiffusionCommitAuthorHeraldField' => 'applications/diffusion/herald/DiffusionCommitAuthorHeraldField.php', 'DiffusionCommitAutocloseHeraldField' => 'applications/diffusion/herald/DiffusionCommitAutocloseHeraldField.php', @@ -629,6 +630,7 @@ phutil_register_library_map(array( 'DiffusionCommitDiffContentHeraldField' => 'applications/diffusion/herald/DiffusionCommitDiffContentHeraldField.php', 'DiffusionCommitDiffContentRemovedHeraldField' => 'applications/diffusion/herald/DiffusionCommitDiffContentRemovedHeraldField.php', 'DiffusionCommitDiffEnormousHeraldField' => 'applications/diffusion/herald/DiffusionCommitDiffEnormousHeraldField.php', + 'DiffusionCommitDraftEngine' => 'applications/diffusion/engine/DiffusionCommitDraftEngine.php', 'DiffusionCommitEditConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionCommitEditConduitAPIMethod.php', 'DiffusionCommitEditController' => 'applications/diffusion/controller/DiffusionCommitEditController.php', 'DiffusionCommitEditEngine' => 'applications/diffusion/editor/DiffusionCommitEditEngine.php', @@ -1697,7 +1699,6 @@ phutil_register_library_map(array( 'PHUIListItemView' => 'view/phui/PHUIListItemView.php', 'PHUIListView' => 'view/phui/PHUIListView.php', 'PHUIListViewTestCase' => 'view/layout/__tests__/PHUIListViewTestCase.php', - 'PHUIMainMenuView' => 'view/phui/PHUIMainMenuView.php', 'PHUIObjectBoxView' => 'view/phui/PHUIObjectBoxView.php', 'PHUIObjectItemListExample' => 'applications/uiexample/examples/PHUIObjectItemListExample.php', 'PHUIObjectItemListView' => 'view/phui/PHUIObjectItemListView.php', @@ -2591,7 +2592,6 @@ phutil_register_library_map(array( 'PhabricatorEditEngineConfigurationTransactionQuery' => 'applications/transactions/query/PhabricatorEditEngineConfigurationTransactionQuery.php', 'PhabricatorEditEngineConfigurationViewController' => 'applications/transactions/controller/PhabricatorEditEngineConfigurationViewController.php', 'PhabricatorEditEngineController' => 'applications/transactions/controller/PhabricatorEditEngineController.php', - 'PhabricatorEditEngineCreateQuickActions' => 'applications/settings/quickmenu/PhabricatorEditEngineCreateQuickActions.php', 'PhabricatorEditEngineDatasource' => 'applications/transactions/typeahead/PhabricatorEditEngineDatasource.php', 'PhabricatorEditEngineExtension' => 'applications/transactions/engineextension/PhabricatorEditEngineExtension.php', 'PhabricatorEditEngineExtensionModule' => 'applications/transactions/engineextension/PhabricatorEditEngineExtensionModule.php', @@ -2669,10 +2669,8 @@ phutil_register_library_map(array( 'PhabricatorFactSpec' => 'applications/fact/spec/PhabricatorFactSpec.php', 'PhabricatorFactUpdateIterator' => 'applications/fact/extract/PhabricatorFactUpdateIterator.php', 'PhabricatorFavoritesApplication' => 'applications/favorites/application/PhabricatorFavoritesApplication.php', - 'PhabricatorFavoritesConstants' => 'applications/favorites/constants/PhabricatorFavoritesConstants.php', 'PhabricatorFavoritesController' => 'applications/favorites/controller/PhabricatorFavoritesController.php', 'PhabricatorFavoritesMainController' => 'applications/favorites/controller/PhabricatorFavoritesMainController.php', - 'PhabricatorFavoritesManageProfileMenuItem' => 'applications/favorites/menuitem/PhabricatorFavoritesManageProfileMenuItem.php', 'PhabricatorFavoritesMenuItemController' => 'applications/favorites/controller/PhabricatorFavoritesMenuItemController.php', 'PhabricatorFavoritesProfileMenuEngine' => 'applications/favorites/engine/PhabricatorFavoritesProfileMenuEngine.php', 'PhabricatorFaxContentSource' => 'infrastructure/contentsource/PhabricatorFaxContentSource.php', @@ -2827,7 +2825,6 @@ phutil_register_library_map(array( 'PhabricatorHelpDocumentationController' => 'applications/help/controller/PhabricatorHelpDocumentationController.php', 'PhabricatorHelpEditorProtocolController' => 'applications/help/controller/PhabricatorHelpEditorProtocolController.php', 'PhabricatorHelpKeyboardShortcutController' => 'applications/help/controller/PhabricatorHelpKeyboardShortcutController.php', - 'PhabricatorHelpMainMenuBarExtension' => 'applications/help/extension/PhabricatorHelpMainMenuBarExtension.php', 'PhabricatorHeraldApplication' => 'applications/herald/application/PhabricatorHeraldApplication.php', 'PhabricatorHeraldContentSource' => 'applications/herald/contentsource/PhabricatorHeraldContentSource.php', 'PhabricatorHighSecurityRequestExceptionHandler' => 'aphront/handler/PhabricatorHighSecurityRequestExceptionHandler.php', @@ -2840,7 +2837,6 @@ phutil_register_library_map(array( 'PhabricatorHomeMenuItemController' => 'applications/home/controller/PhabricatorHomeMenuItemController.php', 'PhabricatorHomePreferencesSettingsPanel' => 'applications/settings/panel/PhabricatorHomePreferencesSettingsPanel.php', 'PhabricatorHomeProfileMenuEngine' => 'applications/home/engine/PhabricatorHomeProfileMenuEngine.php', - 'PhabricatorHomeQuickCreateController' => 'applications/home/controller/PhabricatorHomeQuickCreateController.php', 'PhabricatorHovercardEngineExtension' => 'applications/search/engineextension/PhabricatorHovercardEngineExtension.php', 'PhabricatorHovercardEngineExtensionModule' => 'applications/search/engineextension/PhabricatorHovercardEngineExtensionModule.php', 'PhabricatorIDsSearchEngineExtension' => 'applications/search/engineextension/PhabricatorIDsSearchEngineExtension.php', @@ -3024,7 +3020,6 @@ phutil_register_library_map(array( 'PhabricatorModularTransactionType' => 'applications/transactions/storage/PhabricatorModularTransactionType.php', 'PhabricatorMonospacedFontSetting' => 'applications/settings/setting/PhabricatorMonospacedFontSetting.php', 'PhabricatorMonospacedTextareasSetting' => 'applications/settings/setting/PhabricatorMonospacedTextareasSetting.php', - 'PhabricatorMotivatorProfileMenuItem' => 'applications/search/menuitem/PhabricatorMotivatorProfileMenuItem.php', 'PhabricatorMultiColumnUIExample' => 'applications/uiexample/examples/PhabricatorMultiColumnUIExample.php', 'PhabricatorMultiFactorSettingsPanel' => 'applications/settings/panel/PhabricatorMultiFactorSettingsPanel.php', 'PhabricatorMultimeterApplication' => 'applications/multimeter/application/PhabricatorMultimeterApplication.php', @@ -3316,7 +3311,6 @@ phutil_register_library_map(array( 'PhabricatorPeopleLogQuery' => 'applications/people/query/PhabricatorPeopleLogQuery.php', 'PhabricatorPeopleLogSearchEngine' => 'applications/people/query/PhabricatorPeopleLogSearchEngine.php', 'PhabricatorPeopleLogsController' => 'applications/people/controller/PhabricatorPeopleLogsController.php', - 'PhabricatorPeopleMainMenuBarExtension' => 'applications/people/extension/PhabricatorPeopleMainMenuBarExtension.php', 'PhabricatorPeopleManageProfileMenuItem' => 'applications/people/menuitem/PhabricatorPeopleManageProfileMenuItem.php', 'PhabricatorPeopleNewController' => 'applications/people/controller/PhabricatorPeopleNewController.php', 'PhabricatorPeopleNoOwnerDatasource' => 'applications/people/typeahead/PhabricatorPeopleNoOwnerDatasource.php', @@ -3422,7 +3416,6 @@ phutil_register_library_map(array( 'PhabricatorPolicyTestObject' => 'applications/policy/__tests__/PhabricatorPolicyTestObject.php', 'PhabricatorPolicyType' => 'applications/policy/constants/PhabricatorPolicyType.php', 'PhabricatorPonderApplication' => 'applications/ponder/application/PhabricatorPonderApplication.php', - 'PhabricatorProfileMenuCollapsedSetting' => 'applications/settings/setting/PhabricatorProfileMenuCollapsedSetting.php', 'PhabricatorProfileMenuEditEngine' => 'applications/search/editor/PhabricatorProfileMenuEditEngine.php', 'PhabricatorProfileMenuEditor' => 'applications/search/editor/PhabricatorProfileMenuEditor.php', 'PhabricatorProfileMenuEngine' => 'applications/search/engine/PhabricatorProfileMenuEngine.php', @@ -3562,7 +3555,6 @@ phutil_register_library_map(array( 'PhabricatorQueryOrderItem' => 'infrastructure/query/order/PhabricatorQueryOrderItem.php', 'PhabricatorQueryOrderTestCase' => 'infrastructure/query/order/__tests__/PhabricatorQueryOrderTestCase.php', 'PhabricatorQueryOrderVector' => 'infrastructure/query/order/PhabricatorQueryOrderVector.php', - 'PhabricatorQuickActions' => 'applications/settings/quickmenu/PhabricatorQuickActions.php', 'PhabricatorRateLimitRequestExceptionHandler' => 'aphront/handler/PhabricatorRateLimitRequestExceptionHandler.php', 'PhabricatorRecaptchaConfigOptions' => 'applications/config/option/PhabricatorRecaptchaConfigOptions.php', 'PhabricatorRecipientHasBadgeEdgeType' => 'applications/badges/edge/PhabricatorRecipientHasBadgeEdgeType.php', @@ -3771,7 +3763,6 @@ phutil_register_library_map(array( 'PhabricatorSettingsListController' => 'applications/settings/controller/PhabricatorSettingsListController.php', 'PhabricatorSettingsLogsPanelGroup' => 'applications/settings/panelgroup/PhabricatorSettingsLogsPanelGroup.php', 'PhabricatorSettingsMainController' => 'applications/settings/controller/PhabricatorSettingsMainController.php', - 'PhabricatorSettingsMainMenuBarExtension' => 'applications/settings/extension/PhabricatorSettingsMainMenuBarExtension.php', 'PhabricatorSettingsPanel' => 'applications/settings/panel/PhabricatorSettingsPanel.php', 'PhabricatorSettingsPanelGroup' => 'applications/settings/panelgroup/PhabricatorSettingsPanelGroup.php', 'PhabricatorSettingsTimezoneController' => 'applications/settings/controller/PhabricatorSettingsTimezoneController.php', @@ -5330,6 +5321,7 @@ phutil_register_library_map(array( 'DiffusionCommitActionTransaction' => 'DiffusionCommitTransactionType', 'DiffusionCommitAffectedFilesHeraldField' => 'DiffusionCommitHeraldField', 'DiffusionCommitAuditTransaction' => 'DiffusionCommitActionTransaction', + 'DiffusionCommitAuditorsHeraldField' => 'DiffusionCommitHeraldField', 'DiffusionCommitAuditorsTransaction' => 'DiffusionCommitTransactionType', 'DiffusionCommitAuthorHeraldField' => 'DiffusionCommitHeraldField', 'DiffusionCommitAutocloseHeraldField' => 'DiffusionCommitHeraldField', @@ -5342,6 +5334,7 @@ phutil_register_library_map(array( 'DiffusionCommitDiffContentHeraldField' => 'DiffusionCommitHeraldField', 'DiffusionCommitDiffContentRemovedHeraldField' => 'DiffusionCommitHeraldField', 'DiffusionCommitDiffEnormousHeraldField' => 'DiffusionCommitHeraldField', + 'DiffusionCommitDraftEngine' => 'PhabricatorDraftEngine', 'DiffusionCommitEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', 'DiffusionCommitEditController' => 'DiffusionController', 'DiffusionCommitEditEngine' => 'PhabricatorEditEngine', @@ -6574,7 +6567,6 @@ phutil_register_library_map(array( 'PHUIListItemView' => 'AphrontTagView', 'PHUIListView' => 'AphrontTagView', 'PHUIListViewTestCase' => 'PhabricatorTestCase', - 'PHUIMainMenuView' => 'AphrontView', 'PHUIObjectBoxView' => 'AphrontTagView', 'PHUIObjectItemListExample' => 'PhabricatorUIExample', 'PHUIObjectItemListView' => 'AphrontTagView', @@ -6678,7 +6670,7 @@ phutil_register_library_map(array( 'PhabricatorAccessLogConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorAccessibilitySetting' => 'PhabricatorSelectSetting', 'PhabricatorAccountSettingsPanel' => 'PhabricatorEditEngineSettingsPanel', - 'PhabricatorActionListView' => 'AphrontView', + 'PhabricatorActionListView' => 'AphrontTagView', 'PhabricatorActionView' => 'AphrontView', 'PhabricatorActivitySettingsPanel' => 'PhabricatorSettingsPanel', 'PhabricatorAdministratorsPolicyRule' => 'PhabricatorPolicyRule', @@ -7612,7 +7604,6 @@ phutil_register_library_map(array( 'PhabricatorEditEngineConfigurationTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorEditEngineConfigurationViewController' => 'PhabricatorEditEngineController', 'PhabricatorEditEngineController' => 'PhabricatorApplicationTransactionController', - 'PhabricatorEditEngineCreateQuickActions' => 'PhabricatorQuickActions', 'PhabricatorEditEngineDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorEditEngineExtension' => 'Phobject', 'PhabricatorEditEngineExtensionModule' => 'PhabricatorConfigModule', @@ -7692,10 +7683,8 @@ phutil_register_library_map(array( 'PhabricatorFactSpec' => 'Phobject', 'PhabricatorFactUpdateIterator' => 'PhutilBufferedIterator', 'PhabricatorFavoritesApplication' => 'PhabricatorApplication', - 'PhabricatorFavoritesConstants' => 'PhabricatorFavoritesController', 'PhabricatorFavoritesController' => 'PhabricatorController', 'PhabricatorFavoritesMainController' => 'PhabricatorFavoritesController', - 'PhabricatorFavoritesManageProfileMenuItem' => 'PhabricatorProfileMenuItem', 'PhabricatorFavoritesMenuItemController' => 'PhabricatorFavoritesController', 'PhabricatorFavoritesProfileMenuEngine' => 'PhabricatorProfileMenuEngine', 'PhabricatorFaxContentSource' => 'PhabricatorContentSource', @@ -7886,7 +7875,6 @@ phutil_register_library_map(array( 'PhabricatorHelpDocumentationController' => 'PhabricatorHelpController', 'PhabricatorHelpEditorProtocolController' => 'PhabricatorHelpController', 'PhabricatorHelpKeyboardShortcutController' => 'PhabricatorHelpController', - 'PhabricatorHelpMainMenuBarExtension' => 'PhabricatorMainMenuBarExtension', 'PhabricatorHeraldApplication' => 'PhabricatorApplication', 'PhabricatorHeraldContentSource' => 'PhabricatorContentSource', 'PhabricatorHighSecurityRequestExceptionHandler' => 'PhabricatorRequestExceptionHandler', @@ -7899,7 +7887,6 @@ phutil_register_library_map(array( 'PhabricatorHomeMenuItemController' => 'PhabricatorHomeController', 'PhabricatorHomePreferencesSettingsPanel' => 'PhabricatorSettingsPanel', 'PhabricatorHomeProfileMenuEngine' => 'PhabricatorProfileMenuEngine', - 'PhabricatorHomeQuickCreateController' => 'PhabricatorHomeController', 'PhabricatorHovercardEngineExtension' => 'Phobject', 'PhabricatorHovercardEngineExtensionModule' => 'PhabricatorConfigModule', 'PhabricatorIDsSearchEngineExtension' => 'PhabricatorSearchEngineExtension', @@ -8093,7 +8080,6 @@ phutil_register_library_map(array( 'PhabricatorModularTransactionType' => 'Phobject', 'PhabricatorMonospacedFontSetting' => 'PhabricatorStringSetting', 'PhabricatorMonospacedTextareasSetting' => 'PhabricatorSelectSetting', - 'PhabricatorMotivatorProfileMenuItem' => 'PhabricatorProfileMenuItem', 'PhabricatorMultiColumnUIExample' => 'PhabricatorUIExample', 'PhabricatorMultiFactorSettingsPanel' => 'PhabricatorSettingsPanel', 'PhabricatorMultimeterApplication' => 'PhabricatorApplication', @@ -8449,7 +8435,6 @@ phutil_register_library_map(array( 'PhabricatorPeopleLogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorPeopleLogSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorPeopleLogsController' => 'PhabricatorPeopleController', - 'PhabricatorPeopleMainMenuBarExtension' => 'PhabricatorMainMenuBarExtension', 'PhabricatorPeopleManageProfileMenuItem' => 'PhabricatorProfileMenuItem', 'PhabricatorPeopleNewController' => 'PhabricatorPeopleController', 'PhabricatorPeopleNoOwnerDatasource' => 'PhabricatorTypeaheadDatasource', @@ -8575,7 +8560,6 @@ phutil_register_library_map(array( ), 'PhabricatorPolicyType' => 'PhabricatorPolicyConstants', 'PhabricatorPonderApplication' => 'PhabricatorApplication', - 'PhabricatorProfileMenuCollapsedSetting' => 'PhabricatorInternalSetting', 'PhabricatorProfileMenuEditEngine' => 'PhabricatorEditEngine', 'PhabricatorProfileMenuEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorProfileMenuEngine' => 'Phobject', @@ -8749,7 +8733,6 @@ phutil_register_library_map(array( 'Phobject', 'Iterator', ), - 'PhabricatorQuickActions' => 'Phobject', 'PhabricatorRateLimitRequestExceptionHandler' => 'PhabricatorRequestExceptionHandler', 'PhabricatorRecaptchaConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorRecipientHasBadgeEdgeType' => 'PhabricatorEdgeType', @@ -8796,6 +8779,7 @@ phutil_register_library_map(array( 'PhabricatorApplicationTransactionInterface', 'PhabricatorFulltextInterface', 'PhabricatorConduitResultInterface', + 'PhabricatorDraftInterface', ), 'PhabricatorRepositoryCommitChangeParserWorker' => 'PhabricatorRepositoryCommitParserWorker', 'PhabricatorRepositoryCommitData' => 'PhabricatorRepositoryDAO', @@ -9015,7 +8999,6 @@ phutil_register_library_map(array( 'PhabricatorSettingsListController' => 'PhabricatorController', 'PhabricatorSettingsLogsPanelGroup' => 'PhabricatorSettingsPanelGroup', 'PhabricatorSettingsMainController' => 'PhabricatorController', - 'PhabricatorSettingsMainMenuBarExtension' => 'PhabricatorMainMenuBarExtension', 'PhabricatorSettingsPanel' => 'Phobject', 'PhabricatorSettingsPanelGroup' => 'Phobject', 'PhabricatorSettingsTimezoneController' => 'PhabricatorController', diff --git a/src/applications/audit/conduit/AuditQueryConduitAPIMethod.php b/src/applications/audit/conduit/AuditQueryConduitAPIMethod.php index 0f2fe473f5..d65c939a61 100644 --- a/src/applications/audit/conduit/AuditQueryConduitAPIMethod.php +++ b/src/applications/audit/conduit/AuditQueryConduitAPIMethod.php @@ -75,7 +75,7 @@ final class AuditQueryConduitAPIMethod extends AuditConduitAPIMethod { PhabricatorAuditCommitStatusConstants::CONCERN_RAISED, ), self::AUDIT_LEGACYSTATUS_ACCEPTED => array( - PhabricatorAuditCommitStatusConstants::CONCERN_ACCEPTED, + PhabricatorAuditCommitStatusConstants::FULLY_AUDITED, ), self::AUDIT_LEGACYSTATUS_PARTIAL => array( PhabricatorAuditCommitStatusConstants::PARTIALLY_AUDITED, diff --git a/src/applications/audit/query/PhabricatorCommitSearchEngine.php b/src/applications/audit/query/PhabricatorCommitSearchEngine.php index fa4fa3c963..f24b12d2b8 100644 --- a/src/applications/audit/query/PhabricatorCommitSearchEngine.php +++ b/src/applications/audit/query/PhabricatorCommitSearchEngine.php @@ -14,7 +14,8 @@ final class PhabricatorCommitSearchEngine public function newQuery() { return id(new DiffusionCommitQuery()) ->needAuditRequests(true) - ->needCommitData(true); + ->needCommitData(true) + ->needDrafts(true); } protected function newResultBuckets() { @@ -140,7 +141,8 @@ final class PhabricatorCommitSearchEngine $bucket = $this->getResultBucket($query); $template = id(new PhabricatorAuditListView()) - ->setViewer($viewer); + ->setViewer($viewer) + ->setShowDrafts(true); $views = array(); if ($bucket) { diff --git a/src/applications/audit/view/PhabricatorAuditListView.php b/src/applications/audit/view/PhabricatorAuditListView.php index f348acc759..9207230e7c 100644 --- a/src/applications/audit/view/PhabricatorAuditListView.php +++ b/src/applications/audit/view/PhabricatorAuditListView.php @@ -4,6 +4,7 @@ final class PhabricatorAuditListView extends AphrontView { private $commits; private $header; + private $showDrafts; private $noDataString; private $highlightedAudits; @@ -25,6 +26,15 @@ final class PhabricatorAuditListView extends AphrontView { return $this->header; } + public function setShowDrafts($show_drafts) { + $this->showDrafts = $show_drafts; + return $this; + } + + public function getShowDrafts() { + return $this->showDrafts; + } + /** * These commits should have both commit data and audit requests attached. */ @@ -73,7 +83,31 @@ final class PhabricatorAuditListView extends AphrontView { $viewer = $this->getViewer(); $rowc = array(); - $handles = $viewer->loadHandles(mpull($this->commits, 'getPHID')); + $phids = array(); + foreach ($this->getCommits() as $commit) { + $phids[] = $commit->getPHID(); + + foreach ($commit->getAudits() as $audit) { + $phids[] = $audit->getAuditorPHID(); + } + + $author_phid = $commit->getAuthorPHID(); + if ($author_phid) { + $phids[] = $author_phid; + } + } + + $handles = $viewer->loadHandles($phids); + + $show_drafts = $this->getShowDrafts(); + + $draft_icon = id(new PHUIIconView()) + ->setIcon('fa-comment yellow') + ->addSigil('has-tooltip') + ->setMetadata( + array( + 'tip' => pht('Unsubmitted Comments'), + )); $list = new PHUIObjectItemListView(); foreach ($this->commits as $commit) { @@ -86,15 +120,6 @@ final class PhabricatorAuditListView extends AphrontView { $commit_desc = $this->getCommitDescription($commit_phid); $committed = phabricator_datetime($commit->getEpoch(), $viewer); - $audits = mpull($commit->getAudits(), null, 'getAuditorPHID'); - $auditors = array(); - $reasons = array(); - foreach ($audits as $audit) { - $auditor_phid = $audit->getAuditorPHID(); - $auditors[$auditor_phid] = $viewer->renderHandle($auditor_phid); - } - $auditors = phutil_implode_html(', ', $auditors); - $status = $commit->getAuditStatus(); $status_text = @@ -106,7 +131,7 @@ final class PhabricatorAuditListView extends AphrontView { $author_phid = $commit->getAuthorPHID(); if ($author_phid) { - $author_name = $viewer->renderHandle($author_phid); + $author_name = $handles[$author_phid]->renderLink(); } else { $author_name = $commit->getCommitData()->getAuthorName(); } @@ -115,14 +140,26 @@ final class PhabricatorAuditListView extends AphrontView { ->setObjectName($commit_name) ->setHeader($commit_desc) ->setHref($commit_link) - ->addAttribute(pht('Author: %s', $author_name)) - ->addAttribute($reasons) + ->addByline(pht('Author: %s', $author_name)) ->addIcon('none', $committed); - if (!empty($auditors)) { - $item->addByLine(pht('Auditors: %s', $auditors)); + if ($show_drafts) { + if ($commit->getHasDraft($viewer)) { + $item->addAttribute($draft_icon); + } } + $audits = $commit->getAudits(); + $auditor_phids = mpull($audits, 'getAuditorPHID'); + if ($auditor_phids) { + $auditor_list = $handles->newSublist($auditor_phids) + ->renderList() + ->setAsInline(true); + } else { + $auditor_list = phutil_tag('em', array(), pht('None')); + } + $item->addAttribute(pht('Auditors: %s', $auditor_list)); + if ($status_color) { $item->setStatusIcon($status_icon.' '.$status_color, $status_text); } diff --git a/src/applications/auth/controller/PhabricatorAuthRegisterController.php b/src/applications/auth/controller/PhabricatorAuthRegisterController.php index 3e4135fff5..cdb7980a16 100644 --- a/src/applications/auth/controller/PhabricatorAuthRegisterController.php +++ b/src/applications/auth/controller/PhabricatorAuthRegisterController.php @@ -54,6 +54,8 @@ final class PhabricatorAuthRegisterController } } + $errors = array(); + $user = new PhabricatorUser(); $default_username = $account->getUsername(); @@ -65,23 +67,37 @@ final class PhabricatorAuthRegisterController $default_email = $invite->getEmailAddress(); } - if (!PhabricatorUserEmail::isValidAddress($default_email)) { - $default_email = null; + if ($default_email !== null) { + if (!PhabricatorUserEmail::isValidAddress($default_email)) { + $errors[] = pht( + 'The email address associated with this external account ("%s") is '. + 'not a valid email address and can not be used to register a '. + 'Phabricator account. Choose a different, valid address.', + phutil_tag('strong', array(), $default_email)); + $default_email = null; + } } if ($default_email !== null) { // We should bypass policy here becase e.g. limiting an application use // to a subset of users should not allow the others to overwrite - // configured application emails + // configured application emails. $application_email = id(new PhabricatorMetaMTAApplicationEmailQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) ->withAddresses(array($default_email)) ->executeOne(); if ($application_email) { + $errors[] = pht( + 'The email address associated with this account ("%s") is '. + 'already in use by an application and can not be used to '. + 'register a new Phabricator account. Choose a different, valid '. + 'address.', + phutil_tag('strong', array(), $default_email)); $default_email = null; } } + $show_existing = null; if ($default_email !== null) { // If the account source provided an email, but it's not allowed by // the configuration, roadblock the user. Previously, we let the user @@ -105,9 +121,6 @@ final class PhabricatorAuthRegisterController // If the account source provided an email, but another account already // has that email, just pretend we didn't get an email. - - // TODO: See T3472. - if ($default_email !== null) { $same_email = id(new PhabricatorUserEmail())->loadOneWhere( 'address = %s', @@ -118,12 +131,57 @@ final class PhabricatorAuthRegisterController // invite means that the address is nonprimary and unverified and // we're OK to steal it. } else { + $show_existing = $default_email; $default_email = null; } } } } + if ($show_existing !== null) { + if (!$request->getInt('phase')) { + return $this->newDialog() + ->setTitle(pht('Email Address Already in Use')) + ->addHiddenInput('phase', 1) + ->appendParagraph( + pht( + 'You are creating a new Phabricator account linked to an '. + 'existing external account from outside Phabricator.')) + ->appendParagraph( + pht( + 'The email address ("%s") associated with the external account '. + 'is already in use by an existing Phabricator account. Multiple '. + 'Phabricator accounts may not have the same email address, so '. + 'you can not use this email address to register a new '. + 'Phabricator account.', + phutil_tag('strong', array(), $show_existing))) + ->appendParagraph( + pht( + 'If you want to register a new account, continue with this '. + 'registration workflow and choose a new, unique email address '. + 'for the new account.')) + ->appendParagraph( + pht( + 'If you want to link an existing Phabricator account to this '. + 'external account, do not continue. Instead: log in to your '. + 'existing account, then go to "Settings" and link the account '. + 'in the "External Accounts" panel.')) + ->appendParagraph( + pht( + 'If you continue, you will create a new account. You will not '. + 'be able to link this external account to an existing account.')) + ->addCancelButton('/auth/login/', pht('Cancel')) + ->addSubmitButton(pht('Create New Account')); + } else { + $errors[] = pht( + 'The external account you are registering with has an email address '. + 'that is already in use ("%s") by an existing Phabricator account. '. + 'Choose a new, valid email address to register a new Phabricator '. + 'account.', + phutil_tag('strong', array(), $show_existing)); + } + } + $profile = id(new PhabricatorRegistrationProfile()) ->setDefaultUsername($default_username) ->setDefaultEmail($default_email) @@ -167,8 +225,6 @@ final class PhabricatorAuthRegisterController $value_email = $default_email; $value_password = null; - $errors = array(); - $require_real_name = PhabricatorEnv::getEnvConfig('user.require-real-name'); $e_username = strlen($value_username) ? null : true; @@ -193,7 +249,14 @@ final class PhabricatorAuthRegisterController $e_username = null; } - if (($request->isFormPost() || !$can_edit_anything) && !$from_invite) { + $try_register = + ($request->isFormPost() || !$can_edit_anything) && + !$from_invite && + ($request->getInt('phase') != 1); + + if ($try_register) { + $errors = array(); + $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); if ($must_set_password && !$skip_captcha) { @@ -402,7 +465,8 @@ final class PhabricatorAuthRegisterController } $form = id(new AphrontFormView()) - ->setUser($request->getUser()); + ->setUser($request->getUser()) + ->addHiddenInput('phase', 2); if (!$is_default) { $form->appendChild( diff --git a/src/applications/auth/extension/PhabricatorAuthMainMenuBarExtension.php b/src/applications/auth/extension/PhabricatorAuthMainMenuBarExtension.php index 47264517e0..2757bec91c 100644 --- a/src/applications/auth/extension/PhabricatorAuthMainMenuBarExtension.php +++ b/src/applications/auth/extension/PhabricatorAuthMainMenuBarExtension.php @@ -13,9 +13,7 @@ final class PhabricatorAuthMainMenuBarExtension $viewer = $this->getViewer(); if ($viewer->isLoggedIn()) { - return array( - $this->buildLogoutMenu(), - ); + return array(); } $controller = $this->getController(); @@ -30,25 +28,6 @@ final class PhabricatorAuthMainMenuBarExtension ); } - private function buildLogoutMenu() { - $controller = $this->getController(); - - $is_selected = ($controller instanceof PhabricatorLogoutController); - - $bar_item = id(new PHUIListItemView()) - ->addClass('core-menu-item') - ->setName(pht('Log Out')) - ->setIcon('fa-sign-out') - ->setWorkflow(true) - ->setHref('/logout/') - ->setSelected($is_selected) - ->setAural(pht('Log Out')); - - return id(new PHUIMainMenuView()) - ->setOrder(900) - ->setMenuBarItem($bar_item); - } - private function buildLoginMenu() { $controller = $this->getController(); @@ -58,16 +37,12 @@ final class PhabricatorAuthMainMenuBarExtension $uri->setQueryParam('next', $path); } - $bar_item = id(new PHUIListItemView()) - ->addClass('core-menu-item') - ->setName(pht('Log In')) - ->setIcon('fa-sign-in') + return id(new PHUIButtonView()) + ->setTag('a') + ->setText(pht('Log In')) ->setHref($uri) - ->setAural(pht('Log In')); - - return id(new PHUIMainMenuView()) - ->setOrder(900) - ->setMenuBarItem($bar_item); + ->setNoCSS(true) + ->addClass('phabricator-core-login-button'); } } diff --git a/src/applications/base/PhabricatorApplication.php b/src/applications/base/PhabricatorApplication.php index 95045623d0..e50045b0e9 100644 --- a/src/applications/base/PhabricatorApplication.php +++ b/src/applications/base/PhabricatorApplication.php @@ -172,41 +172,40 @@ abstract class PhabricatorApplication $articles = $this->getHelpDocumentationArticles($viewer); if ($articles) { - $items[] = id(new PHUIListItemView()) - ->setType(PHUIListItemView::TYPE_LABEL) - ->setName(pht('%s Documentation', $this->getName())); foreach ($articles as $article) { - $item = id(new PHUIListItemView()) + $item = id(new PhabricatorActionView()) ->setName($article['name']) - ->setIcon('fa-book') ->setHref($article['href']) + ->addSigil('help-item') ->setOpenInNewWindow(true); - $items[] = $item; } } $command_specs = $this->getMailCommandObjects(); if ($command_specs) { - $items[] = id(new PHUIListItemView()) - ->setType(PHUIListItemView::TYPE_LABEL) - ->setName(pht('Email Help')); foreach ($command_specs as $key => $spec) { $object = $spec['object']; $class = get_class($this); $href = '/applications/mailcommands/'.$class.'/'.$key.'/'; - - $item = id(new PHUIListItemView()) + $item = id(new PhabricatorActionView()) ->setName($spec['name']) - ->setIcon('fa-envelope-o') ->setHref($href) + ->addSigil('help-item') ->setOpenInNewWindow(true); $items[] = $item; } } - return $items; + if ($items) { + $divider = id(new PhabricatorActionView()) + ->addSigil('help-item') + ->setType(PhabricatorActionView::TYPE_DIVIDER); + array_unshift($items, $divider); + } + + return array_values($items); } public function getHelpDocumentationArticles(PhabricatorUser $viewer) { diff --git a/src/applications/celerity/postprocessor/CelerityDefaultPostprocessor.php b/src/applications/celerity/postprocessor/CelerityDefaultPostprocessor.php index be5bfc14c2..b68c23d69b 100644 --- a/src/applications/celerity/postprocessor/CelerityDefaultPostprocessor.php +++ b/src/applications/celerity/postprocessor/CelerityDefaultPostprocessor.php @@ -29,7 +29,7 @@ final class CelerityDefaultPostprocessor "Arial, sans-serif", // Drop Shadow - 'dropshadow' => '0 1px 6px rgba(0, 0, 0, .25)', + 'dropshadow' => '0 2px 12px rgba(0, 0, 0, .20)', 'whitetextshadow' => '0 1px 0 rgba(255, 255, 255, 1)', // Anchors diff --git a/src/applications/differential/conduit/DifferentialGetCommitMessageConduitAPIMethod.php b/src/applications/differential/conduit/DifferentialGetCommitMessageConduitAPIMethod.php index 2c5c936679..d45fc22fd3 100644 --- a/src/applications/differential/conduit/DifferentialGetCommitMessageConduitAPIMethod.php +++ b/src/applications/differential/conduit/DifferentialGetCommitMessageConduitAPIMethod.php @@ -142,9 +142,11 @@ final class DifferentialGetCommitMessageConduitAPIMethod private function loadCustomFieldStorage( PhabricatorUser $viewer, DifferentialRevision $revision) { + $custom_field_list = PhabricatorCustomField::getObjectFields( $revision, - DifferentialCustomField::ROLE_COMMITMESSAGE); + PhabricatorCustomField::ROLE_STORAGE); + $custom_field_list ->setViewer($viewer) ->readFieldsFromStorage($revision); diff --git a/src/applications/differential/customfield/DifferentialAuditorsField.php b/src/applications/differential/customfield/DifferentialAuditorsField.php index 544f238458..23055461e0 100644 --- a/src/applications/differential/customfield/DifferentialAuditorsField.php +++ b/src/applications/differential/customfield/DifferentialAuditorsField.php @@ -36,10 +36,6 @@ final class DifferentialAuditorsField return true; } - public function shouldAppearInCommitMessage() { - return true; - } - public function shouldAppearInConduitTransactions() { return true; } diff --git a/src/applications/differential/customfield/DifferentialBlameRevisionField.php b/src/applications/differential/customfield/DifferentialBlameRevisionField.php index b2d8872225..d36e199b1a 100644 --- a/src/applications/differential/customfield/DifferentialBlameRevisionField.php +++ b/src/applications/differential/customfield/DifferentialBlameRevisionField.php @@ -91,10 +91,6 @@ final class DifferentialBlameRevisionField $xaction->renderHandleLink($object_phid)); } - public function shouldAppearInCommitMessage() { - return true; - } - public function shouldAppearInConduitDictionary() { return true; } diff --git a/src/applications/differential/customfield/DifferentialCoreCustomField.php b/src/applications/differential/customfield/DifferentialCoreCustomField.php index d4181a31e7..6d956ac367 100644 --- a/src/applications/differential/customfield/DifferentialCoreCustomField.php +++ b/src/applications/differential/customfield/DifferentialCoreCustomField.php @@ -156,15 +156,6 @@ abstract class DifferentialCoreCustomField return $this->value; } - public function readValueFromCommitMessage($value) { - $this->setValue($value); - return $this; - } - - public function renderCommitMessageValue(array $handles) { - return $this->getValue(); - } - public function getConduitDictionaryValue() { return $this->getValue(); } diff --git a/src/applications/differential/customfield/DifferentialCustomField.php b/src/applications/differential/customfield/DifferentialCustomField.php index f210dd0f63..487e412f66 100644 --- a/src/applications/differential/customfield/DifferentialCustomField.php +++ b/src/applications/differential/customfield/DifferentialCustomField.php @@ -7,9 +7,6 @@ abstract class DifferentialCustomField extends PhabricatorCustomField { - const ROLE_COMMITMESSAGE = 'differential:commitmessage'; - const ROLE_COMMITMESSAGEEDIT = 'differential:commitmessageedit'; - /** * TODO: It would be nice to remove this, but a lot of different code is * bound together by it. Until everything is modernized, retaining the old @@ -25,18 +22,6 @@ abstract class DifferentialCustomField return $this->getFieldKeyForConduit(); } - public function shouldEnableForRole($role) { - switch ($role) { - case self::ROLE_COMMITMESSAGE: - return $this->shouldAppearInCommitMessage(); - case self::ROLE_COMMITMESSAGEEDIT: - return $this->shouldAppearInCommitMessage() && - $this->shouldAllowEditInCommitMessage(); - } - - return parent::shouldEnableForRole($role); - } - protected function parseObjectList( $value, array $types, @@ -97,39 +82,6 @@ abstract class DifferentialCustomField /* -( Integration with Commit Messages )----------------------------------- */ - /** - * @task commitmessage - */ - public function shouldAppearInCommitMessage() { - if ($this->getProxy()) { - return $this->getProxy()->shouldAppearInCommitMessage(); - } - return false; - } - - - /** - * @task commitmessage - */ - public function shouldAppearInCommitMessageTemplate() { - if ($this->getProxy()) { - return $this->getProxy()->shouldAppearInCommitMessageTemplate(); - } - return false; - } - - - /** - * @task commitmessage - */ - public function shouldAllowEditInCommitMessage() { - if ($this->getProxy()) { - return $this->getProxy()->shouldAllowEditInCommitMessage(); - } - return true; - } - - /** * @task commitmessage */ @@ -141,95 +93,6 @@ abstract class DifferentialCustomField } - /** - * @task commitmessage - */ - public function getCommitMessageLabels() { - if ($this->getProxy()) { - return $this->getProxy()->getCommitMessageLabels(); - } - return array($this->renderCommitMessageLabel()); - } - - - /** - * @task commitmessage - */ - public function parseValueFromCommitMessage($value) { - if ($this->getProxy()) { - return $this->getProxy()->parseValueFromCommitMessage($value); - } - return $value; - } - - - /** - * @task commitmessage - */ - public function readValueFromCommitMessage($value) { - if ($this->getProxy()) { - $this->getProxy()->readValueFromCommitMessage($value); - return $this; - } - return $this; - } - - - /** - * @task commitmessage - */ - public function shouldOverwriteWhenCommitMessageIsEdited() { - if ($this->getProxy()) { - return $this->getProxy()->shouldOverwriteWhenCommitMessageIsEdited(); - } - return false; - } - - - /** - * @task commitmessage - */ - public function getRequiredHandlePHIDsForCommitMessage() { - if ($this->getProxy()) { - return $this->getProxy()->getRequiredHandlePHIDsForCommitMessage(); - } - return array(); - } - - - /** - * @task commitmessage - */ - public function renderCommitMessageLabel() { - if ($this->getProxy()) { - return $this->getProxy()->renderCommitMessageLabel(); - } - return $this->getFieldName(); - } - - - /** - * @task commitmessage - */ - public function renderCommitMessageValue(array $handles) { - if ($this->getProxy()) { - return $this->getProxy()->renderCommitMessageValue($handles); - } - throw new PhabricatorCustomFieldImplementationIncompleteException($this); - } - - - /** - * @task commitmessage - */ - public function validateCommitMessageValue($value) { - if ($this->getProxy()) { - return $this->getProxy()->validateCommitMessageValue($value); - } - return; - } - - /* -( Integration with Diff Properties )----------------------------------- */ diff --git a/src/applications/differential/customfield/DifferentialJIRAIssuesField.php b/src/applications/differential/customfield/DifferentialJIRAIssuesField.php index fc15f4a45b..e97efd6ad5 100644 --- a/src/applications/differential/customfield/DifferentialJIRAIssuesField.php +++ b/src/applications/differential/customfield/DifferentialJIRAIssuesField.php @@ -270,39 +270,6 @@ final class DifferentialJIRAIssuesField $editor->save(); } - public function shouldAppearInCommitMessage() { - return true; - } - - public function shouldAppearInCommitMessageTemplate() { - return true; - } - - public function getCommitMessageLabels() { - return array( - 'JIRA', - 'JIRA Issues', - 'JIRA Issue', - ); - } - - public function parseValueFromCommitMessage($value) { - return preg_split('/[\s,]+/', $value, $limit = -1, PREG_SPLIT_NO_EMPTY); - } - - public function readValueFromCommitMessage($value) { - $this->setValue($value); - return $this; - } - - public function renderCommitMessageValue(array $handles) { - $value = $this->getValue(); - if (!$value) { - return null; - } - return implode(', ', $value); - } - public function shouldAppearInConduitDictionary() { return true; } diff --git a/src/applications/differential/customfield/DifferentialRevertPlanField.php b/src/applications/differential/customfield/DifferentialRevertPlanField.php index 0fd5531426..ca13788294 100644 --- a/src/applications/differential/customfield/DifferentialRevertPlanField.php +++ b/src/applications/differential/customfield/DifferentialRevertPlanField.php @@ -130,14 +130,6 @@ final class DifferentialRevertPlanField return array($xaction->getNewValue()); } - public function shouldAppearInCommitMessage() { - return true; - } - - public function renderCommitMessageValue(array $handles) { - return $this->getValue(); - } - public function shouldAppearInConduitDictionary() { return true; } diff --git a/src/applications/differential/field/DifferentialCommitMessageCustomField.php b/src/applications/differential/field/DifferentialCommitMessageCustomField.php index cfa71a2a58..21f21e1774 100644 --- a/src/applications/differential/field/DifferentialCommitMessageCustomField.php +++ b/src/applications/differential/field/DifferentialCommitMessageCustomField.php @@ -45,7 +45,7 @@ abstract class DifferentialCommitMessageCustomField protected function getCustomFieldOrder($key) { $field_list = PhabricatorCustomField::getObjectFields( new DifferentialRevision(), - DifferentialCustomField::ROLE_COMMITMESSAGE); + PhabricatorCustomField::ROLE_DEFAULT); $fields = $field_list->getFields(); diff --git a/src/applications/differential/query/DifferentialRevisionQuery.php b/src/applications/differential/query/DifferentialRevisionQuery.php index a4e446ad0d..5dff433e9c 100644 --- a/src/applications/differential/query/DifferentialRevisionQuery.php +++ b/src/applications/differential/query/DifferentialRevisionQuery.php @@ -473,34 +473,9 @@ final class DifferentialRevisionQuery } if ($this->needDrafts) { - $viewer_phid = $viewer->getPHID(); - $draft_type = PhabricatorObjectHasDraftEdgeType::EDGECONST; - - if (!$viewer_phid) { - // Viewers without a valid PHID can never have drafts. - foreach ($revisions as $revision) { - $revision->attachHasDraft($viewer, false); - } - } else { - $edge_query = id(new PhabricatorEdgeQuery()) - ->withSourcePHIDs(mpull($revisions, 'getPHID')) - ->withEdgeTypes( - array( - $draft_type, - )) - ->withDestinationPHIDs(array($viewer_phid)); - - $edge_query->execute(); - - foreach ($revisions as $revision) { - $has_draft = (bool)$edge_query->getDestinationPHIDs( - array( - $revision->getPHID(), - )); - - $revision->attachHasDraft($viewer, $has_draft); - } - } + PhabricatorDraftEngine::attachDrafts( + $viewer, + $revisions); } return $revisions; diff --git a/src/applications/differential/xaction/DifferentialRevisionAcceptTransaction.php b/src/applications/differential/xaction/DifferentialRevisionAcceptTransaction.php index df4e3b4d33..3a64a44767 100644 --- a/src/applications/differential/xaction/DifferentialRevisionAcceptTransaction.php +++ b/src/applications/differential/xaction/DifferentialRevisionAcceptTransaction.php @@ -50,7 +50,7 @@ final class DifferentialRevisionAcceptTransaction public function generateOldValue($object) { $actor = $this->getActor(); - return $this->isViewerAcceptingReviewer($object, $actor); + return $this->isViewerFullyAccepted($object, $actor); } public function applyExternalEffects($object, $value) { @@ -79,7 +79,7 @@ final class DifferentialRevisionAcceptTransaction } } - if ($this->isViewerAcceptingReviewer($object, $viewer)) { + if ($this->isViewerFullyAccepted($object, $viewer)) { throw new Exception( pht( 'You can not accept this revision because you have already '. diff --git a/src/applications/differential/xaction/DifferentialRevisionRejectTransaction.php b/src/applications/differential/xaction/DifferentialRevisionRejectTransaction.php index 96812de06b..b4c71209aa 100644 --- a/src/applications/differential/xaction/DifferentialRevisionRejectTransaction.php +++ b/src/applications/differential/xaction/DifferentialRevisionRejectTransaction.php @@ -46,7 +46,7 @@ final class DifferentialRevisionRejectTransaction public function generateOldValue($object) { $actor = $this->getActor(); - return $this->isViewerRejectingReviewer($object, $actor); + return $this->isViewerFullyRejected($object, $actor); } public function applyExternalEffects($object, $value) { @@ -72,7 +72,7 @@ final class DifferentialRevisionRejectTransaction 'not own.')); } - if ($this->isViewerRejectingReviewer($object, $viewer)) { + if ($this->isViewerFullyRejected($object, $viewer)) { throw new Exception( pht( 'You can not request changes to this revision because you have '. diff --git a/src/applications/differential/xaction/DifferentialRevisionReviewTransaction.php b/src/applications/differential/xaction/DifferentialRevisionReviewTransaction.php index de75977220..7e0c60a7b1 100644 --- a/src/applications/differential/xaction/DifferentialRevisionReviewTransaction.php +++ b/src/applications/differential/xaction/DifferentialRevisionReviewTransaction.php @@ -13,10 +13,10 @@ abstract class DifferentialRevisionReviewTransaction return ($this->getViewerReviewerStatus($revision, $viewer) !== null); } - protected function isViewerAcceptingReviewer( + protected function isViewerFullyAccepted( DifferentialRevision $revision, PhabricatorUser $viewer) { - return $this->isViewerReviewerStatusAmong( + return $this->isViewerReviewerStatusFullyAmong( $revision, $viewer, array( @@ -24,10 +24,10 @@ abstract class DifferentialRevisionReviewTransaction )); } - protected function isViewerRejectingReviewer( + protected function isViewerFullyRejected( DifferentialRevision $revision, PhabricatorUser $viewer) { - return $this->isViewerReviewerStatusAmong( + return $this->isViewerReviewerStatusFullyAmong( $revision, $viewer, array( @@ -54,18 +54,34 @@ abstract class DifferentialRevisionReviewTransaction return null; } - protected function isViewerReviewerStatusAmong( + protected function isViewerReviewerStatusFullyAmong( DifferentialRevision $revision, PhabricatorUser $viewer, array $status_list) { + // If the user themselves is not a reviewer, the reviews they have + // authority over can not all be in any set of states since their own + // personal review has no state. $status = $this->getViewerReviewerStatus($revision, $viewer); if ($status === null) { return false; } + // Otherwise, check that all reviews they have authority over are in + // the desired set of states. $status_map = array_fuse($status_list); - return isset($status_map[$status]); + foreach ($revision->getReviewerStatus() as $reviewer) { + if (!$reviewer->hasAuthority($viewer)) { + continue; + } + + $status = $reviewer->getStatus(); + if (!isset($status_map[$status])) { + return false; + } + } + + return true; } protected function applyReviewerEffect( diff --git a/src/applications/diffusion/editor/DiffusionRepositoryEditEngine.php b/src/applications/diffusion/editor/DiffusionRepositoryEditEngine.php index 933cdbb597..4f45357956 100644 --- a/src/applications/diffusion/editor/DiffusionRepositoryEditEngine.php +++ b/src/applications/diffusion/editor/DiffusionRepositoryEditEngine.php @@ -20,6 +20,10 @@ final class DiffusionRepositoryEditEngine return false; } + public function isDefaultQuickCreateEngine() { + return true; + } + public function getEngineName() { return pht('Repositories'); } diff --git a/src/applications/diffusion/engine/DiffusionCommitDraftEngine.php b/src/applications/diffusion/engine/DiffusionCommitDraftEngine.php new file mode 100644 index 0000000000..ce39e525a6 --- /dev/null +++ b/src/applications/diffusion/engine/DiffusionCommitDraftEngine.php @@ -0,0 +1,18 @@ +getViewer(); + $commit = $this->getObject(); + + $inlines = PhabricatorAuditInlineComment::loadDraftComments( + $viewer, + $commit->getPHID(), + $raw = true); + + return (bool)$inlines; + } + +} diff --git a/src/applications/diffusion/herald/DiffusionCommitAuditorsHeraldField.php b/src/applications/diffusion/herald/DiffusionCommitAuditorsHeraldField.php new file mode 100644 index 0000000000..8deee3417e --- /dev/null +++ b/src/applications/diffusion/herald/DiffusionCommitAuditorsHeraldField.php @@ -0,0 +1,41 @@ +setViewer($viewer) + ->withPHIDs(array($object->getPHID())) + ->needAuditRequests(true) + ->executeOne(); + + $audits = $commit->getAudits(); + + $phids = array(); + foreach ($audits as $audit) { + if ($audit->isActiveAudit()) { + $phids[] = $audit->getAuditorPHID(); + } + } + + return $phids; + } + + protected function getHeraldFieldStandardType() { + return self::STANDARD_PHID_LIST; + } + + protected function getDatasource() { + return new DiffusionAuditorDatasource(); + } + +} diff --git a/src/applications/diffusion/query/DiffusionCommitQuery.php b/src/applications/diffusion/query/DiffusionCommitQuery.php index a24f8038e0..fddaf547bd 100644 --- a/src/applications/diffusion/query/DiffusionCommitQuery.php +++ b/src/applications/diffusion/query/DiffusionCommitQuery.php @@ -22,6 +22,7 @@ final class DiffusionCommitQuery private $importing; private $needCommitData; + private $needDrafts; public function withIDs(array $ids) { $this->ids = $ids; @@ -98,6 +99,11 @@ final class DiffusionCommitQuery return $this; } + public function needDrafts($need) { + $this->needDrafts = $need; + return $this; + } + public function needAuditRequests($need) { $this->needAuditRequests = $need; return $this; @@ -239,6 +245,8 @@ final class DiffusionCommitQuery } protected function didFilterPage(array $commits) { + $viewer = $this->getViewer(); + if ($this->needCommitData) { $data = id(new PhabricatorRepositoryCommitData())->loadAllWhere( 'commitID in (%Ld)', @@ -268,6 +276,12 @@ final class DiffusionCommitQuery } } + if ($this->needDrafts) { + PhabricatorDraftEngine::attachDrafts( + $viewer, + $commits); + } + return $commits; } diff --git a/src/applications/diffusion/view/DiffusionHistoryTableView.php b/src/applications/diffusion/view/DiffusionHistoryTableView.php index 4c19e3762b..bb3aee37da 100644 --- a/src/applications/diffusion/view/DiffusionHistoryTableView.php +++ b/src/applications/diffusion/view/DiffusionHistoryTableView.php @@ -187,6 +187,19 @@ final class DiffusionHistoryTableView extends DiffusionView { 'type' => $history->getFileType(), )); + $status = $commit->getAuditStatus(); + $icon = PhabricatorAuditCommitStatusConstants::getStatusIcon($status); + $color = PhabricatorAuditCommitStatusConstants::getStatusColor($status); + $name = PhabricatorAuditCommitStatusConstants::getStatusName($status); + + $audit_view = id(new PHUIIconView()) + ->setIcon($icon, $color) + ->addSigil('has-tooltip') + ->setMetadata( + array( + 'tip' => $name, + )); + $rows[] = array( $graph ? $graph[$ii++] : null, $browse, @@ -194,6 +207,7 @@ final class DiffusionHistoryTableView extends DiffusionView { $drequest->getRepository(), $history->getCommitIdentifier()), $build, + $audit_view, ($commit ? self::linkRevision(idx($this->revisions, $commit->getPHID())) : null), @@ -211,7 +225,8 @@ final class DiffusionHistoryTableView extends DiffusionView { pht('Commit'), null, null, - pht('Author/Committer'), + null, + pht('Author'), pht('Details'), pht('Committed'), )); @@ -221,6 +236,7 @@ final class DiffusionHistoryTableView extends DiffusionView { 'nudgeright', '', 'icon', + 'icon', '', '', 'wide', @@ -232,6 +248,7 @@ final class DiffusionHistoryTableView extends DiffusionView { true, true, $has_any_build, + true, $show_revisions, )); $view->setDeviceVisibility( @@ -241,6 +258,7 @@ final class DiffusionHistoryTableView extends DiffusionView { true, true, true, + true, false, true, false, diff --git a/src/applications/favorites/application/PhabricatorFavoritesApplication.php b/src/applications/favorites/application/PhabricatorFavoritesApplication.php index 3c5211fec4..958355a2b5 100644 --- a/src/applications/favorites/application/PhabricatorFavoritesApplication.php +++ b/src/applications/favorites/application/PhabricatorFavoritesApplication.php @@ -15,7 +15,7 @@ final class PhabricatorFavoritesApplication extends PhabricatorApplication { } public function getIcon() { - return 'fa-star-o'; + return 'fa-star'; } public function getRoutes() { @@ -32,8 +32,82 @@ final class PhabricatorFavoritesApplication extends PhabricatorApplication { return false; } - public function getApplicationOrder() { - return 9; + public function buildMainMenuExtraNodes( + PhabricatorUser $viewer, + PhabricatorController $controller = null) { + + $dropdown = $this->renderFavoritesDropdown($viewer); + if (!$dropdown) { + return null; + } + + return id(new PHUIButtonView()) + ->setTag('a') + ->setHref('#') + ->setIcon('fa-star') + ->addClass('phabricator-core-user-menu') + ->setNoCSS(true) + ->setDropdown(true) + ->setDropdownMenu($dropdown); + } + + private function renderFavoritesDropdown(PhabricatorUser $viewer) { + $application = __CLASS__; + + $applications = id(new PhabricatorApplicationQuery()) + ->setViewer($viewer) + ->withClasses(array($application)) + ->withInstalled(true) + ->execute(); + $favorites = head($applications); + if (!$favorites) { + return null; + } + + $menu_engine = id(new PhabricatorFavoritesProfileMenuEngine()) + ->setViewer($viewer) + ->setProfileObject($favorites); + + if ($viewer->getPHID()) { + $menu_engine + ->setCustomPHID($viewer->getPHID()) + ->setMenuType(PhabricatorProfileMenuEngine::MENU_COMBINED); + } else { + $menu_engine + ->setMenuType(PhabricatorProfileMenuEngine::MENU_GLOBAL); + } + + $filter_view = $menu_engine->buildNavigation(); + + $menu_view = $filter_view->getMenu(); + $item_views = $menu_view->getItems(); + + $view = id(new PhabricatorActionListView()) + ->setViewer($viewer); + foreach ($item_views as $item) { + $type = null; + if (!strlen($item->getName())) { + $type = PhabricatorActionView::TYPE_DIVIDER; + } + $action = id(new PhabricatorActionView()) + ->setName($item->getName()) + ->setHref($item->getHref()) + ->setType($type); + $view->addAction($action); + } + + // Build out edit interface + if ($viewer->isLoggedIn()) { + $view->addAction( + id(new PhabricatorActionView()) + ->setType(PhabricatorActionView::TYPE_DIVIDER)); + $view->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Edit Favorites')) + ->setHref('/favorites/')); + } + + return $view; } } diff --git a/src/applications/favorites/constants/PhabricatorFavoritesConstants.php b/src/applications/favorites/constants/PhabricatorFavoritesConstants.php deleted file mode 100644 index c11a435eef..0000000000 --- a/src/applications/favorites/constants/PhabricatorFavoritesConstants.php +++ /dev/null @@ -1,11 +0,0 @@ -getViewer(); + if (!$viewer->getIsAdmin()) { + $uri = '/favorites/personal/item/configure/'; + return id(new AphrontRedirectResponse())->setURI($uri); + } + $menu = id(new PHUIObjectItemListView()) ->setUser($viewer); diff --git a/src/applications/favorites/controller/PhabricatorFavoritesMenuItemController.php b/src/applications/favorites/controller/PhabricatorFavoritesMenuItemController.php index a398cf6ee8..912d9efe0d 100644 --- a/src/applications/favorites/controller/PhabricatorFavoritesMenuItemController.php +++ b/src/applications/favorites/controller/PhabricatorFavoritesMenuItemController.php @@ -7,8 +7,10 @@ final class PhabricatorFavoritesMenuItemController $viewer = $this->getViewer(); $type = $request->getURIData('type'); $custom_phid = null; + $menu = PhabricatorProfileMenuEngine::MENU_GLOBAL; if ($type == 'personal') { $custom_phid = $viewer->getPHID(); + $menu = PhabricatorProfileMenuEngine::MENU_PERSONAL; } $application = 'PhabricatorFavoritesApplication'; @@ -21,7 +23,9 @@ final class PhabricatorFavoritesMenuItemController $engine = id(new PhabricatorFavoritesProfileMenuEngine()) ->setProfileObject($favorites) ->setCustomPHID($custom_phid) - ->setController($this); + ->setController($this) + ->setMenuType($menu) + ->setShowNavigation(false); return $engine->buildResponse(); } diff --git a/src/applications/favorites/engine/PhabricatorFavoritesProfileMenuEngine.php b/src/applications/favorites/engine/PhabricatorFavoritesProfileMenuEngine.php index a12922a6e8..3c86d19a58 100644 --- a/src/applications/favorites/engine/PhabricatorFavoritesProfileMenuEngine.php +++ b/src/applications/favorites/engine/PhabricatorFavoritesProfileMenuEngine.php @@ -20,50 +20,28 @@ final class PhabricatorFavoritesProfileMenuEngine protected function getBuiltinProfileItems($object) { $items = array(); - $custom_phid = $this->getCustomPHID(); + $viewer = $this->getViewer(); - // Built-in Global Defaults - if (!$custom_phid) { - $create_task = array( - 'name' => null, - 'formKey' => - id(new ManiphestEditEngine())->getProfileMenuItemDefault(), - ); + $engines = PhabricatorEditEngine::getAllEditEngines(); + $engines = msortv($engines, 'getQuickCreateOrderVector'); - $create_project = array( - 'name' => null, - 'formKey' => - id(new PhabricatorProjectEditEngine())->getProfileMenuItemDefault(), - ); + foreach ($engines as $engine) { + foreach ($engine->getDefaultQuickCreateFormKeys() as $form_key) { + $form_hash = PhabricatorHash::digestForIndex($form_key); + $builtin_key = "editengine.form({$form_hash})"; - $create_repository = array( - 'name' => null, - 'formKey' => - id(new DiffusionRepositoryEditEngine())->getProfileMenuItemDefault(), - ); + $properties = array( + 'name' => null, + 'formKey' => $form_key, + ); - $items[] = $this->newItem() - ->setBuiltinKey(PhabricatorFavoritesConstants::ITEM_TASK) - ->setMenuItemKey(PhabricatorEditEngineProfileMenuItem::MENUITEMKEY) - ->setMenuItemProperties($create_task); - - $items[] = $this->newItem() - ->setBuiltinKey(PhabricatorFavoritesConstants::ITEM_PROJECT) - ->setMenuItemKey(PhabricatorEditEngineProfileMenuItem::MENUITEMKEY) - ->setMenuItemProperties($create_project); - - $items[] = $this->newItem() - ->setBuiltinKey(PhabricatorFavoritesConstants::ITEM_REPOSITORY) - ->setMenuItemKey(PhabricatorEditEngineProfileMenuItem::MENUITEMKEY) - ->setMenuItemProperties($create_repository); + $items[] = $this->newItem() + ->setBuiltinKey($builtin_key) + ->setMenuItemKey(PhabricatorEditEngineProfileMenuItem::MENUITEMKEY) + ->setMenuItemProperties($properties); + } } - // Single Manage Item, switches URI based on admin/user - $items[] = $this->newItem() - ->setBuiltinKey(PhabricatorFavoritesConstants::ITEM_MANAGE) - ->setMenuItemKey( - PhabricatorFavoritesManageProfileMenuItem::MENUITEMKEY); - return $items; } diff --git a/src/applications/favorites/menuitem/PhabricatorFavoritesManageProfileMenuItem.php b/src/applications/favorites/menuitem/PhabricatorFavoritesManageProfileMenuItem.php deleted file mode 100644 index 36847061bf..0000000000 --- a/src/applications/favorites/menuitem/PhabricatorFavoritesManageProfileMenuItem.php +++ /dev/null @@ -1,72 +0,0 @@ -getMenuItemProperty('name'); - - if (strlen($name)) { - return $name; - } - - return $this->getDefaultName(); - } - - public function buildEditEngineFields( - PhabricatorProfileMenuItemConfiguration $config) { - return array( - id(new PhabricatorTextEditField()) - ->setKey('name') - ->setLabel(pht('Name')) - ->setPlaceholder($this->getDefaultName()) - ->setValue($config->getMenuItemProperty('name')), - ); - } - - protected function newNavigationMenuItems( - PhabricatorProfileMenuItemConfiguration $config) { - $viewer = $this->getViewer(); - - if ($viewer->isLoggedIn()) { - $admin = $viewer->getIsAdmin(); - $name = $this->getDisplayName($config); - $icon = 'fa-pencil'; - $href = '/favorites/personal/item/configure/'; - if ($admin) { - $href = '/favorites/'; - } - - $item = $this->newItem() - ->setHref($href) - ->setName($name) - ->setIcon($icon); - } - - return array( - $item, - ); - } - -} diff --git a/src/applications/help/controller/PhabricatorHelpDocumentationController.php b/src/applications/help/controller/PhabricatorHelpDocumentationController.php index 4983520bab..82a6de6ec5 100644 --- a/src/applications/help/controller/PhabricatorHelpDocumentationController.php +++ b/src/applications/help/controller/PhabricatorHelpDocumentationController.php @@ -31,7 +31,6 @@ final class PhabricatorHelpDocumentationController $list->addItem( id(new PHUIObjectItemView()) ->setHeader($item->getName()) - ->setWorkflow($item->getWorkflow()) ->setHref($item->getHref())); } diff --git a/src/applications/help/extension/PhabricatorHelpMainMenuBarExtension.php b/src/applications/help/extension/PhabricatorHelpMainMenuBarExtension.php deleted file mode 100644 index 3d2969c035..0000000000 --- a/src/applications/help/extension/PhabricatorHelpMainMenuBarExtension.php +++ /dev/null @@ -1,70 +0,0 @@ -getApplication(); - if (!$application) { - return array(); - } - - $viewer = $this->getViewer(); - $help_links = $application->getHelpMenuItems($viewer); - if (!$help_links) { - return array(); - } - - $help_id = celerity_generate_unique_node_id(); - - Javelin::initBehavior( - 'aphlict-dropdown', - array( - 'bubbleID' => $help_id, - 'dropdownID' => 'phabricator-help-menu', - 'local' => true, - 'desktop' => true, - 'right' => true, - )); - - $help_name = pht('%s Help', $application->getName()); - - $help_item = id(new PHUIListItemView()) - ->setIcon('fa-book') - ->addClass('core-menu-item') - ->setID($help_id) - ->setName($help_name) - ->setHref('/help/documentation/'.get_class($application).'/') - ->setAural($help_name); - - $view = new PHUIListView(); - foreach ($help_links as $help_link) { - $view->addMenuItem($help_link); - } - - $dropdown_menu = phutil_tag( - 'div', - array( - 'id' => 'phabricator-help-menu', - 'class' => 'phabricator-main-menu-dropdown phui-list-sidenav', - 'style' => 'display: none', - ), - $view); - - $help_menu = id(new PHUIMainMenuView()) - ->setOrder(200) - ->setMenuBarItem($help_item) - ->appendChild($dropdown_menu); - - return array( - $help_menu, - ); - } - -} diff --git a/src/applications/home/application/PhabricatorHomeApplication.php b/src/applications/home/application/PhabricatorHomeApplication.php index 8d1b97a797..20858e4931 100644 --- a/src/applications/home/application/PhabricatorHomeApplication.php +++ b/src/applications/home/application/PhabricatorHomeApplication.php @@ -2,7 +2,6 @@ final class PhabricatorHomeApplication extends PhabricatorApplication { - private $quickItems; const DASHBOARD_DEFAULT = 'dashboard:default'; public function getBaseURI() { @@ -26,7 +25,6 @@ final class PhabricatorHomeApplication extends PhabricatorApplication { '/' => 'PhabricatorHomeMainController', '/(?Phome)/' => 'PhabricatorHomeMainController', '/home/' => array( - 'create/' => 'PhabricatorHomeQuickCreateController', 'menu/' => array( '' => 'PhabricatorHomeMenuController', '(?Pglobal|personal)/item/' => $this->getProfileMenuRouting( @@ -44,73 +42,114 @@ final class PhabricatorHomeApplication extends PhabricatorApplication { return 9; } - public function buildMainMenuItems( - PhabricatorUser $user, - PhabricatorController $controller = null) { - - $quick_items = $this->getQuickActionItems($user); - if (!$quick_items) { - return array(); - } - - $items = array(); - $create_id = celerity_generate_unique_node_id(); - - Javelin::initBehavior( - 'aphlict-dropdown', - array( - 'bubbleID' => $create_id, - 'dropdownID' => 'phabricator-quick-create-menu', - 'local' => true, - 'desktop' => true, - 'right' => true, - )); - - $item = id(new PHUIListItemView()) - ->setName(pht('Quick Actions')) - ->setIcon('fa-plus') - ->addClass('core-menu-item') - ->setHref('/home/create/') - ->addSigil('quick-create-menu') - ->setID($create_id) - ->setAural(pht('Quick Actions')) - ->setOrder(300); - $items[] = $item; - - return $items; - } - public function buildMainMenuExtraNodes( PhabricatorUser $viewer, PhabricatorController $controller = null) { - $items = $this->getQuickActionItems($viewer); - - $view = null; - if ($items) { - $view = new PHUIListView(); - foreach ($items as $item) { - $view->addMenuItem($item); - } - - return phutil_tag( - 'div', - array( - 'id' => 'phabricator-quick-create-menu', - 'class' => 'phabricator-main-menu-dropdown phui-list-sidenav', - 'style' => 'display: none', - ), - $view); + if (!$viewer->isLoggedIn()) { + return; } + + $image = $viewer->getProfileImageURI(); + + $profile_image = id(new PHUIIconView()) + ->setImage($image) + ->setHeadSize(PHUIIconView::HEAD_SMALL); + + if ($controller) { + $application = $controller->getCurrentApplication(); + } else { + $application = null; + } + $dropdown_menu = $this->renderUserDropdown($viewer, $application); + + $menu_id = celerity_generate_unique_node_id(); + + Javelin::initBehavior( + 'user-menu', + array( + 'menuID' => $menu_id, + 'menu' => $dropdown_menu->getDropdownMenuMetadata(), + )); + + return id(new PHUIButtonView()) + ->setID($menu_id) + ->setTag('a') + ->setHref('/p/'.$viewer->getUsername().'/') + ->setIcon($profile_image) + ->addClass('phabricator-core-user-menu') + ->setHasCaret(true) + ->setNoCSS(true); + } + + private function renderUserDropdown( + PhabricatorUser $viewer, + $application) { + + $person_to_show = id(new PHUIObjectItemView()) + ->setObjectName($viewer->getRealName()) + ->setSubHead($viewer->getUsername()) + ->setImageURI($viewer->getProfileImageURI()); + + $user_view = id(new PHUIObjectItemListView()) + ->setViewer($viewer) + ->setFlush(true) + ->setSimple(true) + ->addItem($person_to_show) + ->addClass('phabricator-core-user-profile-object'); + + $view = id(new PhabricatorActionListView()) + ->setViewer($viewer); + + // User Menu + $view->addAction( + id(new PhabricatorActionView()) + ->appendChild($user_view)); + + $view->addAction( + id(new PhabricatorActionView()) + ->setType(PhabricatorActionView::TYPE_DIVIDER)); + + $view->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Profile')) + ->setHref('/p/'.$viewer->getUsername().'/')); + + $view->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Settings')) + ->setHref('/settings/user/'.$viewer->getUsername().'/')); + + $view->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Manage')) + ->setHref('/people/manage/'.$viewer->getID().'/')); + + // Help Menus + if ($application) { + $help_links = $application->getHelpMenuItems($viewer); + if ($help_links) { + foreach ($help_links as $link) { + $view->addAction($link); + } + } + } + + // Logout Menu + $view->addAction( + id(new PhabricatorActionView()) + ->addSigil('logout-item') + ->setType(PhabricatorActionView::TYPE_DIVIDER)); + + $view->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Log Out %s', $viewer->getUsername())) + ->addSigil('logout-item') + ->setHref('/logout/') + ->setColor(PhabricatorActionView::RED) + ->setWorkflow(true)); + return $view; } - private function getQuickActionItems(PhabricatorUser $viewer) { - if ($this->quickItems === null) { - $items = PhabricatorQuickActions::loadMenuItemsForUser($viewer); - $this->quickItems = $items; - } - return $this->quickItems; - } - } diff --git a/src/applications/home/controller/PhabricatorHomeQuickCreateController.php b/src/applications/home/controller/PhabricatorHomeQuickCreateController.php deleted file mode 100644 index 0100c40366..0000000000 --- a/src/applications/home/controller/PhabricatorHomeQuickCreateController.php +++ /dev/null @@ -1,47 +0,0 @@ -getViewer(); - - $items = PhabricatorQuickActions::loadMenuItemsForUser($viewer); - - $list = id(new PHUIObjectItemListView()) - ->setUser($viewer); - - foreach ($items as $item) { - $list->addItem( - id(new PHUIObjectItemView()) - ->setHeader($item->getName()) - ->setWorkflow($item->getWorkflow()) - ->setHref($item->getHref())); - } - - $title = pht('Quick Create'); - - $crumbs = $this->buildApplicationCrumbs(); - $crumbs->addTextCrumb(pht('Quick Create')); - $crumbs->setBorder(true); - - $box = id(new PHUIObjectBoxView()) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) - ->setObjectList($list); - - $header = id(new PHUIHeaderView()) - ->setHeader($title) - ->setHeaderIcon('fa-plus-square'); - - $view = id(new PHUITwoColumnView()) - ->setHeader($header) - ->setFooter($box); - - return $this->newPage() - ->setTitle($title) - ->setCrumbs($crumbs) - ->appendChild($view); - - } - -} diff --git a/src/applications/maniphest/editor/ManiphestEditEngine.php b/src/applications/maniphest/editor/ManiphestEditEngine.php index 8e5893a9b8..0433e8200a 100644 --- a/src/applications/maniphest/editor/ManiphestEditEngine.php +++ b/src/applications/maniphest/editor/ManiphestEditEngine.php @@ -21,6 +21,10 @@ final class ManiphestEditEngine return 'PhabricatorManiphestApplication'; } + public function isDefaultQuickCreateEngine() { + return true; + } + protected function newEditableObject() { return ManiphestTask::initializeNewTask($this->getViewer()); } diff --git a/src/applications/people/controller/PhabricatorPeopleProfileManageController.php b/src/applications/people/controller/PhabricatorPeopleProfileManageController.php index c5a3ceabd4..ba533c041c 100644 --- a/src/applications/people/controller/PhabricatorPeopleProfileManageController.php +++ b/src/applications/people/controller/PhabricatorPeopleProfileManageController.php @@ -45,11 +45,6 @@ final class PhabricatorPeopleProfileManageController $nav = $this->getProfileMenu(); $nav->selectFilter(PhabricatorPeopleProfileMenuEngine::ITEM_MANAGE); - $timeline = $this->buildTransactionTimeline( - $user, - new PhabricatorPeopleTransactionQuery()); - $timeline->setShouldTerminate(true); - $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb(pht('Manage')); $crumbs->setBorder(true); @@ -57,11 +52,7 @@ final class PhabricatorPeopleProfileManageController $manage = id(new PHUITwoColumnView()) ->setHeader($header) ->setCurtain($curtain) - ->addPropertySection(pht('Details'), $properties) - ->setMainColumn( - array( - $timeline, - )); + ->addPropertySection(pht('Details'), $properties); return $this->newPage() ->setTitle( diff --git a/src/applications/people/extension/PhabricatorPeopleMainMenuBarExtension.php b/src/applications/people/extension/PhabricatorPeopleMainMenuBarExtension.php deleted file mode 100644 index 5028280ac4..0000000000 --- a/src/applications/people/extension/PhabricatorPeopleMainMenuBarExtension.php +++ /dev/null @@ -1,41 +0,0 @@ -getViewer(); - $image = $viewer->getProfileImageURI(); - - $bar_item = id(new PHUIListItemView()) - ->setName($viewer->getUsername()) - ->setHref('/p/'.$viewer->getUsername().'/') - ->addClass('core-menu-item') - ->setAural(pht('Profile')); - - $classes = array( - 'phabricator-core-menu-icon', - 'phabricator-core-menu-profile-image', - ); - - $bar_item->appendChild( - phutil_tag( - 'span', - array( - 'class' => implode(' ', $classes), - 'style' => 'background-image: url('.$image.')', - ), - '')); - - $profile_menu = id(new PHUIMainMenuView()) - ->setOrder(100) - ->setMenuBarItem($bar_item); - - return array( - $profile_menu, - ); - } - -} diff --git a/src/applications/phame/application/PhabricatorPhameApplication.php b/src/applications/phame/application/PhabricatorPhameApplication.php index 8b4d991591..677872ba1e 100644 --- a/src/applications/phame/application/PhabricatorPhameApplication.php +++ b/src/applications/phame/application/PhabricatorPhameApplication.php @@ -11,7 +11,7 @@ final class PhabricatorPhameApplication extends PhabricatorApplication { } public function getIcon() { - return 'fa-star'; + return 'fa-feed'; } public function getShortDescription() { diff --git a/src/applications/project/engine/PhabricatorProjectEditEngine.php b/src/applications/project/engine/PhabricatorProjectEditEngine.php index 760fad39d0..7a0c11be0e 100644 --- a/src/applications/project/engine/PhabricatorProjectEditEngine.php +++ b/src/applications/project/engine/PhabricatorProjectEditEngine.php @@ -26,6 +26,10 @@ final class PhabricatorProjectEditEngine return $this->milestoneProject; } + public function isDefaultQuickCreateEngine() { + return true; + } + public function getEngineName() { return pht('Projects'); } diff --git a/src/applications/repository/storage/PhabricatorRepositoryAuditRequest.php b/src/applications/repository/storage/PhabricatorRepositoryAuditRequest.php index f0a17718aa..ea86594d9e 100644 --- a/src/applications/repository/storage/PhabricatorRepositoryAuditRequest.php +++ b/src/applications/repository/storage/PhabricatorRepositoryAuditRequest.php @@ -49,6 +49,19 @@ final class PhabricatorRepositoryAuditRequest return $this->assertAttached($this->commit); } + public function isActiveAudit() { + switch ($this->getAuditStatus()) { + case PhabricatorAuditStatusConstants::NONE: + case PhabricatorAuditStatusConstants::AUDIT_NOT_REQUIRED: + case PhabricatorAuditStatusConstants::RESIGNED: + case PhabricatorAuditStatusConstants::CLOSED: + case PhabricatorAuditStatusConstants::CC: + return false; + } + + return true; + } + public function isInteresting() { switch ($this->getAuditStatus()) { case PhabricatorAuditStatusConstants::NONE: diff --git a/src/applications/repository/storage/PhabricatorRepositoryCommit.php b/src/applications/repository/storage/PhabricatorRepositoryCommit.php index 67f187d9c2..7f617069ec 100644 --- a/src/applications/repository/storage/PhabricatorRepositoryCommit.php +++ b/src/applications/repository/storage/PhabricatorRepositoryCommit.php @@ -14,7 +14,8 @@ final class PhabricatorRepositoryCommit PhabricatorCustomFieldInterface, PhabricatorApplicationTransactionInterface, PhabricatorFulltextInterface, - PhabricatorConduitResultInterface { + PhabricatorConduitResultInterface, + PhabricatorDraftInterface { protected $repositoryID; protected $phid; @@ -39,6 +40,7 @@ final class PhabricatorRepositoryCommit private $audits = self::ATTACHABLE; private $repository = self::ATTACHABLE; private $customFields = self::ATTACHABLE; + private $drafts = array(); public function attachRepository(PhabricatorRepository $repository) { $this->repository = $repository; @@ -342,6 +344,7 @@ final class PhabricatorRepositoryCommit return nonempty($parsed->getDisplayName(), $parsed->getAddress()); } + /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { @@ -603,4 +606,20 @@ final class PhabricatorRepositoryCommit return array(); } + +/* -( PhabricatorDraftInterface )------------------------------------------ */ + + public function newDraftEngine() { + return new DiffusionCommitDraftEngine(); + } + + public function getHasDraft(PhabricatorUser $viewer) { + return $this->assertAttachedKey($this->drafts, $viewer->getCacheFragment()); + } + + public function attachHasDraft(PhabricatorUser $viewer, $has_draft) { + $this->drafts[$viewer->getCacheFragment()] = $has_draft; + return $this; + } + } diff --git a/src/applications/search/editor/PhabricatorProfileMenuEditEngine.php b/src/applications/search/editor/PhabricatorProfileMenuEditEngine.php index 70ba141967..b21d03cbd1 100644 --- a/src/applications/search/editor/PhabricatorProfileMenuEditEngine.php +++ b/src/applications/search/editor/PhabricatorProfileMenuEditEngine.php @@ -109,6 +109,7 @@ final class PhabricatorProfileMenuEditEngine } protected function getObjectEditTitleText($object) { + $object->willBuildNavigationItems(array($object)); return pht('Edit Menu Item: %s', $object->getDisplayName()); } @@ -148,4 +149,47 @@ final class PhabricatorProfileMenuEditEngine return $fields; } + protected function getValidationExceptionShortMessage( + PhabricatorApplicationTransactionValidationException $ex, + PhabricatorEditField $field) { + + // Menu item properties all have the same transaction type, so we need + // to make sure errors about a specific property (like the URI for a + // link) are only applied to the field for that particular property. If + // we don't do this, the red error text like "Required" will display + // next to every field. + + $property_type = + PhabricatorProfileMenuItemConfigurationTransaction::TYPE_PROPERTY; + + $xaction_type = $field->getTransactionType(); + if ($xaction_type == $property_type) { + $field_key = $field->getKey(); + foreach ($ex->getErrors() as $error) { + if ($error->getType() !== $xaction_type) { + continue; + } + + $xaction = $error->getTransaction(); + if (!$xaction) { + continue; + } + + $xaction_setting = $xaction->getMetadataValue('property.key'); + if ($xaction_setting != $field_key) { + continue; + } + + $short_message = $error->getShortMessage(); + if ($short_message !== null) { + return $short_message; + } + } + + return null; + } + + return parent::getValidationExceptionShortMessage($ex, $field); + } + } diff --git a/src/applications/search/editor/PhabricatorProfileMenuEditor.php b/src/applications/search/editor/PhabricatorProfileMenuEditor.php index d91bba272b..308cde0db5 100644 --- a/src/applications/search/editor/PhabricatorProfileMenuEditor.php +++ b/src/applications/search/editor/PhabricatorProfileMenuEditor.php @@ -87,4 +87,39 @@ final class PhabricatorProfileMenuEditor return parent::applyCustomExternalTransaction($object, $xaction); } + protected function validateTransaction( + PhabricatorLiskDAO $object, + $type, + array $xactions) { + + $errors = parent::validateTransaction($object, $type, $xactions); + + $actor = $this->getActor(); + $menu_item = $object->getMenuItem(); + $menu_item->setViewer($actor); + + switch ($type) { + case PhabricatorProfileMenuItemConfigurationTransaction::TYPE_PROPERTY: + $key_map = array(); + foreach ($xactions as $xaction) { + $xaction_key = $xaction->getMetadataValue('property.key'); + $old = $this->getCustomTransactionOldValue($object, $xaction); + $new = $xaction->getNewValue(); + $key_map[$xaction_key][] = array( + 'xaction' => $xaction, + 'old' => $old, + 'new' => $new, + ); + } + + foreach ($object->validateTransactions($key_map) as $error) { + $errors[] = $error; + } + break; + } + + return $errors; + } + + } diff --git a/src/applications/search/engine/PhabricatorProfileMenuEngine.php b/src/applications/search/engine/PhabricatorProfileMenuEngine.php index c1d4df3b2a..3e11436ced 100644 --- a/src/applications/search/engine/PhabricatorProfileMenuEngine.php +++ b/src/applications/search/engine/PhabricatorProfileMenuEngine.php @@ -6,9 +6,16 @@ abstract class PhabricatorProfileMenuEngine extends Phobject { private $profileObject; private $customPHID; private $items; + private $menuType = self::MENU_GLOBAL; private $defaultItem; private $controller; private $navigation; + private $showNavigation = true; + + const MENU_GLOBAL = 'global'; + const MENU_PERSONAL = 'personal'; + const MENU_COMBINED = 'menu'; + const ITEM_CUSTOM_DIVIDER = 'engine.divider'; public function setViewer(PhabricatorUser $viewer) { $this->viewer = $viewer; @@ -57,10 +64,35 @@ abstract class PhabricatorProfileMenuEngine extends Phobject { return $this->defaultItem; } - abstract protected function getItemURI($path); + public function setMenuType($type) { + $this->menuType = $type; + return $this; + } + private function getMenuType() { + return $this->menuType; + } + + public function setShowNavigation($show) { + $this->showNavigation = $show; + return $this; + } + + public function getShowNavigation() { + return $this->showNavigation; + } + + abstract protected function getItemURI($path); abstract protected function isMenuEngineConfigurable(); + abstract protected function getBuiltinProfileItems($object); + + protected function getBuiltinCustomProfileItems( + $object, + $custom_phid) { + return array(); + } + public function buildResponse() { $controller = $this->getController(); @@ -130,6 +162,14 @@ abstract class PhabricatorProfileMenuEngine extends Phobject { $navigation->selectFilter('item.configure'); $crumbs = $controller->buildApplicationCrumbsForEditEngine(); + switch ($this->getMenuType()) { + case 'personal': + $crumbs->addTextCrumb(pht('Personal')); + break; + case 'global': + $crumbs->addTextCrumb(pht('Global')); + break; + } switch ($item_action) { case 'view': @@ -177,11 +217,15 @@ abstract class PhabricatorProfileMenuEngine extends Phobject { $crumbs->setBorder(true); - return $controller->newPage() + $page = $controller->newPage() ->setTitle(pht('Configure Menu')) - ->setNavigation($navigation) ->setCrumbs($crumbs) ->appendChild($content); + + if ($this->getShowNavigation()) { + $page->setNavigation($navigation); + } + return $page; } public function buildNavigation() { @@ -194,6 +238,7 @@ abstract class PhabricatorProfileMenuEngine extends Phobject { ->setBaseURI(new PhutilURI($this->getItemURI(''))); $menu_items = $this->getItems(); + $filtered_items = array(); foreach ($menu_items as $menu_item) { if ($menu_item->isDisabled()) { @@ -239,11 +284,6 @@ abstract class PhabricatorProfileMenuEngine extends Phobject { } } - $more_items = $this->newAutomaticMenuItems($nav); - foreach ($more_items as $item) { - $nav->addMenuItem($item); - } - $nav->selectFilter(null); $this->navigation = $nav; @@ -264,19 +304,25 @@ abstract class PhabricatorProfileMenuEngine extends Phobject { $items = $this->loadBuiltinProfileItems(); - if ($this->getCustomPHID()) { - $stored_items = id(new PhabricatorProfileMenuItemConfigurationQuery()) - ->setViewer($viewer) - ->withProfilePHIDs(array($object->getPHID())) - ->withCustomPHIDs(array($this->getCustomPHID())) - ->execute(); - } else { - $stored_items = id(new PhabricatorProfileMenuItemConfigurationQuery()) - ->setViewer($viewer) - ->withProfilePHIDs(array($object->getPHID())) - ->execute(); + $query = id(new PhabricatorProfileMenuItemConfigurationQuery()) + ->setViewer($viewer) + ->withProfilePHIDs(array($object->getPHID())); + + $menu_type = $this->getMenuType(); + switch ($menu_type) { + case self::MENU_GLOBAL: + $query->withCustomPHIDs(array(), true); + break; + case self::MENU_PERSONAL: + $query->withCustomPHIDs(array($this->getCustomPHID()), false); + break; + case self::MENU_COMBINED: + $query->withCustomPHIDs(array($this->getCustomPHID()), true); + break; } + $stored_items = $query->execute(); + foreach ($stored_items as $stored_item) { $impl = $stored_item->getMenuItem(); $impl->setViewer($viewer); @@ -305,12 +351,7 @@ abstract class PhabricatorProfileMenuEngine extends Phobject { } } - $items = msort($items, 'getSortKey'); - - // Normalize keys since callers shouldn't rely on this array being - // partially keyed. - $items = array_values($items); - + $items = $this->arrangeItems($items); // Make sure exactly one valid item is marked as default. $default = null; @@ -343,7 +384,26 @@ abstract class PhabricatorProfileMenuEngine extends Phobject { private function loadBuiltinProfileItems() { $object = $this->getProfileObject(); - $builtins = $this->getBuiltinProfileItems($object); + + $menu_type = $this->getMenuType(); + switch ($menu_type) { + case self::MENU_GLOBAL: + $builtins = $this->getBuiltinProfileItems($object); + break; + case self::MENU_PERSONAL: + $builtins = $this->getBuiltinCustomProfileItems( + $object, + $this->getCustomPHID()); + break; + case self::MENU_COMBINED: + $builtins = array(); + $builtins[] = $this->getBuiltinCustomProfileItems( + $object, + $this->getCustomPHID()); + $builtins[] = $this->getBuiltinProfileItems($object); + $builtins = array_mergev($builtins); + break; + } $items = PhabricatorProfileMenuItem::getAllMenuItems(); $viewer = $this->getViewer(); @@ -410,73 +470,6 @@ abstract class PhabricatorProfileMenuEngine extends Phobject { } } - private function newAutomaticMenuItems(AphrontSideNavFilterView $nav) { - $items = array(); - - // NOTE: We're adding a spacer item for the fixed footer, so that if the - // menu taller than the page content you can still scroll down the page far - // enough to access the last item without the content being obscured by the - // fixed items. - $items[] = id(new PHUIListItemView()) - ->setHideInApplicationMenu(true) - ->addClass('phui-profile-menu-spacer'); - - $collapse_id = celerity_generate_unique_node_id(); - $viewer = $this->getViewer(); - $collapse_key = PhabricatorProfileMenuCollapsedSetting::SETTINGKEY; - - $is_collapsed = $viewer->getUserSetting($collapse_key); - - if ($is_collapsed) { - $nav->addClass('phui-profile-menu-collapsed'); - } else { - $nav->addClass('phui-profile-menu-expanded'); - } - - if ($viewer->isLoggedIn()) { - $settings_uri = '/settings/adjust/?key='.$collapse_key; - } else { - $settings_uri = null; - } - - Javelin::initBehavior( - 'phui-profile-menu', - array( - 'menuID' => $nav->getMainID(), - 'collapseID' => $collapse_id, - 'isCollapsed' => (bool)$is_collapsed, - 'settingsURI' => $settings_uri, - )); - - $collapse_icon = id(new PHUIIconCircleView()) - ->addClass('phui-list-item-icon') - ->addClass('phui-profile-menu-visible-when-expanded') - ->setIcon('fa-chevron-left'); - - $expand_icon = id(new PHUIIconCircleView()) - ->addClass('phui-list-item-icon') - ->addClass('phui-profile-menu-visible-when-collapsed') - ->addSigil('has-tooltip') - ->setMetadata( - array( - 'tip' => pht('Expand'), - 'align' => 'E', - )) - ->setIcon('fa-chevron-right'); - - $items[] = id(new PHUIListItemView()) - ->setName('Collapse') - ->addIcon($collapse_icon) - ->addIcon($expand_icon) - ->setID($collapse_id) - ->addClass('phui-profile-menu-footer') - ->addClass('phui-profile-menu-footer-1') - ->setHideInApplicationMenu(true) - ->setHref('#'); - - return $items; - } - public function getConfigureURI() { return $this->getItemURI('configure/'); } @@ -558,10 +551,22 @@ abstract class PhabricatorProfileMenuEngine extends Phobject { $viewer = $this->getViewer(); $object = $this->getProfileObject(); - PhabricatorPolicyFilter::requireCapability( - $viewer, - $object, - PhabricatorPolicyCapability::CAN_EDIT); + $filtered_groups = mgroup($items, 'getMenuItemKey'); + foreach ($filtered_groups as $group) { + $first_item = head($group); + $first_item->willBuildNavigationItems($group); + } + + // Users only need to be able to edit the object which this menu appears + // on if they're editing global menu items. For example, users do not need + // to be able to edit the Favorites application to add new items to the + // Favorites menu. + if (!$this->getCustomPHID()) { + PhabricatorPolicyFilter::requireCapability( + $viewer, + $object, + PhabricatorPolicyCapability::CAN_EDIT); + } $list_id = celerity_generate_unique_node_id(); @@ -573,7 +578,8 @@ abstract class PhabricatorProfileMenuEngine extends Phobject { )); $list = id(new PHUIObjectItemListView()) - ->setID($list_id); + ->setID($list_id) + ->setNoDataString(pht('This menu currently has no items.')); foreach ($items as $item) { $id = $item->getID(); @@ -710,11 +716,11 @@ abstract class PhabricatorProfileMenuEngine extends Phobject { ->setName($doc_name)); $header = id(new PHUIHeaderView()) - ->setHeader(pht('Profile Menu Items')) + ->setHeader(pht('Menu Items')) ->setHeaderIcon('fa-list'); $box = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Navigation')) + ->setHeaderText(pht('Current Menu Items')) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->setObjectList($list); @@ -1022,4 +1028,40 @@ abstract class PhabricatorProfileMenuEngine extends Phobject { return $this; } + private function arrangeItems(array $items) { + // Sort the items. + $items = msortv($items, 'getSortVector'); + + // If we have some global items and some custom items and are in "combined" + // mode, put a hard-coded divider item between them. + if ($this->getMenuType() == self::MENU_COMBINED) { + $list = array(); + $seen_custom = false; + $seen_global = false; + foreach ($items as $item) { + if ($item->getCustomPHID()) { + $seen_custom = true; + } else { + if ($seen_custom && !$seen_global) { + $list[] = $this->newItem() + ->setBuiltinKey(self::ITEM_CUSTOM_DIVIDER) + ->setMenuItemKey(PhabricatorDividerProfileMenuItem::MENUITEMKEY) + ->attachMenuItem( + new PhabricatorDividerProfileMenuItem()); + } + $seen_global = true; + } + $list[] = $item; + } + $items = $list; + } + + // Normalize keys since callers shouldn't rely on this array being + // partially keyed. + $items = array_values($items); + + return $items; + } + + } diff --git a/src/applications/search/menuitem/PhabricatorApplicationProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorApplicationProfileMenuItem.php index 214819100e..7d87bc25d4 100644 --- a/src/applications/search/menuitem/PhabricatorApplicationProfileMenuItem.php +++ b/src/applications/search/menuitem/PhabricatorApplicationProfileMenuItem.php @@ -5,6 +5,8 @@ final class PhabricatorApplicationProfileMenuItem const MENUITEMKEY = 'application'; + const FIELD_APPLICATION = 'application'; + public function getMenuItemTypeIcon() { return 'fa-globe'; } @@ -19,30 +21,45 @@ final class PhabricatorApplicationProfileMenuItem public function getDisplayName( PhabricatorProfileMenuItemConfiguration $config) { - $app = $this->getApplication($config); - if ($app) { - return $app->getName(); - } else { - return pht('(Uninstalled Application)'); + $application = $this->getApplication($config); + if (!$application) { + return pht('(Restricted/Invalid Application)'); } - return $app->getName(); + + $name = $this->getName($config); + if (strlen($name)) { + return $name; + } + + return $application->getName(); } public function buildEditEngineFields( PhabricatorProfileMenuItemConfiguration $config) { return array( id(new PhabricatorDatasourceEditField()) - ->setKey('application') + ->setKey(self::FIELD_APPLICATION) ->setLabel(pht('Application')) ->setDatasource(new PhabricatorApplicationDatasource()) + ->setIsRequired(true) ->setSingleValue($config->getMenuItemProperty('application')), + id(new PhabricatorTextEditField()) + ->setKey('name') + ->setLabel(pht('Name')) + ->setValue($this->getName($config)), ); } + private function getName( + PhabricatorProfileMenuItemConfiguration $config) { + return $config->getMenuItemProperty('name'); + } + private function getApplication( PhabricatorProfileMenuItemConfiguration $config) { $viewer = $this->getViewer(); $phid = $config->getMenuItemProperty('application'); + $app = id(new PhabricatorApplicationQuery()) ->setViewer($viewer) ->withPHIDs(array($phid)) @@ -68,7 +85,7 @@ final class PhabricatorApplicationProfileMenuItem $item = $this->newItem() ->setHref($app->getApplicationURI()) - ->setName($app->getName()) + ->setName($this->getDisplayName($config)) ->setIcon($app->getIcon()); return array( @@ -76,4 +93,49 @@ final class PhabricatorApplicationProfileMenuItem ); } + public function validateTransactions( + PhabricatorProfileMenuItemConfiguration $config, + $field_key, + $value, + array $xactions) { + + $viewer = $this->getViewer(); + $errors = array(); + + if ($field_key == self::FIELD_APPLICATION) { + if ($this->isEmptyTransaction($value, $xactions)) { + $errors[] = $this->newRequiredError( + pht('You must choose an application.'), + $field_key); + } + + foreach ($xactions as $xaction) { + $new = $xaction['new']; + + if (!$new) { + continue; + } + + if ($new === $value) { + continue; + } + + $applications = id(new PhabricatorApplicationQuery()) + ->setViewer($viewer) + ->withPHIDs(array($new)) + ->execute(); + if (!$applications) { + $errors[] = $this->newInvalidError( + pht( + 'Application "%s" is not a valid application which you have '. + 'permission to see.', + $new), + $xaction['xaction']); + } + } + } + + return $errors; + } + } diff --git a/src/applications/search/menuitem/PhabricatorDashboardProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorDashboardProfileMenuItem.php index 9074b1b117..c9a13bd4ab 100644 --- a/src/applications/search/menuitem/PhabricatorDashboardProfileMenuItem.php +++ b/src/applications/search/menuitem/PhabricatorDashboardProfileMenuItem.php @@ -5,6 +5,8 @@ final class PhabricatorDashboardProfileMenuItem const MENUITEMKEY = 'dashboard'; + const FIELD_DASHBOARD = 'dashboardPHID'; + private $dashboard; public function getMenuItemTypeIcon() { @@ -70,15 +72,16 @@ final class PhabricatorDashboardProfileMenuItem public function buildEditEngineFields( PhabricatorProfileMenuItemConfiguration $config) { return array( + id(new PhabricatorDatasourceEditField()) + ->setKey(self::FIELD_DASHBOARD) + ->setLabel(pht('Dashboard')) + ->setIsRequired(true) + ->setDatasource(new PhabricatorDashboardDatasource()) + ->setSingleValue($config->getMenuItemProperty('dashboardPHID')), id(new PhabricatorTextEditField()) ->setKey('name') ->setLabel(pht('Name')) ->setValue($this->getName($config)), - id(new PhabricatorDatasourceEditField()) - ->setKey('dashboardPHID') - ->setLabel(pht('Dashboard')) - ->setDatasource(new PhabricatorDashboardDatasource()) - ->setSingleValue($config->getMenuItemProperty('dashboardPHID')), ); } @@ -109,4 +112,49 @@ final class PhabricatorDashboardProfileMenuItem ); } + public function validateTransactions( + PhabricatorProfileMenuItemConfiguration $config, + $field_key, + $value, + array $xactions) { + + $viewer = $this->getViewer(); + $errors = array(); + + if ($field_key == self::FIELD_DASHBOARD) { + if ($this->isEmptyTransaction($value, $xactions)) { + $errors[] = $this->newRequiredError( + pht('You must choose a dashboard.'), + $field_key); + } + + foreach ($xactions as $xaction) { + $new = $xaction['new']; + + if (!$new) { + continue; + } + + if ($new === $value) { + continue; + } + + $dashboards = id(new PhabricatorDashboardQuery()) + ->setViewer($viewer) + ->withPHIDs(array($new)) + ->execute(); + if (!$dashboards) { + $errors[] = $this->newInvalidError( + pht( + 'Dashboard "%s" is not a valid dashboard which you have '. + 'permission to see.', + $new), + $xaction['xaction']); + } + } + } + + return $errors; + } + } diff --git a/src/applications/search/menuitem/PhabricatorEditEngineProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorEditEngineProfileMenuItem.php index 6622bb7506..4b840d39e3 100644 --- a/src/applications/search/menuitem/PhabricatorEditEngineProfileMenuItem.php +++ b/src/applications/search/menuitem/PhabricatorEditEngineProfileMenuItem.php @@ -5,6 +5,8 @@ final class PhabricatorEditEngineProfileMenuItem const MENUITEMKEY = 'editengine'; + const FIELD_FORM = 'formKey'; + private $form; public function getMenuItemTypeIcon() { @@ -12,7 +14,7 @@ final class PhabricatorEditEngineProfileMenuItem } public function getMenuItemTypeName() { - return pht('Forms'); + return pht('Form'); } public function canAddToObject($object) { @@ -51,7 +53,8 @@ final class PhabricatorEditEngineProfileMenuItem foreach ($items as $item) { $key = $item->getMenuItemProperty('formKey'); - list($engine_key, $form_key) = explode('/', $key); + list($engine_key, $form_key) = PhabricatorEditEngine::splitFullKey($key); + if (is_numeric($form_key)) { $form = idx($form_ids, $form_key, null); $item->getMenuItem()->attachForm($form); @@ -78,15 +81,16 @@ final class PhabricatorEditEngineProfileMenuItem public function buildEditEngineFields( PhabricatorProfileMenuItemConfiguration $config) { return array( + id(new PhabricatorDatasourceEditField()) + ->setKey(self::FIELD_FORM) + ->setLabel(pht('Form')) + ->setIsRequired(true) + ->setDatasource(new PhabricatorEditEngineDatasource()) + ->setSingleValue($config->getMenuItemProperty('formKey')), id(new PhabricatorTextEditField()) ->setKey('name') ->setLabel(pht('Name')) ->setValue($this->getName($config)), - id(new PhabricatorDatasourceEditField()) - ->setKey('formKey') - ->setLabel(pht('Form')) - ->setDatasource(new PhabricatorEditEngineDatasource()) - ->setSingleValue($config->getMenuItemProperty('formKey')), ); } @@ -119,4 +123,53 @@ final class PhabricatorEditEngineProfileMenuItem ); } + public function validateTransactions( + PhabricatorProfileMenuItemConfiguration $config, + $field_key, + $value, + array $xactions) { + + $viewer = $this->getViewer(); + $errors = array(); + + if ($field_key == self::FIELD_FORM) { + if ($this->isEmptyTransaction($value, $xactions)) { + $errors[] = $this->newRequiredError( + pht('You must choose a form.'), + $field_key); + } + + foreach ($xactions as $xaction) { + $new = $xaction['new']; + + if (!$new) { + continue; + } + + if ($new === $value) { + continue; + } + + list($engine_key, $form_key) = PhabricatorEditEngine::splitFullKey( + $new); + + $forms = id(new PhabricatorEditEngineConfigurationQuery()) + ->setViewer($viewer) + ->withEngineKeys(array($engine_key)) + ->withIdentifiers(array($form_key)) + ->execute(); + if (!$forms) { + $errors[] = $this->newInvalidError( + pht( + 'Form "%s" is not a valid form which you have permission to '. + 'see.', + $new), + $xaction['xaction']); + } + } + } + + return $errors; + } + } diff --git a/src/applications/search/menuitem/PhabricatorLinkProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorLinkProfileMenuItem.php index 5571788cc1..3b136321c2 100644 --- a/src/applications/search/menuitem/PhabricatorLinkProfileMenuItem.php +++ b/src/applications/search/menuitem/PhabricatorLinkProfileMenuItem.php @@ -5,6 +5,9 @@ final class PhabricatorLinkProfileMenuItem const MENUITEMKEY = 'link'; + const FIELD_URI = 'uri'; + const FIELD_NAME = 'name'; + public function getMenuItemTypeIcon() { return 'fa-link'; } @@ -26,12 +29,12 @@ final class PhabricatorLinkProfileMenuItem PhabricatorProfileMenuItemConfiguration $config) { return array( id(new PhabricatorTextEditField()) - ->setKey('name') + ->setKey(self::FIELD_NAME) ->setLabel(pht('Name')) ->setIsRequired(true) ->setValue($this->getLinkName($config)), id(new PhabricatorTextEditField()) - ->setKey('uri') + ->setKey(self::FIELD_URI) ->setLabel(pht('URI')) ->setIsRequired(true) ->setValue($this->getLinkURI($config)), @@ -91,4 +94,53 @@ final class PhabricatorLinkProfileMenuItem ); } + public function validateTransactions( + PhabricatorProfileMenuItemConfiguration $config, + $field_key, + $value, + array $xactions) { + + $viewer = $this->getViewer(); + $errors = array(); + + if ($field_key == self::FIELD_NAME) { + if ($this->isEmptyTransaction($value, $xactions)) { + $errors[] = $this->newRequiredError( + pht('You must choose a link name.'), + $field_key); + } + } + + if ($field_key == self::FIELD_URI) { + if ($this->isEmptyTransaction($value, $xactions)) { + $errors[] = $this->newRequiredError( + pht('You must choose a URI to link to.'), + $field_key); + } + + foreach ($xactions as $xaction) { + $new = $xaction['new']; + + if (!$new) { + continue; + } + + if ($new === $value) { + continue; + } + + if (!$this->isValidLinkURI($new)) { + $errors[] = $this->newInvalidError( + pht( + 'URI "%s" is not a valid link URI. It should be a full, valid '. + 'URI beginning with a protocol like "%s".', + $new, + 'https://'), + $xaction['xaction']); + } + } + } + + return $errors; + } } diff --git a/src/applications/search/menuitem/PhabricatorMotivatorProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorMotivatorProfileMenuItem.php deleted file mode 100644 index f53bc2b0eb..0000000000 --- a/src/applications/search/menuitem/PhabricatorMotivatorProfileMenuItem.php +++ /dev/null @@ -1,164 +0,0 @@ -getOptions(); - $name = idx($options, $config->getMenuItemProperty('source')); - if ($name !== null) { - return pht('Motivator: %s', $name); - } else { - return pht('Motivator'); - } - } - - public function buildEditEngineFields( - PhabricatorProfileMenuItemConfiguration $config) { - return array( - id(new PhabricatorInstructionsEditField()) - ->setValue( - pht( - 'Motivate your team with inspirational quotes from great minds. '. - 'This menu item shows a new quote every day.')), - id(new PhabricatorSelectEditField()) - ->setKey('source') - ->setLabel(pht('Source')) - ->setOptions($this->getOptions()), - ); - } - - private function getOptions() { - return array( - 'catfacts' => pht('Cat Facts'), - ); - } - - protected function newNavigationMenuItems( - PhabricatorProfileMenuItemConfiguration $config) { - - $source = $config->getMenuItemProperty('source'); - - switch ($source) { - case 'catfacts': - default: - $facts = $this->getCatFacts(); - break; - } - - $fact = $this->selectFact($facts); - - switch ($source) { - case 'catfacts': - default: - $fact = array( - id(new PHUIIconView())->setIcon('fa-paw'), - ' ', - $fact, - ); - break; - } - - $fact = phutil_tag( - 'div', - array( - 'class' => 'phui-motivator', - ), - $fact); - - $item = $this->newItem() - ->appendChild($fact); - - return array( - $item, - ); - } - - private function getCatFacts() { - return array( - pht('Cats purr when they are happy, upset, or asleep.'), - pht('The first cats evolved on the savanah about 8,000 years ago.'), - pht( - 'Cats have a tail, two feet, between one and three ears, and two '. - 'other feet.'), - pht('Cats use their keen sense of smell to avoid feeling empathy.'), - pht('The first cats evolved in swamps about 65 years ago.'), - pht( - 'You can tell how warm a cat is by examining the coloration: cooler '. - 'areas are darker.'), - pht( - 'Cat tails are flexible because they contain thousands of tiny '. - 'bones.'), - pht( - 'A cattail is a wetland plant with an appearance that resembles '. - 'the tail of a cat.'), - pht( - 'Cats must eat a diet rich in fish to replace the tiny bones in '. - 'their tails.'), - pht('Cats are stealthy predators and nearly invisible to radar.'), - pht( - 'Cats use a special type of magnetism to help them land on their '. - 'feet.'), - pht( - 'A cat can run seven times faster than a human, but only for a '. - 'short distance.'), - pht( - 'The largest recorded cat was nearly 11 inches long from nose to '. - 'tail.'), - pht( - 'Not all cats can retract their claws, but most of them can.'), - pht( - 'In the wild, cats and racoons sometimes hunt together in packs.'), - pht( - 'The Spanish word for cat is "cato". The biggest cat is called '. - '"el cato".'), - pht( - 'The Japanese word for cat is "kome", which is also the word for '. - 'rice. Japanese cats love to eat rice, so the two are synonymous.'), - pht('Cats have five pointy ends.'), - pht('cat -A can find mice hiding in files.'), - pht('A cat\'s visual, olfactory, and auditory senses, '. - 'Contribute to their hunting skills and natural defenses.'), - pht( - 'Cats with high self-esteem seek out high perches '. - 'to launch their attacks. Watch out!'), - pht('Cats prefer vanilla ice cream.'), - pht('Taco cat spelled backwards is taco cat.'), - pht( - 'Cats will often bring you their prey because they feel sorry '. - 'for your inability to hunt.'), - pht('Cats spend most of their time plotting to kill their owner.'), - ); - } - - private function selectFact(array $facts) { - // This is a simple pseudorandom number generator that avoids touching - // srand(), because it would seed it to a highly predictable value. It - // selects a new fact every day. - - $seed = ((int)date('Y') * 366) + (int)date('z'); - for ($ii = 0; $ii < 32; $ii++) { - $seed = ((1664525 * $seed) + 1013904223) % (1 << 31); - } - - return $facts[$seed % count($facts)]; - } - - -} diff --git a/src/applications/search/menuitem/PhabricatorProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorProfileMenuItem.php index c47d9afe8e..05fa6543d3 100644 --- a/src/applications/search/menuitem/PhabricatorProfileMenuItem.php +++ b/src/applications/search/menuitem/PhabricatorProfileMenuItem.php @@ -70,4 +70,41 @@ abstract class PhabricatorProfileMenuItem extends Phobject { return new PHUIListItemView(); } + public function valdateTransactions( + PhabricatorProfileMenuItemConfiguration $config, + $field_key, + $value, + array $xactions) { + return array(); + } + + final protected function isEmptyTransaction($value, array $xactions) { + $result = $value; + foreach ($xactions as $xaction) { + $result = $xaction['new']; + } + + return !strlen($result); + } + + final protected function newError($title, $message, $xaction = null) { + return new PhabricatorApplicationTransactionValidationError( + PhabricatorProfileMenuItemConfigurationTransaction::TYPE_PROPERTY, + $title, + $message, + $xaction); + } + + final protected function newRequiredError($message, $type) { + $xaction = id(new PhabricatorProfileMenuItemConfigurationTransaction()) + ->setMetadataValue('property.key', $type); + + return $this->newError(pht('Required'), $message, $xaction) + ->setIsMissingFieldError(true); + } + + final protected function newInvalidError($message, $xaction = null) { + return $this->newError(pht('Invalid'), $message, $xaction); + } + } diff --git a/src/applications/search/menuitem/PhabricatorProjectProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorProjectProfileMenuItem.php index 002a3fcace..aadabd179a 100644 --- a/src/applications/search/menuitem/PhabricatorProjectProfileMenuItem.php +++ b/src/applications/search/menuitem/PhabricatorProjectProfileMenuItem.php @@ -4,6 +4,7 @@ final class PhabricatorProjectProfileMenuItem extends PhabricatorProfileMenuItem { const MENUITEMKEY = 'project'; + const FIELD_PROJECT = 'project'; private $project; @@ -71,15 +72,16 @@ final class PhabricatorProjectProfileMenuItem public function buildEditEngineFields( PhabricatorProfileMenuItemConfiguration $config) { return array( + id(new PhabricatorDatasourceEditField()) + ->setKey(self::FIELD_PROJECT) + ->setLabel(pht('Project')) + ->setIsRequired(true) + ->setDatasource(new PhabricatorProjectDatasource()) + ->setSingleValue($config->getMenuItemProperty('project')), id(new PhabricatorTextEditField()) ->setKey('name') ->setLabel(pht('Name')) ->setValue($this->getName($config)), - id(new PhabricatorDatasourceEditField()) - ->setKey('project') - ->setLabel(pht('Project')) - ->setDatasource(new PhabricatorProjectDatasource()) - ->setSingleValue($config->getMenuItemProperty('project')), ); } @@ -110,4 +112,49 @@ final class PhabricatorProjectProfileMenuItem ); } + public function validateTransactions( + PhabricatorProfileMenuItemConfiguration $config, + $field_key, + $value, + array $xactions) { + + $viewer = $this->getViewer(); + $errors = array(); + + if ($field_key == self::FIELD_PROJECT) { + if ($this->isEmptyTransaction($value, $xactions)) { + $errors[] = $this->newRequiredError( + pht('You must choose a project.'), + $field_key); + } + + foreach ($xactions as $xaction) { + $new = $xaction['new']; + + if (!$new) { + continue; + } + + if ($new === $value) { + continue; + } + + $projects = id(new PhabricatorProjectQuery()) + ->setViewer($viewer) + ->withPHIDs(array($new)) + ->execute(); + if (!$projects) { + $errors[] = $this->newInvalidError( + pht( + 'Project "%s" is not a valid project which you have '. + 'permission to see.', + $new), + $xaction['xaction']); + } + } + } + + return $errors; + } + } diff --git a/src/applications/search/query/PhabricatorProfileMenuItemConfigurationQuery.php b/src/applications/search/query/PhabricatorProfileMenuItemConfigurationQuery.php index eb09044d63..83a84ac306 100644 --- a/src/applications/search/query/PhabricatorProfileMenuItemConfigurationQuery.php +++ b/src/applications/search/query/PhabricatorProfileMenuItemConfigurationQuery.php @@ -7,6 +7,7 @@ final class PhabricatorProfileMenuItemConfigurationQuery private $phids; private $profilePHIDs; private $customPHIDs; + private $includeGlobal; public function withIDs(array $ids) { $this->ids = $ids; @@ -23,8 +24,9 @@ final class PhabricatorProfileMenuItemConfigurationQuery return $this; } - public function withCustomPHIDs(array $phids) { + public function withCustomPHIDs(array $phids, $include_global = false) { $this->customPHIDs = $phids; + $this->includeGlobal = $include_global; return $this; } @@ -61,10 +63,21 @@ final class PhabricatorProfileMenuItemConfigurationQuery } if ($this->customPHIDs !== null) { - $where[] = qsprintf( - $conn, - 'customPHID IN (%Ls)', - $this->customPHIDs); + if ($this->customPHIDs && $this->includeGlobal) { + $where[] = qsprintf( + $conn, + 'customPHID IN (%Ls) OR customPHID IS NULL', + $this->customPHIDs); + } else if ($this->customPHIDs) { + $where[] = qsprintf( + $conn, + 'customPHID IN (%Ls)', + $this->customPHIDs); + } else { + $where[] = qsprintf( + $conn, + 'customPHID IS NULL'); + } } return $where; diff --git a/src/applications/search/storage/PhabricatorProfileMenuItemConfiguration.php b/src/applications/search/storage/PhabricatorProfileMenuItemConfiguration.php index 78fc380604..107fa63c72 100644 --- a/src/applications/search/storage/PhabricatorProfileMenuItemConfiguration.php +++ b/src/applications/search/storage/PhabricatorProfileMenuItemConfiguration.php @@ -126,18 +126,52 @@ final class PhabricatorProfileMenuItemConfiguration return $this->getMenuItem()->willBuildNavigationItems($items); } - public function getSortKey() { - $order = $this->getMenuItemOrder(); - if ($order === null) { - $order = 'Z'; - } else { - $order = sprintf('%020d', $order); + public function validateTransactions(array $map) { + $item = $this->getMenuItem(); + + $fields = $item->buildEditEngineFields($this); + $errors = array(); + foreach ($fields as $field) { + $field_key = $field->getKey(); + + $xactions = idx($map, $field_key, array()); + $value = $this->getMenuItemProperty($field_key); + + $field_errors = $item->validateTransactions( + $this, + $field_key, + $value, + $xactions); + foreach ($field_errors as $error) { + $errors[] = $error; + } } - return sprintf( - '~%s%020d', - $order, - $this->getID()); + return $errors; + } + + public function getSortVector() { + // Sort custom items above global items. + if ($this->getCustomPHID()) { + $is_global = 0; + } else { + $is_global = 1; + } + + // Sort items with an explicit order above items without an explicit order, + // so any newly created builtins go to the bottom. + $order = $this->getMenuItemOrder(); + if ($order !== null) { + $has_order = 0; + } else { + $has_order = 1; + } + + return id(new PhutilSortVector()) + ->addInt($is_global) + ->addInt($has_order) + ->addInt((int)$order) + ->addInt((int)$this->getID()); } public function isDisabled() { @@ -179,6 +213,21 @@ final class PhabricatorProfileMenuItemConfiguration public function getExtendedPolicy($capability, PhabricatorUser $viewer) { + // If this is an item with a custom PHID (like a personal menu item), + // we only require that the user can edit the corresponding custom + // object (usually their own user profile), not the object that the + // menu appears on (which may be an Application like Favorites or Home). + if ($capability == PhabricatorPolicyCapability::CAN_EDIT) { + if ($this->getCustomPHID()) { + return array( + array( + $this->getCustomPHID(), + $capability, + ), + ); + } + } + return array( array( $this->getProfileObject(), diff --git a/src/applications/settings/extension/PhabricatorSettingsMainMenuBarExtension.php b/src/applications/settings/extension/PhabricatorSettingsMainMenuBarExtension.php deleted file mode 100644 index 21534c4237..0000000000 --- a/src/applications/settings/extension/PhabricatorSettingsMainMenuBarExtension.php +++ /dev/null @@ -1,29 +0,0 @@ -getController(); - $is_selected = ($controller instanceof PhabricatorSettingsMainController); - - $bar_item = id(new PHUIListItemView()) - ->setName(pht('Settings')) - ->setIcon('fa-wrench') - ->addClass('core-menu-item') - ->setSelected($is_selected) - ->setHref('/settings/') - ->setAural(pht('Settings')); - - $settings_menu = id(new PHUIMainMenuView()) - ->setMenuBarItem($bar_item) - ->setOrder(400); - - return array( - $settings_menu, - ); - } - -} diff --git a/src/applications/settings/quickmenu/PhabricatorEditEngineCreateQuickActions.php b/src/applications/settings/quickmenu/PhabricatorEditEngineCreateQuickActions.php deleted file mode 100644 index e4a8c520e5..0000000000 --- a/src/applications/settings/quickmenu/PhabricatorEditEngineCreateQuickActions.php +++ /dev/null @@ -1,46 +0,0 @@ -getViewer(); - - $engines = PhabricatorEditEngine::getAllEditEngines(); - - foreach ($engines as $key => $engine) { - if (!$engine->hasQuickCreateActions()) { - unset($engines[$key]); - } - } - - if (!$engines) { - return array(); - } - - $engine_keys = array_keys($engines); - - $configs = id(new PhabricatorEditEngineConfigurationQuery()) - ->setViewer($viewer) - ->withEngineKeys($engine_keys) - ->withIsDefault(true) - ->withIsDisabled(false) - ->execute(); - $configs = msort($configs, 'getCreateSortKey'); - $configs = mgroup($configs, 'getEngineKey'); - - $items = array(); - foreach ($engines as $key => $engine) { - $engine_configs = idx($configs, $key, array()); - $engine_items = $engine->newQuickCreateActions($engine_configs); - foreach ($engine_items as $engine_item) { - $items[] = $engine_item; - } - } - - return $items; - } - -} diff --git a/src/applications/settings/quickmenu/PhabricatorQuickActions.php b/src/applications/settings/quickmenu/PhabricatorQuickActions.php deleted file mode 100644 index 8a7711b809..0000000000 --- a/src/applications/settings/quickmenu/PhabricatorQuickActions.php +++ /dev/null @@ -1,54 +0,0 @@ -viewer = $viewer; - return $this; - } - - public function getViewer() { - return $this->viewer; - } - - public function isEnabled() { - return true; - } - - abstract public function getQuickMenuItems(); - - final public function getQuickActionsKey() { - return $this->getPhobjectClassConstant('QUICKACTIONSKEY'); - } - - public static function getAllQuickActions() { - return id(new PhutilClassMapQuery()) - ->setAncestorClass(__CLASS__) - ->setUniqueMethod('getQuickActionsKey') - ->execute(); - } - - public static function loadMenuItemsForUser(PhabricatorUser $viewer) { - $actions = self::getAllQuickActions(); - - foreach ($actions as $key => $action) { - $action->setViewer($viewer); - if (!$action->isEnabled()) { - unset($actions[$key]); - continue; - } - } - - $items = array(); - foreach ($actions as $key => $action) { - foreach ($action->getQuickMenuItems() as $item) { - $items[] = $item; - } - } - - return $items; - } - -} diff --git a/src/applications/settings/setting/PhabricatorProfileMenuCollapsedSetting.php b/src/applications/settings/setting/PhabricatorProfileMenuCollapsedSetting.php deleted file mode 100644 index e98cb85fa6..0000000000 --- a/src/applications/settings/setting/PhabricatorProfileMenuCollapsedSetting.php +++ /dev/null @@ -1,12 +0,0 @@ -save(); } + final public static function attachDrafts( + PhabricatorUser $viewer, + array $objects) { + assert_instances_of($objects, 'PhabricatorDraftInterface'); + + $viewer_phid = $viewer->getPHID(); + + if (!$viewer_phid) { + // Viewers without a valid PHID can never have drafts. + foreach ($objects as $object) { + $object->attachHasDraft($viewer, false); + } + return; + } else { + $draft_type = PhabricatorObjectHasDraftEdgeType::EDGECONST; + + $edge_query = id(new PhabricatorEdgeQuery()) + ->withSourcePHIDs(mpull($objects, 'getPHID')) + ->withEdgeTypes( + array( + $draft_type, + )) + ->withDestinationPHIDs(array($viewer_phid)); + + $edge_query->execute(); + + foreach ($objects as $object) { + $has_draft = (bool)$edge_query->getDestinationPHIDs( + array( + $object->getPHID(), + )); + + $object->attachHasDraft($viewer, $has_draft); + } + } + } + } diff --git a/src/applications/transactions/draft/PhabricatorDraftInterface.php b/src/applications/transactions/draft/PhabricatorDraftInterface.php index 69b2edf8a0..2e03c17d50 100644 --- a/src/applications/transactions/draft/PhabricatorDraftInterface.php +++ b/src/applications/transactions/draft/PhabricatorDraftInterface.php @@ -4,4 +4,25 @@ interface PhabricatorDraftInterface { public function newDraftEngine(); + public function getHasDraft(PhabricatorUser $viewer); + public function attachHasDraft(PhabricatorUser $viewer, $has_draft); + } + +/* -( PhabricatorDraftInterface )------------------------------------------ */ +/* + + public function newDraftEngine() { + return new <...>DraftEngine(); + } + + public function getHasDraft(PhabricatorUser $viewer) { + return $this->assertAttachedKey($this->drafts, $viewer->getCacheFragment()); + } + + public function attachHasDraft(PhabricatorUser $viewer, $has_draft) { + $this->drafts[$viewer->getCacheFragment()] = $has_draft; + return $this; + } + +*/ diff --git a/src/applications/transactions/editengine/PhabricatorEditEngine.php b/src/applications/transactions/editengine/PhabricatorEditEngine.php index 434fcc5091..e594ae4b67 100644 --- a/src/applications/transactions/editengine/PhabricatorEditEngine.php +++ b/src/applications/transactions/editengine/PhabricatorEditEngine.php @@ -77,6 +77,33 @@ abstract class PhabricatorEditEngine return true; } + public function isDefaultQuickCreateEngine() { + return false; + } + + public function getDefaultQuickCreateFormKeys() { + $keys = array(); + + if ($this->isDefaultQuickCreateEngine()) { + $keys[] = self::EDITENGINECONFIG_DEFAULT; + } + + foreach ($keys as $idx => $key) { + $keys[$idx] = $this->getEngineKey().'/'.$key; + } + + return $keys; + } + + public static function splitFullKey($full_key) { + return explode('/', $full_key, 2); + } + + public function getQuickCreateOrderVector() { + return id(new PhutilSortVector()) + ->addString($this->getObjectCreateShortText()); + } + /** * Force the engine to edit a particular object. */ @@ -107,10 +134,6 @@ abstract class PhabricatorEditEngine return $this->hideHeader; } - public function getProfileMenuItemDefault() { - return $this->getEngineKey().'/'.self::EDITENGINECONFIG_DEFAULT; - } - /* -( Managing Fields )---------------------------------------------------- */ @@ -283,14 +306,6 @@ abstract class PhabricatorEditEngine } - /** - * @task text - */ - protected function getQuickCreateMenuHeaderText() { - return $this->getObjectCreateShortText(); - } - - /** * Return a human-readable header describing what this engine is used to do, * like "Configure Maniphest Task Forms". @@ -2100,50 +2115,6 @@ abstract class PhabricatorEditEngine return $application->getIcon(); } - public function hasQuickCreateActions() { - if (!$this->isEngineConfigurable()) { - return false; - } - - return true; - } - - public function newQuickCreateActions(array $configs) { - $items = array(); - - if (!$configs) { - return array(); - } - - // If the viewer is logged in and can't create objects, don't show the - // menu item. If they're logged out, we assume they could create objects - // if they logged in, so we show the item as a hint about how to - // accomplish the action. - if ($this->getViewer()->isLoggedIn()) { - if (!$this->hasCreateCapability()) { - return array(); - } - } - - if (count($configs) == 1) { - $config = head($configs); - $items[] = $this->newQuickCreateAction($config); - } else { - $group_name = $this->getQuickCreateMenuHeaderText(); - - $items[] = id(new PHUIListItemView()) - ->setType(PHUIListItemView::TYPE_LABEL) - ->setName($group_name); - - foreach ($configs as $config) { - $items[] = $this->newQuickCreateAction($config) - ->setIndented(true); - } - } - - return $items; - } - private function loadUsableConfigurationsForCreate() { $viewer = $this->getViewer(); @@ -2159,20 +2130,6 @@ abstract class PhabricatorEditEngine return $configs; } - private function newQuickCreateAction( - PhabricatorEditEngineConfiguration $config) { - - $item_name = $config->getName(); - $item_icon = $config->getIcon(); - $form_key = $config->getIdentifier(); - $item_uri = $this->getEditURI(null, "form/{$form_key}/"); - - return id(new PHUIListItemView()) - ->setName($item_name) - ->setIcon($item_icon) - ->setHref($item_uri); - } - protected function getValidationExceptionShortMessage( PhabricatorApplicationTransactionValidationException $ex, PhabricatorEditField $field) { diff --git a/src/infrastructure/diff/view/PHUIDiffGraphView.php b/src/infrastructure/diff/view/PHUIDiffGraphView.php index ed4b0acf57..76ae0b2045 100644 --- a/src/infrastructure/diff/view/PHUIDiffGraphView.php +++ b/src/infrastructure/diff/view/PHUIDiffGraphView.php @@ -50,7 +50,6 @@ final class PHUIDiffGraphView extends Phobject { $thread_count = $pos; for ($n = 0; $n < $thread_count; $n++) { - if (empty($threads[$n])) { $line .= ' '; continue; @@ -60,7 +59,7 @@ final class PHUIDiffGraphView extends Phobject { if ($found) { $line .= ' '; $joins[] = $n; - unset($threads[$n]); + $threads[$n] = false; } else { $line .= 'o'; $found = true; @@ -114,6 +113,7 @@ final class PHUIDiffGraphView extends Phobject { if ($thread_commit == $parent) { $found = true; $splits[] = $idx; + break; } } diff --git a/src/infrastructure/diff/view/PHUIDiffInlineCommentDetailView.php b/src/infrastructure/diff/view/PHUIDiffInlineCommentDetailView.php index 808fb5d067..f01bfbdb65 100644 --- a/src/infrastructure/diff/view/PHUIDiffInlineCommentDetailView.php +++ b/src/infrastructure/diff/view/PHUIDiffInlineCommentDetailView.php @@ -270,7 +270,7 @@ final class PHUIDiffInlineCommentDetailView ), 'sigil' => 'differential-inline-preview-jump', ), - pht('Not Visible')); + pht('View')); $action_buttons[] = id(new PHUIButtonView()) ->setTag('a') diff --git a/src/infrastructure/diff/view/__tests__/PHUIDiffGraphViewTestCase.php b/src/infrastructure/diff/view/__tests__/PHUIDiffGraphViewTestCase.php index 9bcf9645a3..2b9e4f8097 100644 --- a/src/infrastructure/diff/view/__tests__/PHUIDiffGraphViewTestCase.php +++ b/src/infrastructure/diff/view/__tests__/PHUIDiffGraphViewTestCase.php @@ -45,10 +45,10 @@ final class PHUIDiffGraphViewTestCase extends PhabricatorTestCase { '^', '|^', 'o ', - '|^', - '||^', - 'o ', - 'x', + '| ^', + '| |^', + 'o ', + 'x ', ); $this->assertGraph($picture, $graph, pht('Reverse Tree')); @@ -71,7 +71,30 @@ final class PHUIDiffGraphViewTestCase extends PhabricatorTestCase { 'x ', ); - $this->assertGraph($picture, $graph, pht('Reverse Tree')); + $this->assertGraph($picture, $graph, pht('Terminated Tree')); + } + + public function testThreeWayGraphJoin() { + $nodes = array( + 'A' => array('D', 'C', 'B'), + 'B' => array('D'), + 'C' => array('B', 'E', 'F'), + 'D' => array(), + 'E' => array(), + 'F' => array(), + ); + + $graph = $this->newGraph($nodes); + $picture = array( + '^', + '||o', + '|o|', + 'x| ||', + ' | x|', + ' | x', + ); + + $this->assertGraph($picture, $graph, pht('Three-Way Tree')); } private function newGraph(array $nodes) { diff --git a/src/view/layout/PhabricatorActionListView.php b/src/view/layout/PhabricatorActionListView.php index fd18e7f429..faf30555eb 100644 --- a/src/view/layout/PhabricatorActionListView.php +++ b/src/view/layout/PhabricatorActionListView.php @@ -1,10 +1,9 @@ object = $object; @@ -16,16 +15,19 @@ final class PhabricatorActionListView extends AphrontView { return $this; } - public function setID($id) { - $this->id = $id; - return $this; + protected function getTagName() { + return 'ul'; } - public function getID() { - return $this->id; + protected function getTagAttributes() { + $classes = array(); + $classes[] = 'phabricator-action-list-view'; + return array( + 'class' => implode(' ', $classes), + ); } - public function render() { + protected function getTagContent() { $viewer = $this->getViewer(); $event = new PhabricatorEvent( @@ -55,13 +57,7 @@ final class PhabricatorActionListView extends AphrontView { } } - return phutil_tag( - 'ul', - array( - 'class' => 'phabricator-action-list-view', - 'id' => $this->id, - ), - $items); + return $items; } public function getDropdownMenuMetadata() { diff --git a/src/view/layout/PhabricatorActionView.php b/src/view/layout/PhabricatorActionView.php index 8788529945..85b9d3abfe 100644 --- a/src/view/layout/PhabricatorActionView.php +++ b/src/view/layout/PhabricatorActionView.php @@ -18,6 +18,13 @@ final class PhabricatorActionView extends AphrontView { private $hidden; private $depth; private $id; + private $order; + private $color; + private $type; + + const TYPE_DIVIDER = 'type-divider'; + const TYPE_LABEL = 'label'; + const RED = 'action-item-red'; public function setSelected($selected) { $this->selected = $selected; @@ -51,6 +58,11 @@ final class PhabricatorActionView extends AphrontView { return $this; } + public function setColor($color) { + $this->color = $color; + return $this; + } + public function addSigil($sigil) { $this->sigils[] = $sigil; return $this; @@ -114,6 +126,24 @@ final class PhabricatorActionView extends AphrontView { return $this->id; } + public function setOrder($order) { + $this->order = $order; + return $this; + } + + public function getOrder() { + return $this->order; + } + + public function setType($type) { + $this->type = $type; + return $this; + } + + public function getType() { + return $this->type; + } + public function setSubmenu(array $submenu) { $this->submenu = $submenu; @@ -173,22 +203,26 @@ final class PhabricatorActionView extends AphrontView { ->setIcon($this->icon.$color); } + $sigils = array(); + if ($this->workflow) { + $sigils[] = 'workflow'; + } + + if ($this->download) { + $sigils[] = 'download'; + } + + if ($this->submenu) { + $sigils[] = 'keep-open'; + } + + if ($this->sigils) { + $sigils = array_merge($sigils, $this->sigils); + } + + $sigils = $sigils ? implode(' ', $sigils) : null; + if ($this->href) { - - $sigils = array(); - if ($this->workflow) { - $sigils[] = 'workflow'; - } - if ($this->download) { - $sigils[] = 'download'; - } - - if ($this->sigils) { - $sigils = array_merge($sigils, $this->sigils); - } - - $sigils = $sigils ? implode(' ', $sigils) : null; - if ($this->renderAsForm) { if (!$this->hasViewer()) { throw new Exception( @@ -244,12 +278,13 @@ final class PhabricatorActionView extends AphrontView { array($icon, $this->name, $caret)); } } else { - $item = phutil_tag( + $item = javelin_tag( 'span', array( 'class' => 'phabricator-action-view-item', + 'sigil' => $sigils, ), - array($icon, $this->name)); + array($icon, $this->name, $this->renderChildren())); } $classes = array(); @@ -275,6 +310,18 @@ final class PhabricatorActionView extends AphrontView { $classes[] = 'phabricator-action-view-href'; } + if ($this->icon) { + $classes[] = 'action-has-icon'; + } + + if ($this->color) { + $classes[] = $this->color; + } + + if ($this->type) { + $classes[] = 'phabricator-action-view-'.$this->type; + } + $style = array(); if ($this->hidden) { diff --git a/src/view/page/PhabricatorStandardPageView.php b/src/view/page/PhabricatorStandardPageView.php index bd2b448be5..67c4dc188c 100644 --- a/src/view/page/PhabricatorStandardPageView.php +++ b/src/view/page/PhabricatorStandardPageView.php @@ -767,23 +767,6 @@ final class PhabricatorStandardPageView extends PhabricatorBarePageView ->setViewer($viewer); $dropdown_query->execute(); - $rendered_dropdowns = array(); - $applications = array( - 'PhabricatorHelpApplication', - ); - foreach ($applications as $application_class) { - if (!PhabricatorApplication::isClassInstalledForViewer( - $application_class, - $viewer)) { - continue; - } - $application = PhabricatorApplication::getByClass($application_class); - $rendered_dropdowns[$application_class] = - $application->buildMainMenuExtraNodes( - $viewer, - $controller); - } - $hisec_warning_config = $this->getHighSecurityWarningConfig(); $console_config = null; @@ -799,6 +782,7 @@ final class PhabricatorStandardPageView extends PhabricatorBarePageView $application_class = null; $application_search_icon = null; + $application_help = null; $controller = $this->getController(); if ($controller) { $application = $controller->getCurrentApplication(); @@ -807,6 +791,16 @@ final class PhabricatorStandardPageView extends PhabricatorBarePageView if ($application->getApplicationSearchDocumentTypes()) { $application_search_icon = $application->getIcon(); } + + $help_items = $application->getHelpMenuItems($viewer); + if ($help_items) { + $help_list = id(new PhabricatorActionListView()) + ->setViewer($viewer); + foreach ($help_items as $help_item) { + $help_list->addAction($help_item); + } + $application_help = $help_list->getDropdownMenuMetadata(); + } } } @@ -818,11 +812,11 @@ final class PhabricatorStandardPageView extends PhabricatorBarePageView $dropdown_query->getConpherenceData(), ), 'globalDragAndDrop' => $upload_enabled, - 'aphlictDropdowns' => $rendered_dropdowns, 'hisecWarningConfig' => $hisec_warning_config, 'consoleConfig' => $console_config, 'applicationClass' => $application_class, 'applicationSearchIcon' => $application_search_icon, + 'helpItems' => $application_help, ) + $this->buildAphlictListenConfigData(); } diff --git a/src/view/page/menu/PhabricatorMainMenuSearchView.php b/src/view/page/menu/PhabricatorMainMenuSearchView.php index aa1855ce17..d21d23d0fd 100644 --- a/src/view/page/menu/PhabricatorMainMenuSearchView.php +++ b/src/view/page/menu/PhabricatorMainMenuSearchView.php @@ -99,8 +99,10 @@ final class PhabricatorMainMenuSearchView extends AphrontView { 'id' => $button_id, 'class' => 'phui-icon-view phui-font-fa fa-search', ), - $search_text), - $selector, + array( + $selector, + $search_text, + )), $primary_input, $target, ))); @@ -118,7 +120,7 @@ final class PhabricatorMainMenuSearchView extends AphrontView { $items[] = array( 'icon' => 'fa-globe', - 'name' => pht('Search All Documents'), + 'name' => pht('All Documents'), 'value' => 'all', ); @@ -134,7 +136,7 @@ final class PhabricatorMainMenuSearchView extends AphrontView { $items[] = array( 'icon' => $application_icon, - 'name' => pht('Search Current Application'), + 'name' => pht('Current Application'), 'value' => PhabricatorSearchController::SCOPE_CURRENT_APPLICATION, ); diff --git a/src/view/page/menu/PhabricatorMainMenuView.php b/src/view/page/menu/PhabricatorMainMenuView.php index a28e38db06..75071a9ee5 100644 --- a/src/view/page/menu/PhabricatorMainMenuView.php +++ b/src/view/page/menu/PhabricatorMainMenuView.php @@ -52,10 +52,10 @@ final class PhabricatorMainMenuView extends AphrontView { $alerts[] = $menu; } $menu_bar = array_merge($menu_bar, $dropdowns); - $app_button = $this->renderApplicationMenuButton($header_id); + $app_button = $this->renderApplicationMenuButton(); $search_button = $this->renderSearchMenuButton($header_id); } else { - $app_button = $this->renderApplicationMenuButton($header_id); + $app_button = $this->renderApplicationMenuButton(); if (PhabricatorEnv::getEnvConfig('policy.allow-public')) { $search_button = $this->renderSearchMenuButton($header_id); } @@ -82,27 +82,17 @@ final class PhabricatorMainMenuView extends AphrontView { phutil_implode_html(' ', $aural)); } + // Build out Header Menus $applications = PhabricatorApplication::getAllInstalledApplications(); $menus = array(); $controller = $this->getController(); foreach ($applications as $application) { - $app_actions = $application->buildMainMenuItems( - $viewer, - $controller); $app_extra = $application->buildMainMenuExtraNodes( $viewer, $controller); - - foreach ($app_actions as $action) { - $menus[] = id(new PHUIMainMenuView()) - ->setMenuBarItem($action) - ->setOrder($action->getOrder()); - } - if ($app_extra !== null) { - $menus[] = id(new PHUIMainMenuView()) - ->appendChild($app_extra); + $menus[] = $app_extra; } } @@ -126,26 +116,17 @@ final class PhabricatorMainMenuView extends AphrontView { } } + // Builds out "login" button foreach ($extensions as $extension) { foreach ($extension->buildMainMenus() as $menu) { $menus[] = $menu; } } - $menus = msort($menus, 'getOrder'); - $bar_items = array(); foreach ($menus as $menu) { $menu_bar[] = $menu; - - $item = $menu->getMenuBarItem(); - if ($item === null) { - continue; - } - - $bar_items[] = $item; } - $application_menu = $this->renderApplicationMenu($bar_items); $classes = array(); $classes[] = 'phabricator-main-menu'; $classes[] = 'phabricator-main-menu-background'; @@ -162,7 +143,6 @@ final class PhabricatorMainMenuView extends AphrontView { $this->renderPhabricatorLogo(), $alerts, $aural, - $application_menu, $search_menu, $menu_bar, )); @@ -218,53 +198,37 @@ final class PhabricatorMainMenuView extends AphrontView { return $result; } - public function renderApplicationMenuButton($header_id) { - $button_id = celerity_generate_unique_node_id(); - return javelin_tag( - 'a', - array( - 'class' => 'phabricator-main-menu-expand-button '. - 'phabricator-expand-search-menu', - 'sigil' => 'jx-toggle-class', - 'meta' => array( - 'map' => array( - $header_id => 'phabricator-application-menu-expanded', - $button_id => 'menu-icon-selected', - ), - ), - ), - phutil_tag( - 'span', - array( - 'class' => 'phabricator-menu-button-icon phui-icon-view '. - 'phui-font-fa fa-bars', - 'id' => $button_id, - ), - '')); + public function renderApplicationMenuButton() { + $dropdown = $this->renderApplicationMenu(); + if (!$dropdown) { + return null; + } + + return id(new PHUIButtonView()) + ->setTag('a') + ->setHref('#') + ->setIcon('fa-bars') + ->addClass('phabricator-core-user-menu') + ->addClass('phabricator-core-user-mobile-menu') + ->setNoCSS(true) + ->setDropdownMenu($dropdown); } - private function renderApplicationMenu(array $bar_items) { + private function renderApplicationMenu() { $viewer = $this->getViewer(); - $view = $this->getApplicationMenu(); - - if (!$view) { - $view = new PHUIListView(); - } - - $view->addClass('phabricator-dark-menu'); - $view->addClass('phabricator-application-menu'); - - if ($bar_items) { - $view->addMenuItem( - id(new PHUIListItemView()) - ->setType(PHUIListItemView::TYPE_LABEL) - ->setName(pht('Actions'))); - foreach ($bar_items as $bar_item) { - $view->addMenuItem($bar_item); + if ($view) { + $items = $view->getItems(); + $view = id(new PhabricatorActionListView()) + ->setViewer($viewer); + foreach ($items as $item) { + $view->addAction( + id(new PhabricatorActionView()) + ->setName($item->getName()) + ->setHref($item->getHref()) + ->setType($item->getType())); } } - return $view; } @@ -296,7 +260,6 @@ final class PhabricatorMainMenuView extends AphrontView { private function renderPhabricatorSearchMenu() { $view = new PHUIListView(); - $view->addClass('phabricator-dark-menu'); $view->addClass('phabricator-search-menu'); $search = $this->renderSearch(); diff --git a/src/view/phui/PHUIButtonView.php b/src/view/phui/PHUIButtonView.php index bda7723ef1..c4ee7a190c 100644 --- a/src/view/phui/PHUIButtonView.php +++ b/src/view/phui/PHUIButtonView.php @@ -27,6 +27,8 @@ final class PHUIButtonView extends AphrontTagView { private $disabled; private $name; private $tooltip; + private $noCSS; + private $hasCaret; public function setName($name) { $this->name = $name; @@ -87,6 +89,20 @@ final class PHUIButtonView extends AphrontTagView { return $this; } + public function setNoCSS($no_css) { + $this->noCSS = $no_css; + return $this; + } + + public function setHasCaret($has_caret) { + $this->hasCaret = $has_caret; + return $this; + } + + public function getHasCaret() { + return $this->hasCaret; + } + public function setIcon($icon, $first = true) { if (!($icon instanceof PHUIIconView)) { $icon = id(new PHUIIconView()) @@ -164,6 +180,10 @@ final class PHUIButtonView extends AphrontTagView { ); } + if ($this->noCSS) { + $classes = array(); + } + return array( 'class' => $classes, 'href' => $this->href, @@ -191,7 +211,7 @@ final class PHUIButtonView extends AphrontTagView { } $caret = null; - if ($this->dropdown) { + if ($this->dropdown || $this->getHasCaret()) { $caret = phutil_tag('span', array('class' => 'caret'), ''); } diff --git a/src/view/phui/PHUIListItemView.php b/src/view/phui/PHUIListItemView.php index 3a4909a1ee..0ca942dd6a 100644 --- a/src/view/phui/PHUIListItemView.php +++ b/src/view/phui/PHUIListItemView.php @@ -202,7 +202,7 @@ final class PHUIListItemView extends AphrontTagView { } return array( - 'class' => $classes, + 'class' => implode(' ', $classes), ); } diff --git a/src/view/phui/PHUIMainMenuView.php b/src/view/phui/PHUIMainMenuView.php deleted file mode 100644 index 7d5910dd7b..0000000000 --- a/src/view/phui/PHUIMainMenuView.php +++ /dev/null @@ -1,31 +0,0 @@ -menuItem = $menu_item; - return $this; - } - - public function getMenuBarItem() { - return $this->menuItem; - } - - public function setOrder($order) { - $this->order = $order; - return $this; - } - - public function getOrder() { - return $this->order; - } - - public function render() { - return $this->renderChildren(); - } - -} diff --git a/src/view/phui/PHUITimelineEventView.php b/src/view/phui/PHUITimelineEventView.php index a5834befd3..142ea1e87d 100644 --- a/src/view/phui/PHUITimelineEventView.php +++ b/src/view/phui/PHUITimelineEventView.php @@ -606,8 +606,8 @@ final class PHUITimelineEventView extends AphrontView { $items[] = id(new PhabricatorActionView()) ->setIcon('fa-quote-left') + ->setName(pht('Quote Comment')) ->setHref('#') - ->setName(pht('Quote')) ->addSigil('transaction-quote') ->setMetadata( array( @@ -619,9 +619,9 @@ final class PHUITimelineEventView extends AphrontView { if ($this->getIsNormalComment()) { $items[] = id(new PhabricatorActionView()) - ->setIcon('fa-cutlery') + ->setIcon('fa-code') ->setHref('/transactions/raw/'.$xaction_phid.'/') - ->setName(pht('View Raw')) + ->setName(pht('View Remarkup')) ->addSigil('transaction-raw') ->setMetadata( array( @@ -646,19 +646,6 @@ final class PHUITimelineEventView extends AphrontView { } } - if ($this->getIsRemovable()) { - $items[] = id(new PhabricatorActionView()) - ->setIcon('fa-times') - ->setHref('/transactions/remove/'.$xaction_phid.'/') - ->setName(pht('Remove Comment')) - ->addSigil('transaction-remove') - ->setMetadata( - array( - 'anchor' => $anchor, - )); - - } - if ($this->getIsEdited()) { $items[] = id(new PhabricatorActionView()) ->setIcon('fa-list') @@ -667,6 +654,23 @@ final class PHUITimelineEventView extends AphrontView { ->setWorkflow(true); } + if ($this->getIsRemovable()) { + $items[] = id(new PhabricatorActionView()) + ->setType(PhabricatorActionView::TYPE_DIVIDER); + + $items[] = id(new PhabricatorActionView()) + ->setIcon('fa-trash-o') + ->setHref('/transactions/remove/'.$xaction_phid.'/') + ->setName(pht('Remove Comment')) + ->setColor(PhabricatorActionView::RED) + ->addSigil('transaction-remove') + ->setMetadata( + array( + 'anchor' => $anchor, + )); + + } + return $items; } diff --git a/webroot/rsrc/css/application/base/main-menu-view.css b/webroot/rsrc/css/application/base/main-menu-view.css index 0e26dc47a4..2bafa7f8f5 100644 --- a/webroot/rsrc/css/application/base/main-menu-view.css +++ b/webroot/rsrc/css/application/base/main-menu-view.css @@ -63,7 +63,7 @@ } .device-phone .phabricator-wordmark { - max-width: 112px; /* iPhone 5 limitation */ + display: none; } .phabricator-wordmark { @@ -119,7 +119,7 @@ */ .device-desktop .phabricator-main-menu-search { - width: 220px; + width: 298px; } .device .phabricator-main-menu-search { @@ -130,7 +130,7 @@ padding: 8px 0; position: relative; height: 24px; - margin: 0 8px; + margin: 0 8px 0 0; } .phabricator-main-menu-search-target { @@ -150,6 +150,7 @@ .device .phabricator-main-menu-search-container { padding: 4px 0; + margin: 0 4px; } .phabricator-main-menu .phabricator-main-menu-search input { @@ -169,9 +170,9 @@ border-style: solid; background-color: #fff; height: 28px; - padding: 3px 30px 3px 6px; + padding: 3px 28px 3px 52px; float: left; - width: 205px; + width: 280px; } .device .phabricator-main-menu-search input { @@ -196,7 +197,7 @@ .phabricator-main-menu-search button { color: {$bluetext}; position: absolute; - background: {$greybackground}; + background: transparent; border: none; outline: none; box-shadow: none; @@ -204,7 +205,7 @@ min-width: 0; height: 24px; width: 28px; - top: 10px; + top: 9px; right: -6px; margin: 0 8px 0 0; padding: 0; @@ -214,20 +215,22 @@ .phabricator-main-menu-search button.phabricator-main-menu-search-dropdown { position: absolute; right: auto; - left: -45px; - width: 40px; - background: transparent; + left: 12px; + width: 46px; + background: {$greybackground}; + z-index: 1; } .device-desktop .phabricator-main-menu-search button.phabricator-main-menu-search-dropdown { - height: 28px; - top: 8px; + height: 24px; + top: 10px; + border-radius: 3px; } .device-desktop .phabricator-main-menu-search button.phabricator-main-menu-search-dropdown:hover .phui-icon-view { - color: #fff; + color: {$sky}; } .device .phabricator-main-menu-search @@ -236,34 +239,24 @@ background: {$greybackground}; } -button.phabricator-main-menu-search-dropdown .caret:before { +button.phabricator-main-menu-search-dropdown .caret:before, +a.phabricator-core-user-menu .caret:before { content: "\f107"; font-family: FontAwesome; - color: {$hoverwhite}; } .phabricator-main-menu-search button.phabricator-main-menu-search-dropdown .phui-icon-view { - color: {$hoverwhite}; + color: {$bluetext}; font-size: 15px; - top: 6px; + top: 4px; left: 8px; } -.device - .phabricator-main-menu-search button.phabricator-main-menu-search-dropdown - .phui-icon-view { - color: {$bluetext}; -} - -.device button.phabricator-main-menu-search-dropdown .caret:before { - color: {$bluetext}; -} - .phabricator-main-menu-search-dropdown .caret { position: absolute; - right: 15px; - top: 5px; + right: 18px; + top: 2px; border: none; margin-top: 1px; } @@ -284,7 +277,7 @@ button.phabricator-main-menu-search-dropdown .caret:before { word-wrap: break-word; overflow-y: auto; box-shadow: {$dropshadow}; - border: 1px solid {$blueborder}; + border: 1px solid {$lightgreyborder}; border-radius: 3px; margin-left: 40px; } @@ -339,12 +332,6 @@ button.phabricator-main-menu-search-dropdown .caret:before { font-size: {$normalfontsize}; } -.device .phabricator-dark-menu .phui-list-item-type-link - .phabricator-main-search-typeahead-result { - line-height: 18px; -} - - /* - Alert --------------------------------------------------------------------- @@ -442,36 +429,6 @@ button.phabricator-main-menu-search-dropdown .caret:before { display: block; } -/* - Dark Menu ----------------------------------------------------------------- - - Styles shared between the "core" menu (left button on mobile) and - "application" menu (right button on mobile). These styles give the menu a - white-on-black appearance. - -*/ - -.device .phabricator-dark-menu, -.device .phabricator-dark-menu a.phui-list-item-href { - color: {$darkbluetext}; - -webkit-font-smoothing: antialiased; -} - -.device .phabricator-dark-menu .phui-list-item-type-label { - text-transform: uppercase; - font-size: {$normalfontsize}; - background-color: #fff; - padding: 6px 0 6px 12px; - display: block; - font-weight: bold; - color: #000; -} - -.device .phabricator-dark-menu .phui-list-item-href { - background-color: #fff; - padding: 4px 0 4px 20px; - display: block; -} - /* - Core Menu ----------------------------------------------------------------- @@ -479,10 +436,6 @@ button.phabricator-main-menu-search-dropdown .caret:before { */ -.phabricator-core-menu-profile-image { - background-size: 28px 28px; -} - .device .phabricator-search-menu { display: none; } @@ -500,12 +453,7 @@ button.phabricator-main-menu-search-dropdown .caret:before { border: 1px solid {$lightblueborder}; border-radius: 3px; box-shadow: {$dropshadow}; -} - -.device .phabricator-dark-menu .phui-list-item-type-link { - min-height: 24px; - line-height: 20px; - background: #fff; + background: {$page.background}; } .device-desktop .phabricator-application-menu { @@ -531,12 +479,6 @@ button.phabricator-main-menu-search-dropdown .caret:before { vertical-align: middle; } -.device .phabricator-dark-menu.phabricator-application-menu - .phui-list-item-icon.phui-font-fa, -.device .phabricator-dark-menu .phabricator-core-menu-icon { - display: none; -} - .device .phabricator-application-menu .phui-list-item-icon.phui-font-fa { margin: 4px 12px 4px 0; } @@ -606,29 +548,108 @@ button.phabricator-main-menu-search-dropdown .caret:before { padding-left: 12px; } +/* - User Menu ----------------------------------------------------------------- -/* - Application Menu ---------------------------------------------------------- - - Styles unique to the application menu (right button on mobile). + Styles unique to the user profile menu. */ -.device .phabricator-application-menu-expanded .phabricator-application-menu { - display: block; - position: absolute; - border: 1px solid {$blueborder}; - border-radius: 3px; - box-shadow: {$dropshadow}; - top: 42px; - right: 8px; - width: 240px; +.phabricator-core-user-menu { + float: right; + display: inline-block; + padding: 9px 24px 0 8px; + height: 35px; + position: relative; } -.device .phabricator-application-menu, -.device-desktop .phabricator-dark-menu .phui-list-item-type-label { +.phabricator-core-user-mobile-menu { display: none; } +.phabricator-core-user-menu span.phui-icon-view.phuihead-small { + height: 24px; + width: 24px; + background-size: 24px; + border-radius: 3px; + display: inline-block; + margin: 1px 0 0 0; +} + +.phabricator-core-user-menu .phui-icon-view { + color: {$hoverwhite}; + font-size: 18px; + margin: 4px 0 0 0; +} + +.phabricator-core-user-menu .caret { + position: absolute; + right: 17px; + top: 13px; + border: none; + margin: 1px; + color: {$hoverwhite}; +} + +.phabricator-core-login-button { + float: right; + display: inline-block; + padding: 4px 12px; + border-radius: 3px; + margin: 8px 6px 4px; + border: 1px solid {$hoverwhite}; + color: {$hoverwhite}; +} + +.device-desktop .phabricator-core-login-button:hover { + border: 1px solid #fff; + color: #fff; +} + +.device-desktop .phabricator-core-user-menu:hover .caret, +.device-desktop .phabricator-core-user-menu:hover .phui-icon-view { + color: #fff; +} + +.device .phabricator-core-user-menu .caret { + display: none; +} + +.device .phabricator-core-user-mobile-menu { + display: block; +} + +.device .phabricator-core-user-menu { + padding: 9px 8px 0 8px; +} + +.device .phabricator-core-user-menu .phui-icon-view { + font-size: 20px; + margin: 3px 0 0 0; +} + +ul.phabricator-core-user-profile-object .phui-oi-objname { + font-size: {$biggestfontsize}; +} + +ul.phabricator-core-user-profile-object li.phui-oi, +ul.phabricator-core-user-profile-object .phui-oi-name, +ul.phabricator-core-user-profile-object .phui-oi-content, +ul.phabricator-core-user-profile-object .phui-oi-subhead { + padding: 0; + margin: 0; +} + +ul.phabricator-core-user-profile-object.phui-oi-list-simple .phui-oi-image { + height: 36px; + width: 36px; +} + +ul.phabricator-core-user-profile-object.phui-oi-list-simple + .phui-oi-content-box { + margin-left: 44px; +} + + /* - Print --------------------------------------------------------------------- */ diff --git a/webroot/rsrc/css/application/base/notification-menu.css b/webroot/rsrc/css/application/base/notification-menu.css index 82a5aa0220..02a3d5a170 100644 --- a/webroot/rsrc/css/application/base/notification-menu.css +++ b/webroot/rsrc/css/application/base/notification-menu.css @@ -8,7 +8,7 @@ word-wrap: break-word; overflow-y: auto; box-shadow: {$dropshadow}; - border: 1px solid {$blueborder}; + border: 1px solid {$lightgreyborder}; border-radius: 3px; } diff --git a/webroot/rsrc/css/phui/phui-action-list.css b/webroot/rsrc/css/phui/phui-action-list.css index 2c82300c3b..354d3fd6e7 100644 --- a/webroot/rsrc/css/phui/phui-action-list.css +++ b/webroot/rsrc/css/phui/phui-action-list.css @@ -11,6 +11,7 @@ /* When an action list view appears inside a dropdown menu, don't hide it by default. */ display: block; + padding: 0; } .device .phabricator-action-list-view.phabricator-action-list-toggle, @@ -18,7 +19,7 @@ .phabricator-action-list-view.phabricator-action-list-toggle { display: block; width: 200px; - border: 1px solid {$lightblueborder}; + border: 1px solid {$lightgreyborder}; border-radius: 3px; position: absolute; right: 16px; @@ -58,18 +59,49 @@ .phabricator-action-view button.phabricator-action-view-item, .phabricator-action-view-item { - padding: 4px 4px 4px 28px; + padding: 4px 8px 6px 8px; display: block; text-decoration: none; color: {$darkbluetext}; } -.phabricator-action-view-label .phabricator-action-view-item { - font-size: {$normalfontsize}; +.action-has-icon button.phabricator-action-view-item, +.action-has-icon .phabricator-action-view-item { + padding: 4px 4px 4px 28px; +} + +.device-desktop .phabricator-action-view-href:hover + .phabricator-action-view-item { + text-decoration: none; + background: rgba({$alphablue}, .08); + color: {$sky}; + border-radius: 3px; +} + +.device-desktop .phabricator-action-view-href:hover + .phabricator-action-view-icon { + color: {$sky}; +} + +.device-desktop .phabricator-action-view-href.action-item-red:hover + .phabricator-action-view-item { + background-color: {$sh-redbackground}; + color: {$sh-redtext}; +} + +.device-desktop .phabricator-action-view-href.action-item-red:hover + .phabricator-action-view-icon { + color: {$red}; +} + +.phabricator-action-view-label .phabricator-action-view-item, +.phabricator-action-view-type-label .phabricator-action-view-item { + font-size: {$smallerfontsize}; font-weight: bold; color: {$bluetext}; padding: 4px 8px 6px 8px; display: block; + text-transform: uppercase; -webkit-font-smoothing: antialiased; } @@ -87,37 +119,23 @@ width: 14px; height: 14px; position: absolute; - top: 8px; + top: 7px; left: 8px; text-align: center; } -.device-desktop .phabricator-action-view:hover .phabricator-action-view-item { - text-decoration: none; - background-color: {$sky}; - color: #fff; -} - -.device-desktop .phabricator-action-view:hover .phabricator-action-view-icon { - color: #fff; -} - .phabricator-action-view-disabled .phabricator-action-view-item, .phabricator-action-view-disabled button.phabricator-action-view-item { color: {$lightgreytext}; } .phabricator-action-view-selected { - border-left: 3px solid {$sky}; - background: {$hoverblue}; + background: {$sh-violetbackground}; + border-radius: 3px; } -.phabricator-action-view-selected .phabricator-action-view-item { - padding-left: 25px; -} - -.phabricator-action-view-selected .phabricator-action-view-icon { - left: 6px; +.phabricator-action-view-selected:hover a { + text-decoration: none; } .phabricator-action-view button[disabled] { @@ -135,3 +153,8 @@ background-color: {$greybackground}; color: {$lightgreytext}; } + +.phabricator-action-view-type-divider { + margin-top: 8px; + border-top: 1px solid {$thinblueborder}; +} diff --git a/webroot/rsrc/css/phui/phui-button.css b/webroot/rsrc/css/phui/phui-button.css index 15142d3b1a..5d35688c1f 100644 --- a/webroot/rsrc/css/phui/phui-button.css +++ b/webroot/rsrc/css/phui/phui-button.css @@ -198,12 +198,12 @@ button.link:hover { .phuix-dropdown-menu { position: absolute; - width: 240px; + width: 200px; background: #fff; margin-top: -1px; - padding: 5px 0; + padding: 12px; box-shadow: {$dropshadow}; - border: 1px solid {$blueborder}; + border: 1px solid {$lightgreyborder}; border-radius: 3px; margin-bottom: 16px; } diff --git a/webroot/rsrc/css/phui/phui-document-pro.css b/webroot/rsrc/css/phui/phui-document-pro.css index 6cf0df1c68..c939b250ed 100644 --- a/webroot/rsrc/css/phui/phui-document-pro.css +++ b/webroot/rsrc/css/phui/phui-document-pro.css @@ -80,7 +80,7 @@ a.button.phui-document-toc { .phui-document-view-pro .phui-document-toc-list { margin: 8px; - border: 1px solid {$blueborder}; + border: 1px solid {$lightgreyborder}; border-radius: 3px; box-shadow: {$dropshadow}; width: 200px; diff --git a/webroot/rsrc/css/phui/phui-form-view.css b/webroot/rsrc/css/phui/phui-form-view.css index fb422f8d67..cc33808c5a 100644 --- a/webroot/rsrc/css/phui/phui-form-view.css +++ b/webroot/rsrc/css/phui/phui-form-view.css @@ -460,8 +460,7 @@ body .phui-form-view .remarkup-assist-textarea.aphront-textarea-drag-and-drop { .fancy-datepicker-core { background-color: white; - border: 1px solid {$lightblueborder}; - border-bottom: 1px solid {$blueborder}; + border: 1px solid {$lightgreyborder}; box-shadow: {$dropshadow}; border-radius: 3px; } diff --git a/webroot/rsrc/css/phui/phui-profile-menu.css b/webroot/rsrc/css/phui/phui-profile-menu.css index f056e34f23..6f8934dd39 100644 --- a/webroot/rsrc/css/phui/phui-profile-menu.css +++ b/webroot/rsrc/css/phui/phui-profile-menu.css @@ -2,7 +2,7 @@ * @provides phui-profile-menu-css */ -.device-desktop .phui-profile-menu-collapsed .phabricator-nav-local { +.device-desktop .phui-profile-menu .phabricator-nav-local { width: {$menu.profile.width.collapsed}; max-width: {$menu.profile.width.collapsed}; } @@ -58,8 +58,7 @@ background-size: 100%; } -.phui-profile-menu .phui-profile-menu-collapsed .phabricator-side-menu - .phui-list-item-href { +.phui-profile-menu .phabricator-side-menu .phui-list-item-href { text-align: center; padding: 42px 4px 14px; line-height: 14px; @@ -67,19 +66,17 @@ font-size: {$smallerfontsize}; } -.phui-profile-menu .phui-profile-menu-collapsed .phabricator-side-menu - .phui-list-item-name { +.phui-profile-menu .phabricator-side-menu .phui-list-item-name { display: block; overflow: hidden; text-overflow: ellipsis; } -.phui-profile-menu .phui-profile-menu-collapsed .phabricator-side-menu - .phui-list-item-icon, -.phui-profile-menu .phui-profile-menu-collapsed .phabricator-side-menu - .phui-list-item-href .phui-list-item-icon { - top: 14px; - left: 32px; +.phui-profile-menu .phabricator-side-menu .phui-list-item-icon, +.phui-profile-menu .phabricator-side-menu .phui-list-item-href + .phui-list-item-icon { + top: 14px; + left: 32px; } .phui-profile-menu .phabricator-side-menu @@ -131,14 +128,12 @@ padding: 16px; } -.phui-profile-menu .phui-profile-menu-collapsed .phabricator-side-menu - .phui-profile-menu-error { +.phui-profile-menu .phabricator-side-menu .phui-profile-menu-error { padding: 16px 8px; overflow: hidden; text-overflow: ellipsis; } - .phui-profile-menu .phabricator-side-menu .phui-list-item-disabled .phui-list-item-href, .phui-profile-menu .phui-list-sidenav .phui-list-item-disabled @@ -153,150 +148,15 @@ padding: 8px 12px 16px; } -.phui-profile-menu .phui-profile-menu-collapsed .phabricator-side-menu - .phui-profile-segment-bar { +.phui-profile-menu .phabricator-side-menu .phui-profile-segment-bar { padding: 8px 8px 16px; } - .phui-profile-menu .phabricator-side-menu .phui-profile-menu-spacer { box-sizing: border-box; height: {$menu.profile.item.height}; } -.phui-profile-menu .phui-profile-menu-collapsed .phabricator-side-menu - .phui-profile-menu-footer - .phui-list-item-name { - display: none; -} - -.phui-profile-menu .phui-profile-menu-expanded - .phui-profile-menu-visible-when-collapsed, -.phui-profile-menu .phui-profile-menu-collapsed - .phui-profile-menu-visible-when-expanded { - display: none; -} - - -.phui-profile-menu .phui-profile-menu-collapsed .phabricator-side-menu - .phui-profile-menu-footer .phui-list-item-href { - padding: 20px 0 24px; -} - -.phui-profile-menu .phabricator-side-menu .phui-profile-menu-footer - .phui-list-item-href:hover { - background: transparent; -} - -.phui-profile-menu .phui-profile-menu-collapsed .phabricator-side-menu - .phui-profile-menu-footer .phui-list-item-href .phui-list-item-icon { - top: 8px; -} - -.phui-profile-menu .phui-profile-menu-footer .phui-icon-circle { - border-color: {$darkbluetext}; -} - -.phui-profile-menu .phui-profile-menu-footer .phui-icon-circle .phui-icon-view { - color: {$darkbluetext}; -} - -.phui-profile-menu .phui-profile-menu-footer - .phui-icon-circle.phui-list-item-icon { - font-size: 12px; -} - -.phui-profile-menu .phabricator-side-menu .phui-profile-menu-footer-1 { - bottom: 0; - position: fixed; -} - -.phui-profile-menu .phui-profile-menu-footer-1 { - width: {$menu.profile.width}; -} - -.phui-profile-menu .phui-profile-menu-collapsed .phui-profile-menu-footer-1 { - width: {$menu.profile.width.collapsed}; -} - -.phui-profile-menu .phabricator-side-menu - .phui-list-item-selected.phui-profile-menu-footer .phui-list-item-href { - background: transparent; -} - -.phui-profile-menu .phui-profile-menu-collapsing - .phabricator-nav-local { - animation: profile-menu-collapse 0.2s; -} - -.phui-profile-menu .phui-profile-menu-expanding - .phabricator-nav-local { - animation: profile-menu-expand 0.2s; -} - -.phui-profile-menu .phui-profile-menu-collapsing - .phabricator-side-menu .phui-list-item-href { - animation: profile-menu-blink 0.2s; -} - -.phui-profile-menu .phui-profile-menu-expanding - .phabricator-side-menu .phui-list-item-href { - animation: profile-menu-blink 0.2s; -} - -@keyframes profile-menu-blink { - 0% { - opacity: 1.0; - } - 25% { - opacity: 0.0; - } - 75% { - opacity: 0.0; - } - 100% { - opacity: 1.0; - } -} - -@keyframes profile-menu-collapse { - 0% { - width: {$menu.profile.width}; - max-width: {$menu.profile.width}; - } - 33% { - width: {$menu.profile.width}; - max-width: {$menu.profile.width}; - } - 66% { - width: {$menu.profile.width.collapsed}; - max-width: {$menu.profile.width.collapsed}; - } - 100% { - width: {$menu.profile.width.collapsed}; - max-width: {$menu.profile.width.collapsed}; - } -} - -@keyframes profile-menu-expand { - 0% { - width: {$menu.profile.width.collapsed}; - max-width: {$menu.profile.width.collapsed}; - } - 33% { - width: {$menu.profile.width.collapsed}; - max-width: {$menu.profile.width.collapsed}; - } - 66% { - width: {$menu.profile.width}; - max-width: {$menu.profile.width}; - } - 100% { - width: {$menu.profile.width}; - max-width: {$menu.profile.width}; - } -} - !print .phui-profile-menu .phabricator-side-menu { display: none; } diff --git a/webroot/rsrc/css/phui/phui-two-column-view.css b/webroot/rsrc/css/phui/phui-two-column-view.css index 0020df8b84..80e51d95da 100644 --- a/webroot/rsrc/css/phui/phui-two-column-view.css +++ b/webroot/rsrc/css/phui/phui-two-column-view.css @@ -159,24 +159,6 @@ padding: 0 12px; } -.phabricator-action-view button.phabricator-action-view-item, -.phabricator-action-view-item { - padding: 5px 4px 5px 28px; -} - -.device-desktop .phui-two-column-properties .phabricator-action-view-href:hover - .phabricator-action-view-item { - text-decoration: none; - background-color: rgba({$alphablue}, .08); - color: {$sky}; - border-radius: 3px; -} - -.device-desktop .phui-two-column-properties .phabricator-action-view-href:hover - .phabricator-action-view-icon { - color: {$sky}; -} - .phui-two-column-view .phui-property-list-section-header, .phui-two-column-view .phui-property-list-text-content { margin: 0 16px; @@ -199,6 +181,10 @@ padding: 12px; } +.phui-two-column-view .phui-oi-empty .phui-info-view { + margin: 0; +} + .phui-two-column-view .phui-side-column .phui-oi-empty .phui-info-view { margin-bottom: 0; diff --git a/webroot/rsrc/css/phui/workboards/phui-workboard.css b/webroot/rsrc/css/phui/workboards/phui-workboard.css index 4a5446bf5b..43fd3a85e4 100644 --- a/webroot/rsrc/css/phui/workboards/phui-workboard.css +++ b/webroot/rsrc/css/phui/workboards/phui-workboard.css @@ -32,11 +32,6 @@ } .device-desktop .project-board-wrapper .phui-workboard-view-shadow { - left: {$menu.profile.width}; -} - -.device-desktop .phui-profile-menu-collapsed .project-board-wrapper - .phui-workboard-view-shadow { left: {$menu.profile.width.collapsed}; } diff --git a/webroot/rsrc/js/application/aphlict/behavior-aphlict-dropdown.js b/webroot/rsrc/js/application/aphlict/behavior-aphlict-dropdown.js index f12be7a22b..21db1d94d5 100644 --- a/webroot/rsrc/js/application/aphlict/behavior-aphlict-dropdown.js +++ b/webroot/rsrc/js/application/aphlict/behavior-aphlict-dropdown.js @@ -91,24 +91,6 @@ JX.behavior('aphlict-dropdown', function(config, statics) { null, function (e) { var data = e.getData(); - if (config.local && config.applicationClass) { - var local_dropdowns = data.newResponse.aphlictDropdowns; - if (local_dropdowns[config.applicationClass]) { - JX.DOM.replace( - dropdown, - JX.$H(local_dropdowns[config.applicationClass])); - dropdown = JX.$(config.dropdownID); - if (dropdown.childNodes.length === 0) { - JX.DOM.hide(bubble); - } else { - JX.DOM.show(bubble); - } - } else { - JX.DOM.hide(bubble); - } - return; - } - if (!data.fromServer) { return; } diff --git a/webroot/rsrc/js/application/projects/behavior-project-boards.js b/webroot/rsrc/js/application/projects/behavior-project-boards.js index 8fccb1dc91..85f41d7907 100644 --- a/webroot/rsrc/js/application/projects/behavior-project-boards.js +++ b/webroot/rsrc/js/application/projects/behavior-project-boards.js @@ -34,13 +34,6 @@ JX.behavior('project-boards', function(config, statics) { data.menu = new JX.PHUIXDropdownMenu(button); data.menu.setContent(list); data.menu.open(); - - JX.DOM.listen(list, 'click', 'tag:a', function(e) { - if (!e.isNormalClick()) { - return; - } - data.menu.close(); - }); }); JX.Stratcom.listen( diff --git a/webroot/rsrc/js/application/transactions/behavior-comment-actions.js b/webroot/rsrc/js/application/transactions/behavior-comment-actions.js index 44d5597cb5..11141f138a 100644 --- a/webroot/rsrc/js/application/transactions/behavior-comment-actions.js +++ b/webroot/rsrc/js/application/transactions/behavior-comment-actions.js @@ -126,7 +126,7 @@ JX.behavior('comment-actions', function(config) { } function force_preview() { - if (!config.shouldPreview) { + if (!config.showPreview) { return; } diff --git a/webroot/rsrc/js/core/behavior-user-menu.js b/webroot/rsrc/js/core/behavior-user-menu.js new file mode 100644 index 0000000000..b74b9d36ab --- /dev/null +++ b/webroot/rsrc/js/core/behavior-user-menu.js @@ -0,0 +1,57 @@ +/** + * @provides javelin-behavior-user-menu + * @requires javelin-behavior + */ + +JX.behavior('user-menu', function(config) { + var node = JX.$(config.menuID); + var list = JX.$H(config.menu.items).getFragment().firstChild; + + var menu = new JX.PHUIXDropdownMenu(node); + + menu.listen('open', function() { + menu.setContent(list); + }); + + // When the user navigates to a new page, we may need to update the links + // to documentation in the menu. + JX.Stratcom.listen('quicksand-redraw', null, function(e) { + var data = e.getData(); + + var new_help = data.newResponse.helpItems; + var nodes; + if (new_help) { + nodes = JX.$H(new_help.items).getFragment().firstChild.children; + } else { + nodes = []; + } + + var ii; + + var tail = []; + for (ii = list.children.length - 1; ii >= 0; ii--) { + var node = list.children[ii]; + + // Remove any old help items. + if (JX.Stratcom.hasSigil(node.firstChild, 'help-item')) { + JX.DOM.remove(node); + } + + // Place the logout items aside, if any exist. + if (JX.Stratcom.hasSigil(node.firstChild, 'logout-item')) { + JX.DOM.remove(node); + tail.push(node); + } + } + + while (nodes.length) { + list.appendChild(nodes[0]); + } + + tail.reverse(); + for (ii = 0; ii < tail.length; ii++) { + list.appendChild(tail[ii]); + } + }); + +}); diff --git a/webroot/rsrc/js/phui/behavior-phui-dropdown-menu.js b/webroot/rsrc/js/phui/behavior-phui-dropdown-menu.js index 4bde14a307..d2fddc8e70 100644 --- a/webroot/rsrc/js/phui/behavior-phui-dropdown-menu.js +++ b/webroot/rsrc/js/phui/behavior-phui-dropdown-menu.js @@ -42,18 +42,6 @@ JX.behavior('phui-dropdown-menu', function() { }); data.menu.open(); - - JX.DOM.listen(list, 'click', 'tag:a', function(e) { - if (!e.isNormalClick()) { - return; - } - - if (JX.Stratcom.pass()) { - return; - } - - data.menu.close(); - }); }); }); diff --git a/webroot/rsrc/js/phui/behavior-phui-profile-menu.js b/webroot/rsrc/js/phui/behavior-phui-profile-menu.js deleted file mode 100644 index f6bb9031f0..0000000000 --- a/webroot/rsrc/js/phui/behavior-phui-profile-menu.js +++ /dev/null @@ -1,53 +0,0 @@ -/** - * @provides javelin-behavior-phui-profile-menu - * @requires javelin-behavior - * javelin-stratcom - * javelin-dom - */ - -JX.behavior('phui-profile-menu', function(config) { - // NOTE: This behavior is not initialized in the rendering pipeline for the - // menu, so it can get initialized when we build but do not render a menu - // (for example, when a page like the panel edit page only has items in - // the mobile/application menu, and does not show the profile menu). For now, - // just bail if we can't find the menu. - - try { - var menu_node = JX.$(config.menuID); - } catch (ex) { - return; - } - - var collapse_node = JX.$(config.collapseID); - - var is_collapsed = config.isCollapsed; - - JX.DOM.listen(collapse_node, 'click', null, function(e) { - is_collapsed = !is_collapsed; - - JX.DOM.alterClass(menu_node, 'phui-profile-menu-collapsing', is_collapsed); - JX.DOM.alterClass(menu_node, 'phui-profile-menu-expanding', !is_collapsed); - - var duration = 0.2; - - setTimeout(function() { - JX.DOM.alterClass(menu_node, 'phui-profile-menu-collapsed', is_collapsed); - JX.DOM.alterClass(menu_node, 'phui-profile-menu-expanded', !is_collapsed); - }, (duration / 2) * 1000); - - setTimeout(function() { - JX.DOM.alterClass(menu_node, 'phui-profile-menu-collapsing', false); - JX.DOM.alterClass(menu_node, 'phui-profile-menu-expanding', false); - }, duration * 1000); - - - if (config.settingsURI) { - new JX.Request(config.settingsURI) - .setData({value: (is_collapsed ? 1 : 0)}) - .send(); - } - - e.kill(); - }); - -}); diff --git a/webroot/rsrc/js/phuix/PHUIXActionView.js b/webroot/rsrc/js/phuix/PHUIXActionView.js index 410c23f5ab..d5d849e733 100644 --- a/webroot/rsrc/js/phuix/PHUIXActionView.js +++ b/webroot/rsrc/js/phuix/PHUIXActionView.js @@ -77,16 +77,27 @@ JX.install('PHUIXActionView', { getNode: function() { if (!this._node) { - var attr = { - className: 'phabricator-action-view' - }; + var classes = ['phabricator-action-view']; + + if (this._href || this._handler) { + classes.push('phabricator-action-view-href'); + } + + if (this._icon) { + classes.push('action-has-icon'); + } var content = [ this._buildIconNode(), this._buildNameNode() ]; + var attr = { + className: classes.join(' ') + }; this._node = JX.$N('li', attr, content); + + JX.Stratcom.addSigil(this._node, 'phuix-action-view'); } return this._node; diff --git a/webroot/rsrc/js/phuix/PHUIXDropdownMenu.js b/webroot/rsrc/js/phuix/PHUIXDropdownMenu.js index d9fd1877b8..3f93c1ee41 100644 --- a/webroot/rsrc/js/phuix/PHUIXDropdownMenu.js +++ b/webroot/rsrc/js/phuix/PHUIXDropdownMenu.js @@ -40,6 +40,12 @@ JX.install('PHUIXDropdownMenu', { JX.Stratcom.listen('phuix.dropdown.open', null, JX.bind(this, this.close)); JX.Stratcom.listen('keydown', null, JX.bind(this, this._onkey)); + + JX.DOM.listen( + this._getMenuNode(), + 'click', + 'tag:a', + JX.bind(this, this._onlink)); }, events: ['open', 'close'], @@ -112,6 +118,28 @@ JX.install('PHUIXDropdownMenu', { e.prevent(); }, + _onlink: function(e) { + if (!e.isNormalClick()) { + return; + } + + // If this action was built dynamically with PHUIXActionView, don't + // do anything by default. The caller is repsonsible for installing a + // handler if they want to react to clicks. + if (e.getNode('phuix-action-view')) { + return; + } + + // If this item opens a submenu, we don't want to close the current + // menu. One submenu is "Edit Related Objects..." on mobile. + var link = e.getNode('tag:a'); + if (JX.Stratcom.hasSigil(link, 'keep-open')) { + return; + } + + this.close(); + }, + _onanyclick : function(e) { if (!this._open) { return;