diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 377bdf2ff7..2f190f9691 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -1,2522 +1,2522 @@ array( 'conpherence.pkg.css' => 'c8fbe125', 'conpherence.pkg.js' => '11f3e07e', - 'core.pkg.css' => 'ade19c40', + 'core.pkg.css' => 'cfc3eabe', 'core.pkg.js' => '03c1cb09', 'darkconsole.pkg.js' => 'e7393ebb', 'differential.pkg.css' => 'e1d704ce', 'differential.pkg.js' => '634399e9', 'diffusion.pkg.css' => '91c5d3a6', 'diffusion.pkg.js' => '84c8f8fd', 'maniphest.pkg.css' => '4845691a', 'maniphest.pkg.js' => '949a7498', 'rsrc/css/aphront/aphront-bars.css' => '231ac33c', 'rsrc/css/aphront/dark-console.css' => 'f54bf286', 'rsrc/css/aphront/dialog-view.css' => '593d3f67', 'rsrc/css/aphront/lightbox-attachment.css' => '7acac05d', 'rsrc/css/aphront/list-filter-view.css' => '5d6f0526', 'rsrc/css/aphront/multi-column.css' => '84cc6640', 'rsrc/css/aphront/notification.css' => '3f6c89c9', 'rsrc/css/aphront/panel-view.css' => '8427b78d', 'rsrc/css/aphront/phabricator-nav-view.css' => 'b29426e9', 'rsrc/css/aphront/table-view.css' => '3225137a', 'rsrc/css/aphront/tokenizer.css' => '056da01b', 'rsrc/css/aphront/tooltip.css' => '1a07aea8', 'rsrc/css/aphront/typeahead-browse.css' => '8904346a', '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' => 'b3ab500d', 'rsrc/css/application/base/phabricator-application-launch-view.css' => '95351601', 'rsrc/css/application/base/phui-theme.css' => '027ba77e', - 'rsrc/css/application/base/standard-page-view.css' => 'e5d90676', + 'rsrc/css/application/base/standard-page-view.css' => '79176f5a', 'rsrc/css/application/chatlog/chatlog.css' => 'd295b020', 'rsrc/css/application/conduit/conduit-api.css' => '7bc725c4', 'rsrc/css/application/config/config-options.css' => '0ede4c9b', 'rsrc/css/application/config/config-page.css' => '8798e14f', 'rsrc/css/application/config/config-template.css' => '8f18fa41', 'rsrc/css/application/config/setup-issue.css' => 'f794cfc3', 'rsrc/css/application/config/unhandled-exception.css' => '4c96257a', 'rsrc/css/application/conpherence/durable-column.css' => 'af11a2a7', 'rsrc/css/application/conpherence/header-pane.css' => '517de9fe', 'rsrc/css/application/conpherence/menu.css' => '78c7b811', 'rsrc/css/application/conpherence/message-pane.css' => '0d7dff02', 'rsrc/css/application/conpherence/notification.css' => '65dd0e79', 'rsrc/css/application/conpherence/participant-pane.css' => '7bba0b56', 'rsrc/css/application/conpherence/transaction.css' => '46253e19', 'rsrc/css/application/conpherence/update.css' => '53bc527a', 'rsrc/css/application/contentsource/content-source-view.css' => '4b8b05d4', 'rsrc/css/application/countdown/timer.css' => '16c52f5c', 'rsrc/css/application/daemon/bulk-job.css' => 'df9c1d4a', 'rsrc/css/application/dashboard/dashboard.css' => 'bc6f2127', 'rsrc/css/application/diff/inline-comment-summary.css' => '51efda3a', 'rsrc/css/application/differential/add-comment.css' => 'c47f8c40', 'rsrc/css/application/differential/changeset-view.css' => '9ef7d354', 'rsrc/css/application/differential/core.css' => '5b7b8ff4', 'rsrc/css/application/differential/phui-inline-comment.css' => '5953c28e', 'rsrc/css/application/differential/revision-comment.css' => '14b8565a', 'rsrc/css/application/differential/revision-history.css' => '0e8eb855', 'rsrc/css/application/differential/revision-list.css' => 'f3c47d33', 'rsrc/css/application/differential/table-of-contents.css' => 'ae4b7a55', 'rsrc/css/application/diffusion/diffusion-icons.css' => 'd678600a', 'rsrc/css/application/diffusion/diffusion-readme.css' => '297373eb', 'rsrc/css/application/diffusion/diffusion-source.css' => '68b30fd3', 'rsrc/css/application/feed/feed.css' => 'ecd4ec57', 'rsrc/css/application/files/global-drag-and-drop.css' => '5c1b47c2', 'rsrc/css/application/flag/flag.css' => '5337623f', 'rsrc/css/application/harbormaster/harbormaster.css' => 'f491c9f4', 'rsrc/css/application/herald/herald-test.css' => 'a52e323e', 'rsrc/css/application/herald/herald.css' => 'dc31f6e9', 'rsrc/css/application/maniphest/batch-editor.css' => 'b0f0b6d5', 'rsrc/css/application/maniphest/report.css' => '9b9580b7', 'rsrc/css/application/maniphest/task-edit.css' => 'fda62a9b', 'rsrc/css/application/maniphest/task-summary.css' => '11cc5344', 'rsrc/css/application/objectselector/object-selector.css' => '85ee8ce6', 'rsrc/css/application/owners/owners-path-editor.css' => '2f00933b', 'rsrc/css/application/paste/paste.css' => '1898e534', 'rsrc/css/application/people/people-profile.css' => '2473d929', 'rsrc/css/application/phame/phame.css' => '8efb0729', 'rsrc/css/application/pholio/pholio-edit.css' => '07676f51', 'rsrc/css/application/pholio/pholio-inline-comments.css' => '8e545e49', 'rsrc/css/application/pholio/pholio.css' => 'ca89d380', 'rsrc/css/application/phortune/phortune-credit-card-form.css' => '8391eb02', 'rsrc/css/application/phortune/phortune.css' => '5b99dae0', 'rsrc/css/application/phrequent/phrequent.css' => 'ffc185ad', 'rsrc/css/application/phriction/phriction-document-css.css' => '4282e4ad', 'rsrc/css/application/policy/policy-edit.css' => '815c66f7', 'rsrc/css/application/policy/policy-transaction-detail.css' => '82100a43', 'rsrc/css/application/policy/policy.css' => '957ea14c', 'rsrc/css/application/ponder/ponder-view.css' => 'fbd45f96', 'rsrc/css/application/project/project-card-view.css' => '9418c97d', 'rsrc/css/application/project/project-view.css' => '55d99221', 'rsrc/css/application/releeph/releeph-core.css' => '9b3c5733', 'rsrc/css/application/releeph/releeph-preview-branch.css' => 'b7a6f4a5', 'rsrc/css/application/releeph/releeph-request-differential-create-dialog.css' => '8d8b92cd', 'rsrc/css/application/releeph/releeph-request-typeahead.css' => '667a48ae', - 'rsrc/css/application/search/application-search-view.css' => '9c9bc8dc', + 'rsrc/css/application/search/application-search-view.css' => 'be6454ec', 'rsrc/css/application/search/search-results.css' => '7dea472c', 'rsrc/css/application/slowvote/slowvote.css' => 'a94b7230', 'rsrc/css/application/tokens/tokens.css' => '3d0f239e', 'rsrc/css/application/uiexample/example.css' => '528b19de', - 'rsrc/css/core/core.css' => '4f5111ea', + 'rsrc/css/core/core.css' => 'd0801452', 'rsrc/css/core/remarkup.css' => 'cd912f2c', 'rsrc/css/core/syntax.css' => '769d3498', 'rsrc/css/core/z-index.css' => '0d4e5558', 'rsrc/css/diviner/diviner-shared.css' => 'aa3656aa', 'rsrc/css/font/font-aleo.css' => '8bdb2835', 'rsrc/css/font/font-awesome.css' => '2b7ebbcc', 'rsrc/css/font/font-lato.css' => 'c7ccd872', 'rsrc/css/font/phui-font-icon-base.css' => '870a7360', 'rsrc/css/layout/phabricator-filetree-view.css' => 'fccf9f82', 'rsrc/css/layout/phabricator-source-code-view.css' => 'cbeef983', 'rsrc/css/phui/calendar/phui-calendar-day.css' => '572b1893', 'rsrc/css/phui/calendar/phui-calendar-list.css' => 'fcc9fb41', 'rsrc/css/phui/calendar/phui-calendar-month.css' => '8e10e92c', 'rsrc/css/phui/calendar/phui-calendar.css' => '477acfaa', 'rsrc/css/phui/phui-action-list.css' => 'c5eba19d', 'rsrc/css/phui/phui-action-panel.css' => '91c7b835', 'rsrc/css/phui/phui-badge.css' => '3baef8db', - 'rsrc/css/phui/phui-basic-nav-view.css' => 'c377093a', + 'rsrc/css/phui/phui-basic-nav-view.css' => '7093573b', 'rsrc/css/phui/phui-big-info-view.css' => 'bd903741', 'rsrc/css/phui/phui-box.css' => '5c8387cf', 'rsrc/css/phui/phui-button.css' => '4a5fbe3d', 'rsrc/css/phui/phui-chart.css' => '6bf6f78e', 'rsrc/css/phui/phui-cms.css' => 'be43c8a8', 'rsrc/css/phui/phui-crumbs-view.css' => '195ac419', 'rsrc/css/phui/phui-curtain-view.css' => '947bf1a4', 'rsrc/css/phui/phui-document-pro.css' => 'ca1fed81', 'rsrc/css/phui/phui-document-summary.css' => '9ca48bdf', 'rsrc/css/phui/phui-document.css' => 'c32e8dec', 'rsrc/css/phui/phui-feed-story.css' => 'aa49845d', 'rsrc/css/phui/phui-fontkit.css' => '9cda225e', 'rsrc/css/phui/phui-form-view.css' => '9e22b190', 'rsrc/css/phui/phui-form.css' => 'aac1d51d', 'rsrc/css/phui/phui-head-thing.css' => 'fd311e5f', 'rsrc/css/phui/phui-header-view.css' => '06385974', 'rsrc/css/phui/phui-hovercard.css' => 'de1a2119', 'rsrc/css/phui/phui-icon-set-selector.css' => '1ab67aad', 'rsrc/css/phui/phui-icon.css' => '9bab6f02', 'rsrc/css/phui/phui-image-mask.css' => 'a8498f9c', 'rsrc/css/phui/phui-info-panel.css' => '27ea50a1', 'rsrc/css/phui/phui-info-view.css' => '28efab79', 'rsrc/css/phui/phui-invisible-character-view.css' => '6993d9f0', 'rsrc/css/phui/phui-list.css' => '9da2aa00', 'rsrc/css/phui/phui-object-box.css' => '6b487c57', 'rsrc/css/phui/phui-object-item-list-view.css' => '87278fa0', 'rsrc/css/phui/phui-pager.css' => 'bea33d23', 'rsrc/css/phui/phui-pinboard-view.css' => '2495140e', 'rsrc/css/phui/phui-profile-menu.css' => '8a3fc181', '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', 'rsrc/css/phui/phui-spacing.css' => '042804d6', 'rsrc/css/phui/phui-status.css' => 'd5263e49', 'rsrc/css/phui/phui-tag-view.css' => '6bbd83e2', 'rsrc/css/phui/phui-timeline-view.css' => 'bc523970', 'rsrc/css/phui/phui-two-column-view.css' => 'fcfbe347', - 'rsrc/css/phui/workboards/phui-workboard-color.css' => '6da20b15', - 'rsrc/css/phui/workboards/phui-workboard.css' => 'fe70ad9c', + 'rsrc/css/phui/workboards/phui-workboard-color.css' => 'ac6fe6a7', + 'rsrc/css/phui/workboards/phui-workboard.css' => 'e09eb53a', 'rsrc/css/phui/workboards/phui-workcard.css' => '0c62d7c5', 'rsrc/css/phui/workboards/phui-workpanel.css' => '92197373', 'rsrc/css/sprite-login.css' => '6dbbbd97', 'rsrc/css/sprite-tokens.css' => '9cdfd599', 'rsrc/css/syntax/syntax-default.css' => '9923583c', 'rsrc/externals/d3/d3.min.js' => 'a11a5ff2', 'rsrc/externals/font/aleo/aleo-bold.eot' => 'd3d3bed7', 'rsrc/externals/font/aleo/aleo-bold.svg' => '45899c8e', 'rsrc/externals/font/aleo/aleo-bold.ttf' => '4b08bef0', 'rsrc/externals/font/aleo/aleo-bold.woff' => '93b513a1', 'rsrc/externals/font/aleo/aleo-bold.woff2' => '75fbf322', 'rsrc/externals/font/aleo/aleo-regular.eot' => 'a4e29e2f', 'rsrc/externals/font/aleo/aleo-regular.svg' => '42a86f7a', 'rsrc/externals/font/aleo/aleo-regular.ttf' => '751e7479', 'rsrc/externals/font/aleo/aleo-regular.woff' => 'c3744be9', 'rsrc/externals/font/aleo/aleo-regular.woff2' => '851aa0ee', 'rsrc/externals/font/fontawesome/fontawesome-webfont.eot' => '59b3076c', 'rsrc/externals/font/fontawesome/fontawesome-webfont.ttf' => '45ad7e57', 'rsrc/externals/font/fontawesome/fontawesome-webfont.woff' => 'f861e2a8', 'rsrc/externals/font/fontawesome/fontawesome-webfont.woff2' => '0ee0f078', 'rsrc/externals/font/lato/lato-bold.eot' => '99fbcf8c', 'rsrc/externals/font/lato/lato-bold.svg' => '2aa83045', 'rsrc/externals/font/lato/lato-bold.ttf' => '0a7141f7', 'rsrc/externals/font/lato/lato-bold.woff' => 'f5db2061', 'rsrc/externals/font/lato/lato-bold.woff2' => '37a94ecd', 'rsrc/externals/font/lato/lato-bolditalic.eot' => 'b93389d0', 'rsrc/externals/font/lato/lato-bolditalic.svg' => '5442e1ef', 'rsrc/externals/font/lato/lato-bolditalic.ttf' => 'dad31252', 'rsrc/externals/font/lato/lato-bolditalic.woff' => 'e53bcf47', 'rsrc/externals/font/lato/lato-bolditalic.woff2' => 'd035007f', 'rsrc/externals/font/lato/lato-italic.eot' => '6a903f5d', 'rsrc/externals/font/lato/lato-italic.svg' => '0dc7cf2f', 'rsrc/externals/font/lato/lato-italic.ttf' => '629f64f0', 'rsrc/externals/font/lato/lato-italic.woff' => '678dc4bb', 'rsrc/externals/font/lato/lato-italic.woff2' => '7c8dd650', 'rsrc/externals/font/lato/lato-regular.eot' => '848dfb1e', 'rsrc/externals/font/lato/lato-regular.svg' => 'cbd5fd6b', 'rsrc/externals/font/lato/lato-regular.ttf' => 'e270165b', 'rsrc/externals/font/lato/lato-regular.woff' => '13d39fe2', 'rsrc/externals/font/lato/lato-regular.woff2' => '57a9f742', 'rsrc/externals/javelin/core/Event.js' => '2ee659ce', 'rsrc/externals/javelin/core/Stratcom.js' => '6ad39b6f', 'rsrc/externals/javelin/core/__tests__/event-stop-and-kill.js' => '717554e4', 'rsrc/externals/javelin/core/__tests__/install.js' => 'c432ee85', 'rsrc/externals/javelin/core/__tests__/stratcom.js' => '88bf7313', 'rsrc/externals/javelin/core/__tests__/util.js' => 'e251703d', 'rsrc/externals/javelin/core/init.js' => '3010e992', 'rsrc/externals/javelin/core/init_node.js' => 'c234aded', 'rsrc/externals/javelin/core/install.js' => '05270951', 'rsrc/externals/javelin/core/util.js' => '93cc50d6', 'rsrc/externals/javelin/docs/Base.js' => '74676256', 'rsrc/externals/javelin/docs/onload.js' => 'e819c479', 'rsrc/externals/javelin/ext/fx/Color.js' => '7e41274a', 'rsrc/externals/javelin/ext/fx/FX.js' => '54b612ba', 'rsrc/externals/javelin/ext/reactor/core/DynVal.js' => 'f6555212', 'rsrc/externals/javelin/ext/reactor/core/Reactor.js' => '2b8de964', 'rsrc/externals/javelin/ext/reactor/core/ReactorNode.js' => '1ad0a787', 'rsrc/externals/javelin/ext/reactor/core/ReactorNodeCalmer.js' => '76f4ebed', 'rsrc/externals/javelin/ext/reactor/dom/RDOM.js' => 'c90a04fc', 'rsrc/externals/javelin/ext/view/HTMLView.js' => 'fe287620', 'rsrc/externals/javelin/ext/view/View.js' => '0f764c35', 'rsrc/externals/javelin/ext/view/ViewInterpreter.js' => 'f829edb3', 'rsrc/externals/javelin/ext/view/ViewPlaceholder.js' => '47830651', 'rsrc/externals/javelin/ext/view/ViewRenderer.js' => '6c2b09a2', 'rsrc/externals/javelin/ext/view/ViewVisitor.js' => 'efe49472', 'rsrc/externals/javelin/ext/view/__tests__/HTMLView.js' => 'f92d7bcb', 'rsrc/externals/javelin/ext/view/__tests__/View.js' => '6450b38b', 'rsrc/externals/javelin/ext/view/__tests__/ViewInterpreter.js' => '7a94d6a5', 'rsrc/externals/javelin/ext/view/__tests__/ViewRenderer.js' => '6ea96ac9', 'rsrc/externals/javelin/lib/Cookie.js' => '62dfea03', 'rsrc/externals/javelin/lib/DOM.js' => '805b806a', 'rsrc/externals/javelin/lib/History.js' => 'd4505101', 'rsrc/externals/javelin/lib/JSON.js' => '69adf288', 'rsrc/externals/javelin/lib/Leader.js' => 'fea0eb47', 'rsrc/externals/javelin/lib/Mask.js' => '8a41885b', 'rsrc/externals/javelin/lib/Quicksand.js' => '6b8ef10b', 'rsrc/externals/javelin/lib/Request.js' => '94b750d2', 'rsrc/externals/javelin/lib/Resource.js' => '44959b73', 'rsrc/externals/javelin/lib/Routable.js' => 'b3e7d692', 'rsrc/externals/javelin/lib/Router.js' => '29274e2b', 'rsrc/externals/javelin/lib/Scrollbar.js' => '087e919c', 'rsrc/externals/javelin/lib/Sound.js' => '949c0fe5', 'rsrc/externals/javelin/lib/URI.js' => 'c989ade3', 'rsrc/externals/javelin/lib/Vector.js' => '2caa8fb8', 'rsrc/externals/javelin/lib/WebSocket.js' => 'e292eaf4', 'rsrc/externals/javelin/lib/Workflow.js' => '1e911d0f', 'rsrc/externals/javelin/lib/__tests__/Cookie.js' => '5ed109e8', 'rsrc/externals/javelin/lib/__tests__/DOM.js' => 'c984504b', 'rsrc/externals/javelin/lib/__tests__/JSON.js' => '837a7d68', 'rsrc/externals/javelin/lib/__tests__/URI.js' => '1e45fda9', 'rsrc/externals/javelin/lib/__tests__/behavior.js' => '1ea62783', 'rsrc/externals/javelin/lib/behavior.js' => '61cbc29a', 'rsrc/externals/javelin/lib/control/tokenizer/Tokenizer.js' => '8d3bc1b2', 'rsrc/externals/javelin/lib/control/typeahead/Typeahead.js' => '70baed2f', 'rsrc/externals/javelin/lib/control/typeahead/normalizer/TypeaheadNormalizer.js' => 'e6e25838', 'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadCompositeSource.js' => '503e17fd', 'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadOnDemandSource.js' => '013ffff9', 'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadPreloadedSource.js' => '54f314a0', 'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadSource.js' => 'b25d5444', 'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadStaticSource.js' => '6c0e62fa', 'rsrc/favicons/apple-touch-icon-114x114.png' => '12a24178', 'rsrc/favicons/apple-touch-icon-120x120.png' => '0d1543c7', 'rsrc/favicons/apple-touch-icon-144x144.png' => '8043b5a5', 'rsrc/favicons/apple-touch-icon-152x152.png' => '65905ecd', 'rsrc/favicons/apple-touch-icon-57x57.png' => '2bfc7b0a', 'rsrc/favicons/apple-touch-icon-60x60.png' => '8ff52925', 'rsrc/favicons/apple-touch-icon-72x72.png' => 'a2bb65d6', 'rsrc/favicons/apple-touch-icon-76x76.png' => '2d061a11', 'rsrc/favicons/dark/apple-touch-icon-114x114.png' => 'd0c8978c', 'rsrc/favicons/dark/apple-touch-icon-120x120.png' => '3a618bc0', 'rsrc/favicons/dark/apple-touch-icon-144x144.png' => '92c1e188', 'rsrc/favicons/dark/apple-touch-icon-152x152.png' => '7ce7e469', 'rsrc/favicons/dark/apple-touch-icon-57x57.png' => 'e3f3f38b', 'rsrc/favicons/dark/apple-touch-icon-60x60.png' => '1e0dcc72', 'rsrc/favicons/dark/apple-touch-icon-72x72.png' => '7fb599b6', 'rsrc/favicons/dark/apple-touch-icon-76x76.png' => '91146961', 'rsrc/favicons/dark/favicon-128.png' => 'd6ac4346', 'rsrc/favicons/dark/favicon-16x16.png' => '17434bb0', 'rsrc/favicons/dark/favicon-196x196.png' => '5e06ee72', 'rsrc/favicons/dark/favicon-32x32.png' => 'bdd7e16b', 'rsrc/favicons/dark/favicon-96x96.png' => '0cf55978', 'rsrc/favicons/dark/mstile-144x144.png' => '4dc9d42d', 'rsrc/favicons/dark/mstile-150x150.png' => '2dc61c90', 'rsrc/favicons/dark/mstile-310x150.png' => '4fe58ab2', 'rsrc/favicons/dark/mstile-310x310.png' => 'e62c1677', 'rsrc/favicons/dark/mstile-70x70.png' => '6d1f41b7', 'rsrc/favicons/favicon-128.png' => '72f7e812', 'rsrc/favicons/favicon-16x16.png' => 'fc6275ba', 'rsrc/favicons/favicon-196x196.png' => '95db275e', 'rsrc/favicons/favicon-32x32.png' => '5bd18b6c', 'rsrc/favicons/favicon-96x96.png' => '7242c8e9', 'rsrc/favicons/mask-icon.svg' => 'e132a80f', 'rsrc/favicons/mstile-144x144.png' => '310c2ee5', 'rsrc/favicons/mstile-150x150.png' => '74bf5133', 'rsrc/favicons/mstile-310x150.png' => '4a49d3ee', 'rsrc/favicons/mstile-310x310.png' => 'a52ab264', 'rsrc/favicons/mstile-70x70.png' => '5edce7b8', 'rsrc/favicons/red/apple-touch-icon-114x114.png' => '91e37d1d', 'rsrc/favicons/red/apple-touch-icon-120x120.png' => '66687533', 'rsrc/favicons/red/apple-touch-icon-144x144.png' => 'bc06002c', 'rsrc/favicons/red/apple-touch-icon-152x152.png' => 'a713de42', 'rsrc/favicons/red/apple-touch-icon-57x57.png' => '4729688b', 'rsrc/favicons/red/apple-touch-icon-60x60.png' => '07b9b609', 'rsrc/favicons/red/apple-touch-icon-72x72.png' => 'b20c3698', 'rsrc/favicons/red/apple-touch-icon-76x76.png' => 'c6e7dd5c', 'rsrc/favicons/red/favicon-128.png' => 'e2b2f8fe', 'rsrc/favicons/red/favicon-16x16.png' => '929fbceb', 'rsrc/favicons/red/favicon-196x196.png' => '94c089a5', 'rsrc/favicons/red/favicon-32x32.png' => '5848673e', 'rsrc/favicons/red/favicon-96x96.png' => '895d54e8', 'rsrc/favicons/red/mstile-144x144.png' => '448639f5', 'rsrc/favicons/red/mstile-150x150.png' => 'c2ba45d0', 'rsrc/favicons/red/mstile-310x150.png' => 'b0e50799', 'rsrc/favicons/red/mstile-310x310.png' => '2475c5a5', 'rsrc/favicons/red/mstile-70x70.png' => '49b197e8', 'rsrc/favicons/yellow/apple-touch-icon-114x114.png' => '5271fb3f', 'rsrc/favicons/yellow/apple-touch-icon-120x120.png' => '6c3d9bf9', 'rsrc/favicons/yellow/apple-touch-icon-144x144.png' => '6484472c', 'rsrc/favicons/yellow/apple-touch-icon-152x152.png' => 'e305dda8', 'rsrc/favicons/yellow/apple-touch-icon-57x57.png' => 'fa6c43d4', 'rsrc/favicons/yellow/apple-touch-icon-60x60.png' => '2673f162', 'rsrc/favicons/yellow/apple-touch-icon-72x72.png' => '3ad8020c', 'rsrc/favicons/yellow/apple-touch-icon-76x76.png' => '58cffd81', 'rsrc/favicons/yellow/favicon-128.png' => '3b2f8233', 'rsrc/favicons/yellow/favicon-16x16.png' => 'f3a90518', 'rsrc/favicons/yellow/favicon-196x196.png' => '932c7c65', 'rsrc/favicons/yellow/favicon-32x32.png' => '005c9f92', 'rsrc/favicons/yellow/favicon-96x96.png' => '3ad9bfa9', 'rsrc/favicons/yellow/mstile-144x144.png' => 'fc52335c', 'rsrc/favicons/yellow/mstile-150x150.png' => '9e556f80', 'rsrc/favicons/yellow/mstile-310x150.png' => '2c915073', 'rsrc/favicons/yellow/mstile-310x310.png' => 'ee49978d', 'rsrc/favicons/yellow/mstile-70x70.png' => '85c7c939', 'rsrc/image/BFCFDA.png' => 'd5ec91f4', 'rsrc/image/actions/edit.png' => '2fc41442', 'rsrc/image/avatar.png' => 'e132bb6a', 'rsrc/image/checker_dark.png' => 'd8e65881', 'rsrc/image/checker_light.png' => 'a0155918', 'rsrc/image/checker_lighter.png' => 'd5da91b6', 'rsrc/image/d5d8e1.png' => '0c2a1497', 'rsrc/image/darkload.gif' => '1ffd3ec6', 'rsrc/image/divot.png' => '94dded62', 'rsrc/image/examples/hero.png' => '979a86ae', 'rsrc/image/grippy_texture.png' => 'aca81e2f', 'rsrc/image/icon/fatcow/arrow_branch.png' => '2537c01c', 'rsrc/image/icon/fatcow/arrow_merge.png' => '21b660e0', 'rsrc/image/icon/fatcow/bullet_black.png' => 'ff190031', 'rsrc/image/icon/fatcow/bullet_orange.png' => 'e273e5bb', 'rsrc/image/icon/fatcow/bullet_red.png' => 'c0b75434', 'rsrc/image/icon/fatcow/calendar_edit.png' => '24632275', 'rsrc/image/icon/fatcow/document_black.png' => '45fe1c60', 'rsrc/image/icon/fatcow/flag_blue.png' => 'a01abb1d', 'rsrc/image/icon/fatcow/flag_finish.png' => '67825cee', 'rsrc/image/icon/fatcow/flag_ghost.png' => '20ca8783', 'rsrc/image/icon/fatcow/flag_green.png' => '7e0eaa7a', 'rsrc/image/icon/fatcow/flag_orange.png' => '9e73df66', 'rsrc/image/icon/fatcow/flag_pink.png' => '7e92f3b2', 'rsrc/image/icon/fatcow/flag_purple.png' => 'cc517522', 'rsrc/image/icon/fatcow/flag_red.png' => '04ec726f', 'rsrc/image/icon/fatcow/flag_yellow.png' => '73946fd4', 'rsrc/image/icon/fatcow/key_question.png' => '52a0c26a', 'rsrc/image/icon/fatcow/link.png' => '7afd4d5e', 'rsrc/image/icon/fatcow/page_white_edit.png' => '39a2eed8', 'rsrc/image/icon/fatcow/page_white_put.png' => '08c95a0c', 'rsrc/image/icon/fatcow/source/conduit.png' => '4ea01d2f', 'rsrc/image/icon/fatcow/source/email.png' => '9bab3239', 'rsrc/image/icon/fatcow/source/fax.png' => '04195e68', 'rsrc/image/icon/fatcow/source/mobile.png' => 'f1321264', 'rsrc/image/icon/fatcow/source/tablet.png' => '49396799', 'rsrc/image/icon/fatcow/source/web.png' => '136ccb5d', 'rsrc/image/icon/lightbox/close-2.png' => 'cc40e7c8', 'rsrc/image/icon/lightbox/close-hover-2.png' => 'fb5d6d9e', 'rsrc/image/icon/lightbox/left-arrow-2.png' => '8426133b', 'rsrc/image/icon/lightbox/left-arrow-hover-2.png' => '701e5ee3', 'rsrc/image/icon/lightbox/right-arrow-2.png' => '6d5519a0', 'rsrc/image/icon/lightbox/right-arrow-hover-2.png' => '3a04aa21', 'rsrc/image/icon/subscribe.png' => 'd03ed5a5', 'rsrc/image/icon/tango/attachment.png' => 'ecc8022e', 'rsrc/image/icon/tango/edit.png' => '929a1363', 'rsrc/image/icon/tango/go-down.png' => '96d95e43', 'rsrc/image/icon/tango/log.png' => 'b08cc63a', 'rsrc/image/icon/tango/upload.png' => '7bbb7984', 'rsrc/image/icon/unsubscribe.png' => '25725013', 'rsrc/image/lightblue-header.png' => '5c168b6d', 'rsrc/image/logo/light-eye.png' => '1a576ddd', 'rsrc/image/main_texture.png' => '29a2c5ad', 'rsrc/image/menu_texture.png' => '5a17580d', 'rsrc/image/people/harding.png' => '45aa614e', 'rsrc/image/people/jefferson.png' => 'afca0e53', 'rsrc/image/people/lincoln.png' => '9369126d', 'rsrc/image/people/mckinley.png' => 'fb8f16ce', 'rsrc/image/people/taft.png' => 'd7bc402c', 'rsrc/image/people/user0.png' => '03dacaea', 'rsrc/image/people/user1.png' => '4a4e7702', 'rsrc/image/people/user2.png' => '47a0ee40', 'rsrc/image/people/user3.png' => '835ff627', 'rsrc/image/people/user4.png' => 'b0e830f1', 'rsrc/image/people/user5.png' => '9c95b369', 'rsrc/image/people/user6.png' => 'ba3fbfb0', 'rsrc/image/people/user7.png' => 'da613924', 'rsrc/image/people/user8.png' => 'f1035edf', 'rsrc/image/people/user9.png' => '66730be3', 'rsrc/image/people/washington.png' => '40dd301c', 'rsrc/image/phrequent_active.png' => 'a466a8ed', 'rsrc/image/phrequent_inactive.png' => 'bfc15a69', 'rsrc/image/resize.png' => 'fd476de4', 'rsrc/image/sprite-login-X2.png' => '4abee916', 'rsrc/image/sprite-login.png' => '2b9663fd', 'rsrc/image/sprite-tokens-X2.png' => '804a5232', 'rsrc/image/sprite-tokens.png' => 'b41d03da', 'rsrc/image/texture/card-gradient.png' => '815f26e8', 'rsrc/image/texture/dark-menu-hover.png' => '5fa7ece8', 'rsrc/image/texture/dark-menu.png' => '7e22296e', 'rsrc/image/texture/grip.png' => '719404f3', 'rsrc/image/texture/panel-header-gradient.png' => 'e3b8dcfe', 'rsrc/image/texture/phlnx-bg.png' => '8d819209', 'rsrc/image/texture/pholio-background.gif' => 'ba29239c', 'rsrc/image/texture/table_header.png' => '5c433037', 'rsrc/image/texture/table_header_hover.png' => '038ec3b9', 'rsrc/image/texture/table_header_tall.png' => 'd56b434f', 'rsrc/js/application/aphlict/Aphlict.js' => '5359e785', 'rsrc/js/application/aphlict/behavior-aphlict-dropdown.js' => '49e20786', 'rsrc/js/application/aphlict/behavior-aphlict-listen.js' => 'fb20ac8d', 'rsrc/js/application/aphlict/behavior-aphlict-status.js' => 'ea681761', 'rsrc/js/application/aphlict/behavior-desktop-notifications-control.js' => 'edd1ba66', 'rsrc/js/application/auth/behavior-persona-login.js' => '9414ff18', 'rsrc/js/application/calendar/behavior-day-view.js' => '4b3c4443', 'rsrc/js/application/calendar/behavior-event-all-day.js' => '937bb700', 'rsrc/js/application/calendar/behavior-month-view.js' => 'fe33e256', 'rsrc/js/application/calendar/behavior-recurring-edit.js' => '5f1c4d5f', 'rsrc/js/application/config/behavior-reorder-fields.js' => 'b6993408', 'rsrc/js/application/conpherence/ConpherenceThreadManager.js' => '01774ab2', 'rsrc/js/application/conpherence/behavior-drag-and-drop-photo.js' => 'cf86d16a', 'rsrc/js/application/conpherence/behavior-durable-column.js' => 'a0e564c2', 'rsrc/js/application/conpherence/behavior-menu.js' => '9eb55204', 'rsrc/js/application/conpherence/behavior-participant-pane.js' => '8604caa8', 'rsrc/js/application/conpherence/behavior-pontificate.js' => 'f2e58483', 'rsrc/js/application/conpherence/behavior-quicksand-blacklist.js' => '7927a7d3', 'rsrc/js/application/conpherence/behavior-toggle-widget.js' => '9bdbbab0', 'rsrc/js/application/countdown/timer.js' => 'e4cc26b3', 'rsrc/js/application/daemon/behavior-bulk-job-reload.js' => 'edf8a145', 'rsrc/js/application/dashboard/behavior-dashboard-async-panel.js' => '469c0d9e', 'rsrc/js/application/dashboard/behavior-dashboard-move-panels.js' => '019f36c4', 'rsrc/js/application/dashboard/behavior-dashboard-query-panel-select.js' => '453c5375', 'rsrc/js/application/dashboard/behavior-dashboard-tab-panel.js' => 'd4eecc63', 'rsrc/js/application/differential/ChangesetViewManager.js' => 'a2828756', 'rsrc/js/application/differential/DifferentialInlineCommentEditor.js' => '64a5550f', 'rsrc/js/application/differential/behavior-add-reviewers-and-ccs.js' => 'e10f8e18', 'rsrc/js/application/differential/behavior-comment-jump.js' => '4fdb476d', 'rsrc/js/application/differential/behavior-comment-preview.js' => 'b064af76', 'rsrc/js/application/differential/behavior-diff-radios.js' => 'e1ff79b1', 'rsrc/js/application/differential/behavior-dropdown-menus.js' => '9a6b9324', 'rsrc/js/application/differential/behavior-edit-inline-comments.js' => '4fbbc3e9', 'rsrc/js/application/differential/behavior-keyboard-nav.js' => '2c426492', 'rsrc/js/application/differential/behavior-populate.js' => '8694b1df', 'rsrc/js/application/differential/behavior-toggle-files.js' => 'ca3f91eb', 'rsrc/js/application/differential/behavior-user-select.js' => 'a8d8459d', 'rsrc/js/application/diffusion/DiffusionLocateFileSource.js' => 'b42eddc7', 'rsrc/js/application/diffusion/behavior-audit-preview.js' => 'd835b03a', 'rsrc/js/application/diffusion/behavior-commit-branches.js' => 'bdaf4d04', 'rsrc/js/application/diffusion/behavior-commit-graph.js' => '49ae8328', 'rsrc/js/application/diffusion/behavior-diffusion-browse-file.js' => '054a0f0b', 'rsrc/js/application/diffusion/behavior-jump-to.js' => '73d09eef', 'rsrc/js/application/diffusion/behavior-load-blame.js' => '42126667', 'rsrc/js/application/diffusion/behavior-locate-file.js' => '6d3e1947', 'rsrc/js/application/diffusion/behavior-pull-lastmodified.js' => 'f01586dc', 'rsrc/js/application/doorkeeper/behavior-doorkeeper-tag.js' => 'e5822781', 'rsrc/js/application/drydock/drydock-live-operation-status.js' => '901935ef', 'rsrc/js/application/files/behavior-icon-composer.js' => '8499b6ab', 'rsrc/js/application/files/behavior-launch-icon-composer.js' => '48086888', 'rsrc/js/application/herald/HeraldRuleEditor.js' => 'd6a7e717', 'rsrc/js/application/herald/PathTypeahead.js' => 'f7fc67ec', 'rsrc/js/application/herald/herald-rule-editor.js' => '7ebaeed3', 'rsrc/js/application/maniphest/behavior-batch-editor.js' => '782ab6e7', 'rsrc/js/application/maniphest/behavior-batch-selector.js' => '7b98d7c5', 'rsrc/js/application/maniphest/behavior-line-chart.js' => 'e4232876', 'rsrc/js/application/maniphest/behavior-list-edit.js' => 'a9f88de2', 'rsrc/js/application/maniphest/behavior-subpriorityeditor.js' => '71237763', 'rsrc/js/application/owners/OwnersPathEditor.js' => 'aa1733d0', 'rsrc/js/application/owners/owners-path-editor.js' => '7a68dda3', 'rsrc/js/application/passphrase/passphrase-credential-control.js' => '3cb0b2fc', 'rsrc/js/application/pholio/behavior-pholio-mock-edit.js' => 'bee502c8', 'rsrc/js/application/pholio/behavior-pholio-mock-view.js' => 'fbe497e7', 'rsrc/js/application/phortune/behavior-stripe-payment-form.js' => '3f5d6dbf', 'rsrc/js/application/phortune/behavior-test-payment-form.js' => 'fc91ab6c', 'rsrc/js/application/phortune/phortune-credit-card-form.js' => '2290aeef', 'rsrc/js/application/policy/behavior-policy-control.js' => 'd0c516d5', 'rsrc/js/application/policy/behavior-policy-rule-editor.js' => '5e9f347c', 'rsrc/js/application/projects/WorkboardBoard.js' => 'fe7cb52a', '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-create.js' => '065227cc', 'rsrc/js/application/projects/behavior-reorder-columns.js' => 'e1d25dfb', 'rsrc/js/application/releeph/releeph-preview-branch.js' => 'b2b4fbaf', 'rsrc/js/application/releeph/releeph-request-state-change.js' => 'a0b57eb8', 'rsrc/js/application/releeph/releeph-request-typeahead.js' => 'de2e896f', 'rsrc/js/application/repository/repository-crossreference.js' => 'e5339c43', 'rsrc/js/application/search/behavior-reorder-profile-menu-items.js' => 'e2e0a072', 'rsrc/js/application/search/behavior-reorder-queries.js' => 'e9581f08', 'rsrc/js/application/slowvote/behavior-slowvote-embed.js' => '887ad43f', 'rsrc/js/application/transactions/behavior-comment-actions.js' => '0300eae6', 'rsrc/js/application/transactions/behavior-reorder-configs.js' => 'd7a74243', 'rsrc/js/application/transactions/behavior-reorder-fields.js' => 'b59e1e96', 'rsrc/js/application/transactions/behavior-show-older-transactions.js' => '94c65b72', 'rsrc/js/application/transactions/behavior-transaction-comment-form.js' => 'b23b49e6', 'rsrc/js/application/transactions/behavior-transaction-list.js' => '13c739ea', 'rsrc/js/application/typeahead/behavior-typeahead-browse.js' => '635de1ec', 'rsrc/js/application/typeahead/behavior-typeahead-search.js' => '93d0c9e3', 'rsrc/js/application/uiexample/JavelinViewExample.js' => 'd4a14807', 'rsrc/js/application/uiexample/ReactorButtonExample.js' => 'd19198c8', 'rsrc/js/application/uiexample/ReactorCheckboxExample.js' => '519705ea', 'rsrc/js/application/uiexample/ReactorFocusExample.js' => '40a6a403', 'rsrc/js/application/uiexample/ReactorInputExample.js' => '886fd850', 'rsrc/js/application/uiexample/ReactorMouseoverExample.js' => '47c794d8', 'rsrc/js/application/uiexample/ReactorRadioExample.js' => '988040b4', 'rsrc/js/application/uiexample/ReactorSelectExample.js' => 'a155550f', 'rsrc/js/application/uiexample/ReactorSendClassExample.js' => '1def2711', 'rsrc/js/application/uiexample/ReactorSendPropertiesExample.js' => 'b1f0ccee', 'rsrc/js/application/uiexample/busy-example.js' => '60479091', 'rsrc/js/application/uiexample/gesture-example.js' => '558829c2', 'rsrc/js/application/uiexample/notification-example.js' => '8ce821c5', 'rsrc/js/core/Busy.js' => '59a7976a', 'rsrc/js/core/DragAndDropFileUpload.js' => '58dea2fa', 'rsrc/js/core/DraggableList.js' => '5a13c79f', 'rsrc/js/core/FileUpload.js' => '680ea2c8', 'rsrc/js/core/Hovercard.js' => '1bd28176', 'rsrc/js/core/KeyboardShortcut.js' => '1ae869f2', 'rsrc/js/core/KeyboardShortcutManager.js' => '4a021c10', 'rsrc/js/core/MultirowRowManager.js' => 'b5d57730', 'rsrc/js/core/Notification.js' => 'ccf1cbf8', 'rsrc/js/core/Prefab.js' => 'cfd23f37', 'rsrc/js/core/ShapedRequest.js' => '7cbe244b', 'rsrc/js/core/TextAreaUtils.js' => '320810c8', 'rsrc/js/core/Title.js' => 'df5e11d2', 'rsrc/js/core/ToolTip.js' => '6323f942', 'rsrc/js/core/behavior-active-nav.js' => 'e379b58e', 'rsrc/js/core/behavior-audio-source.js' => '59b251eb', 'rsrc/js/core/behavior-autofocus.js' => '7319e029', 'rsrc/js/core/behavior-badge-view.js' => '8ff5e24c', 'rsrc/js/core/behavior-choose-control.js' => '327a00d1', 'rsrc/js/core/behavior-crop.js' => 'fa0f4fc2', 'rsrc/js/core/behavior-dark-console.js' => 'f411b6ae', 'rsrc/js/core/behavior-detect-timezone.js' => '4c193c96', 'rsrc/js/core/behavior-device.js' => 'bb1dd507', 'rsrc/js/core/behavior-drag-and-drop-textarea.js' => '484a6e22', 'rsrc/js/core/behavior-error-log.js' => '6882e80a', 'rsrc/js/core/behavior-fancy-datepicker.js' => '568931f3', 'rsrc/js/core/behavior-file-tree.js' => '88236f00', 'rsrc/js/core/behavior-form.js' => '5c54cbf3', 'rsrc/js/core/behavior-gesture.js' => '3ab51e2c', 'rsrc/js/core/behavior-global-drag-and-drop.js' => 'c8e57404', 'rsrc/js/core/behavior-high-security-warning.js' => 'a464fe03', 'rsrc/js/core/behavior-history-install.js' => '7ee2b591', 'rsrc/js/core/behavior-hovercard.js' => 'bcaccd64', 'rsrc/js/core/behavior-keyboard-pager.js' => 'a8da01f0', 'rsrc/js/core/behavior-keyboard-shortcuts.js' => '01fca1f0', 'rsrc/js/core/behavior-lightbox-attachments.js' => 'f8ba29d7', 'rsrc/js/core/behavior-line-linker.js' => '1499a8cb', 'rsrc/js/core/behavior-more.js' => 'a80d0378', 'rsrc/js/core/behavior-object-selector.js' => 'e0ec7f2f', 'rsrc/js/core/behavior-oncopy.js' => '2926fff2', 'rsrc/js/core/behavior-phabricator-nav.js' => '08675c6d', 'rsrc/js/core/behavior-phabricator-remarkup-assist.js' => '116cf19b', 'rsrc/js/core/behavior-read-only-warning.js' => 'ba158207', 'rsrc/js/core/behavior-refresh-csrf.js' => 'ab2f381b', 'rsrc/js/core/behavior-remarkup-preview.js' => '4b700e9e', 'rsrc/js/core/behavior-reorder-applications.js' => '76b9fc3e', 'rsrc/js/core/behavior-reveal-content.js' => '60821bc7', 'rsrc/js/core/behavior-scrollbar.js' => '834a1173', 'rsrc/js/core/behavior-search-typeahead.js' => '06c32383', 'rsrc/js/core/behavior-select-content.js' => 'bf5374ef', 'rsrc/js/core/behavior-select-on-click.js' => '4e3e79a6', 'rsrc/js/core/behavior-setup-check-https.js' => '491416b3', 'rsrc/js/core/behavior-time-typeahead.js' => '522431f7', '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-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-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/PHUIXAutocomplete.js' => '6d86ce8b', 'rsrc/js/phuix/PHUIXDropdownMenu.js' => '82e270da', 'rsrc/js/phuix/PHUIXFormControl.js' => 'e15869a8', 'rsrc/js/phuix/PHUIXIconView.js' => 'bff6884b', ), 'symbols' => array( 'almanac-css' => 'dbb9b3af', 'aphront-bars' => '231ac33c', 'aphront-dark-console-css' => 'f54bf286', 'aphront-dialog-view-css' => '593d3f67', 'aphront-list-filter-view-css' => '5d6f0526', 'aphront-multi-column-view-css' => '84cc6640', 'aphront-panel-view-css' => '8427b78d', 'aphront-table-view-css' => '3225137a', 'aphront-tokenizer-control-css' => '056da01b', 'aphront-tooltip-css' => '1a07aea8', 'aphront-typeahead-control-css' => 'd4f16145', - 'application-search-view-css' => '9c9bc8dc', + 'application-search-view-css' => 'be6454ec', 'auth-css' => '0877ed6e', 'bulk-job-css' => 'df9c1d4a', 'changeset-view-manager' => 'a2828756', 'conduit-api-css' => '7bc725c4', 'config-options-css' => '0ede4c9b', 'config-page-css' => '8798e14f', 'conpherence-durable-column-view' => 'af11a2a7', 'conpherence-header-pane-css' => '517de9fe', 'conpherence-menu-css' => '78c7b811', 'conpherence-message-pane-css' => '0d7dff02', 'conpherence-notification-css' => '65dd0e79', 'conpherence-participant-pane-css' => '7bba0b56', 'conpherence-thread-manager' => '01774ab2', 'conpherence-transaction-css' => '46253e19', 'conpherence-update-css' => '53bc527a', 'd3' => 'a11a5ff2', 'differential-changeset-view-css' => '9ef7d354', 'differential-core-view-css' => '5b7b8ff4', 'differential-inline-comment-editor' => '64a5550f', 'differential-revision-add-comment-css' => 'c47f8c40', 'differential-revision-comment-css' => '14b8565a', 'differential-revision-history-css' => '0e8eb855', 'differential-revision-list-css' => 'f3c47d33', 'differential-table-of-contents-css' => 'ae4b7a55', 'diffusion-icons-css' => 'd678600a', 'diffusion-readme-css' => '297373eb', 'diffusion-source-css' => '68b30fd3', 'diviner-shared-css' => 'aa3656aa', 'font-aleo' => '8bdb2835', 'font-fontawesome' => '2b7ebbcc', 'font-lato' => 'c7ccd872', 'global-drag-and-drop-css' => '5c1b47c2', 'harbormaster-css' => 'f491c9f4', 'herald-css' => 'dc31f6e9', 'herald-rule-editor' => 'd6a7e717', 'herald-test-css' => 'a52e323e', 'inline-comment-summary-css' => '51efda3a', 'javelin-aphlict' => '5359e785', 'javelin-behavior' => '61cbc29a', 'javelin-behavior-aphlict-dropdown' => '49e20786', 'javelin-behavior-aphlict-listen' => 'fb20ac8d', 'javelin-behavior-aphlict-status' => 'ea681761', 'javelin-behavior-aphront-basic-tokenizer' => 'b3a4b884', 'javelin-behavior-aphront-crop' => 'fa0f4fc2', 'javelin-behavior-aphront-drag-and-drop-textarea' => '484a6e22', 'javelin-behavior-aphront-form-disable-on-submit' => '5c54cbf3', 'javelin-behavior-aphront-more' => 'a80d0378', 'javelin-behavior-audio-source' => '59b251eb', 'javelin-behavior-audit-preview' => 'd835b03a', 'javelin-behavior-badge-view' => '8ff5e24c', 'javelin-behavior-bulk-job-reload' => 'edf8a145', 'javelin-behavior-calendar-month-view' => 'fe33e256', 'javelin-behavior-choose-control' => '327a00d1', 'javelin-behavior-comment-actions' => '0300eae6', 'javelin-behavior-config-reorder-fields' => 'b6993408', 'javelin-behavior-conpherence-drag-and-drop-photo' => 'cf86d16a', 'javelin-behavior-conpherence-menu' => '9eb55204', 'javelin-behavior-conpherence-participant-pane' => '8604caa8', 'javelin-behavior-conpherence-pontificate' => 'f2e58483', 'javelin-behavior-countdown-timer' => 'e4cc26b3', 'javelin-behavior-dark-console' => 'f411b6ae', 'javelin-behavior-dashboard-async-panel' => '469c0d9e', 'javelin-behavior-dashboard-move-panels' => '019f36c4', 'javelin-behavior-dashboard-query-panel-select' => '453c5375', 'javelin-behavior-dashboard-tab-panel' => 'd4eecc63', 'javelin-behavior-day-view' => '4b3c4443', 'javelin-behavior-desktop-notifications-control' => 'edd1ba66', 'javelin-behavior-detect-timezone' => '4c193c96', 'javelin-behavior-device' => 'bb1dd507', 'javelin-behavior-differential-add-reviewers-and-ccs' => 'e10f8e18', 'javelin-behavior-differential-comment-jump' => '4fdb476d', 'javelin-behavior-differential-diff-radios' => 'e1ff79b1', 'javelin-behavior-differential-dropdown-menus' => '9a6b9324', 'javelin-behavior-differential-edit-inline-comments' => '4fbbc3e9', 'javelin-behavior-differential-feedback-preview' => 'b064af76', 'javelin-behavior-differential-keyboard-navigation' => '2c426492', 'javelin-behavior-differential-populate' => '8694b1df', 'javelin-behavior-differential-toggle-files' => 'ca3f91eb', 'javelin-behavior-differential-user-select' => 'a8d8459d', 'javelin-behavior-diffusion-browse-file' => '054a0f0b', 'javelin-behavior-diffusion-commit-branches' => 'bdaf4d04', 'javelin-behavior-diffusion-commit-graph' => '49ae8328', 'javelin-behavior-diffusion-jump-to' => '73d09eef', 'javelin-behavior-diffusion-locate-file' => '6d3e1947', 'javelin-behavior-diffusion-pull-lastmodified' => 'f01586dc', 'javelin-behavior-doorkeeper-tag' => 'e5822781', 'javelin-behavior-drydock-live-operation-status' => '901935ef', 'javelin-behavior-durable-column' => 'a0e564c2', 'javelin-behavior-editengine-reorder-configs' => 'd7a74243', 'javelin-behavior-editengine-reorder-fields' => 'b59e1e96', 'javelin-behavior-error-log' => '6882e80a', 'javelin-behavior-event-all-day' => '937bb700', 'javelin-behavior-fancy-datepicker' => '568931f3', 'javelin-behavior-global-drag-and-drop' => 'c8e57404', 'javelin-behavior-herald-rule-editor' => '7ebaeed3', 'javelin-behavior-high-security-warning' => 'a464fe03', 'javelin-behavior-history-install' => '7ee2b591', 'javelin-behavior-icon-composer' => '8499b6ab', 'javelin-behavior-launch-icon-composer' => '48086888', 'javelin-behavior-lightbox-attachments' => 'f8ba29d7', 'javelin-behavior-line-chart' => 'e4232876', 'javelin-behavior-load-blame' => '42126667', 'javelin-behavior-maniphest-batch-editor' => '782ab6e7', 'javelin-behavior-maniphest-batch-selector' => '7b98d7c5', 'javelin-behavior-maniphest-list-editor' => 'a9f88de2', 'javelin-behavior-maniphest-subpriority-editor' => '71237763', 'javelin-behavior-owners-path-editor' => '7a68dda3', 'javelin-behavior-passphrase-credential-control' => '3cb0b2fc', 'javelin-behavior-persona-login' => '9414ff18', 'javelin-behavior-phabricator-active-nav' => 'e379b58e', 'javelin-behavior-phabricator-autofocus' => '7319e029', 'javelin-behavior-phabricator-busy-example' => '60479091', 'javelin-behavior-phabricator-file-tree' => '88236f00', 'javelin-behavior-phabricator-gesture' => '3ab51e2c', 'javelin-behavior-phabricator-gesture-example' => '558829c2', 'javelin-behavior-phabricator-keyboard-pager' => 'a8da01f0', 'javelin-behavior-phabricator-keyboard-shortcuts' => '01fca1f0', 'javelin-behavior-phabricator-line-linker' => '1499a8cb', 'javelin-behavior-phabricator-nav' => '08675c6d', 'javelin-behavior-phabricator-notification-example' => '8ce821c5', 'javelin-behavior-phabricator-object-selector' => 'e0ec7f2f', 'javelin-behavior-phabricator-oncopy' => '2926fff2', 'javelin-behavior-phabricator-remarkup-assist' => '116cf19b', 'javelin-behavior-phabricator-reveal-content' => '60821bc7', 'javelin-behavior-phabricator-search-typeahead' => '06c32383', 'javelin-behavior-phabricator-show-older-transactions' => '94c65b72', 'javelin-behavior-phabricator-tooltips' => '42fcb747', 'javelin-behavior-phabricator-transaction-comment-form' => 'b23b49e6', 'javelin-behavior-phabricator-transaction-list' => '13c739ea', 'javelin-behavior-phabricator-watch-anchor' => '9f36c42d', 'javelin-behavior-pholio-mock-edit' => 'bee502c8', 'javelin-behavior-pholio-mock-view' => 'fbe497e7', 'javelin-behavior-phui-dropdown-menu' => '1aa4c968', '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-create' => '065227cc', 'javelin-behavior-quicksand-blacklist' => '7927a7d3', 'javelin-behavior-read-only-warning' => 'ba158207', 'javelin-behavior-recurring-edit' => '5f1c4d5f', 'javelin-behavior-refresh-csrf' => 'ab2f381b', 'javelin-behavior-releeph-preview-branch' => 'b2b4fbaf', 'javelin-behavior-releeph-request-state-change' => 'a0b57eb8', 'javelin-behavior-releeph-request-typeahead' => 'de2e896f', 'javelin-behavior-remarkup-preview' => '4b700e9e', 'javelin-behavior-reorder-applications' => '76b9fc3e', 'javelin-behavior-reorder-columns' => 'e1d25dfb', 'javelin-behavior-reorder-profile-menu-items' => 'e2e0a072', 'javelin-behavior-repository-crossreference' => 'e5339c43', 'javelin-behavior-scrollbar' => '834a1173', 'javelin-behavior-search-reorder-queries' => 'e9581f08', 'javelin-behavior-select-content' => 'bf5374ef', 'javelin-behavior-select-on-click' => '4e3e79a6', 'javelin-behavior-setup-check-https' => '491416b3', 'javelin-behavior-slowvote-embed' => '887ad43f', 'javelin-behavior-stripe-payment-form' => '3f5d6dbf', 'javelin-behavior-test-payment-form' => 'fc91ab6c', 'javelin-behavior-time-typeahead' => '522431f7', 'javelin-behavior-toggle-class' => '92b9ec77', 'javelin-behavior-toggle-widget' => '9bdbbab0', 'javelin-behavior-typeahead-browse' => '635de1ec', 'javelin-behavior-typeahead-search' => '93d0c9e3', 'javelin-behavior-view-placeholder' => '47830651', 'javelin-behavior-workflow' => '0a3f3021', 'javelin-color' => '7e41274a', 'javelin-cookie' => '62dfea03', 'javelin-diffusion-locate-file-source' => 'b42eddc7', 'javelin-dom' => '805b806a', 'javelin-dynval' => 'f6555212', 'javelin-event' => '2ee659ce', 'javelin-fx' => '54b612ba', 'javelin-history' => 'd4505101', 'javelin-install' => '05270951', 'javelin-json' => '69adf288', 'javelin-leader' => 'fea0eb47', 'javelin-magical-init' => '3010e992', 'javelin-mask' => '8a41885b', 'javelin-quicksand' => '6b8ef10b', 'javelin-reactor' => '2b8de964', 'javelin-reactor-dom' => 'c90a04fc', 'javelin-reactor-node-calmer' => '76f4ebed', 'javelin-reactornode' => '1ad0a787', 'javelin-request' => '94b750d2', 'javelin-resource' => '44959b73', 'javelin-routable' => 'b3e7d692', 'javelin-router' => '29274e2b', 'javelin-scrollbar' => '087e919c', 'javelin-sound' => '949c0fe5', 'javelin-stratcom' => '6ad39b6f', 'javelin-tokenizer' => '8d3bc1b2', 'javelin-typeahead' => '70baed2f', 'javelin-typeahead-composite-source' => '503e17fd', 'javelin-typeahead-normalizer' => 'e6e25838', 'javelin-typeahead-ondemand-source' => '013ffff9', 'javelin-typeahead-preloaded-source' => '54f314a0', 'javelin-typeahead-source' => 'b25d5444', 'javelin-typeahead-static-source' => '6c0e62fa', 'javelin-uri' => 'c989ade3', 'javelin-util' => '93cc50d6', 'javelin-vector' => '2caa8fb8', 'javelin-view' => '0f764c35', 'javelin-view-html' => 'fe287620', 'javelin-view-interpreter' => 'f829edb3', 'javelin-view-renderer' => '6c2b09a2', 'javelin-view-visitor' => 'efe49472', 'javelin-websocket' => 'e292eaf4', 'javelin-workboard-board' => 'fe7cb52a', 'javelin-workboard-card' => 'c587b80f', 'javelin-workboard-column' => '21df4ff5', 'javelin-workboard-controller' => '55baf5ed', 'javelin-workflow' => '1e911d0f', 'lightbox-attachment-css' => '7acac05d', 'maniphest-batch-editor' => 'b0f0b6d5', 'maniphest-report-css' => '9b9580b7', 'maniphest-task-edit-css' => 'fda62a9b', 'maniphest-task-summary-css' => '11cc5344', 'multirow-row-manager' => 'b5d57730', 'owners-path-editor' => 'aa1733d0', 'owners-path-editor-css' => '2f00933b', 'paste-css' => '1898e534', 'path-typeahead' => 'f7fc67ec', 'people-profile-css' => '2473d929', 'phabricator-action-list-view-css' => 'c5eba19d', 'phabricator-application-launch-view-css' => '95351601', 'phabricator-busy' => '59a7976a', 'phabricator-chatlog-css' => 'd295b020', 'phabricator-content-source-view-css' => '4b8b05d4', - 'phabricator-core-css' => '4f5111ea', + 'phabricator-core-css' => 'd0801452', 'phabricator-countdown-css' => '16c52f5c', 'phabricator-dashboard-css' => 'bc6f2127', 'phabricator-drag-and-drop-file-upload' => '58dea2fa', 'phabricator-draggable-list' => '5a13c79f', 'phabricator-fatal-config-template-css' => '8f18fa41', 'phabricator-feed-css' => 'ecd4ec57', 'phabricator-file-upload' => '680ea2c8', 'phabricator-filetree-view-css' => 'fccf9f82', 'phabricator-flag-css' => '5337623f', 'phabricator-keyboard-shortcut' => '1ae869f2', 'phabricator-keyboard-shortcut-manager' => '4a021c10', 'phabricator-main-menu-view' => 'f03e17be', 'phabricator-nav-view-css' => 'b29426e9', 'phabricator-notification' => 'ccf1cbf8', 'phabricator-notification-css' => '3f6c89c9', 'phabricator-notification-menu-css' => 'b3ab500d', 'phabricator-object-selector-css' => '85ee8ce6', 'phabricator-phtize' => 'd254d646', 'phabricator-prefab' => 'cfd23f37', 'phabricator-remarkup-css' => 'cd912f2c', 'phabricator-search-results-css' => '7dea472c', 'phabricator-shaped-request' => '7cbe244b', 'phabricator-slowvote-css' => 'a94b7230', 'phabricator-source-code-view-css' => 'cbeef983', - 'phabricator-standard-page-view' => 'e5d90676', + 'phabricator-standard-page-view' => '79176f5a', 'phabricator-textareautils' => '320810c8', 'phabricator-title' => 'df5e11d2', 'phabricator-tooltip' => '6323f942', 'phabricator-ui-example-css' => '528b19de', 'phabricator-uiexample-javelin-view' => 'd4a14807', 'phabricator-uiexample-reactor-button' => 'd19198c8', 'phabricator-uiexample-reactor-checkbox' => '519705ea', 'phabricator-uiexample-reactor-focus' => '40a6a403', 'phabricator-uiexample-reactor-input' => '886fd850', 'phabricator-uiexample-reactor-mouseover' => '47c794d8', 'phabricator-uiexample-reactor-radio' => '988040b4', 'phabricator-uiexample-reactor-select' => 'a155550f', 'phabricator-uiexample-reactor-sendclass' => '1def2711', 'phabricator-uiexample-reactor-sendproperties' => 'b1f0ccee', 'phabricator-zindex-css' => '0d4e5558', 'phame-css' => '8efb0729', 'pholio-css' => 'ca89d380', 'pholio-edit-css' => '07676f51', 'pholio-inline-comments-css' => '8e545e49', 'phortune-credit-card-form' => '2290aeef', 'phortune-credit-card-form-css' => '8391eb02', 'phortune-css' => '5b99dae0', 'phrequent-css' => 'ffc185ad', 'phriction-document-css' => '4282e4ad', 'phui-action-panel-css' => '91c7b835', 'phui-badge-view-css' => '3baef8db', - 'phui-basic-nav-view-css' => 'c377093a', + 'phui-basic-nav-view-css' => '7093573b', 'phui-big-info-view-css' => 'bd903741', 'phui-box-css' => '5c8387cf', 'phui-button-css' => '4a5fbe3d', 'phui-calendar-css' => '477acfaa', 'phui-calendar-day-css' => '572b1893', 'phui-calendar-list-css' => 'fcc9fb41', 'phui-calendar-month-css' => '8e10e92c', 'phui-chart-css' => '6bf6f78e', 'phui-cms-css' => 'be43c8a8', 'phui-crumbs-view-css' => '195ac419', 'phui-curtain-view-css' => '947bf1a4', 'phui-document-summary-view-css' => '9ca48bdf', 'phui-document-view-css' => 'c32e8dec', 'phui-document-view-pro-css' => 'ca1fed81', 'phui-feed-story-css' => 'aa49845d', 'phui-font-icon-base-css' => '870a7360', 'phui-fontkit-css' => '9cda225e', 'phui-form-css' => 'aac1d51d', 'phui-form-view-css' => '9e22b190', 'phui-head-thing-view-css' => 'fd311e5f', 'phui-header-view-css' => '06385974', 'phui-hovercard' => '1bd28176', 'phui-hovercard-view-css' => 'de1a2119', 'phui-icon-set-selector-css' => '1ab67aad', 'phui-icon-view-css' => '9bab6f02', 'phui-image-mask-css' => 'a8498f9c', 'phui-info-panel-css' => '27ea50a1', 'phui-info-view-css' => '28efab79', 'phui-inline-comment-view-css' => '5953c28e', 'phui-invisible-character-view-css' => '6993d9f0', 'phui-list-view-css' => '9da2aa00', 'phui-object-box-css' => '6b487c57', 'phui-object-item-list-view-css' => '87278fa0', 'phui-pager-css' => 'bea33d23', 'phui-pinboard-view-css' => '2495140e', 'phui-profile-menu-css' => '8a3fc181', 'phui-property-list-view-css' => '6d8e58ac', 'phui-remarkup-preview-css' => '1a8f2591', 'phui-segment-bar-view-css' => '46342871', 'phui-spacing-css' => '042804d6', 'phui-status-list-view-css' => 'd5263e49', 'phui-tag-view-css' => '6bbd83e2', 'phui-theme-css' => '027ba77e', 'phui-timeline-view-css' => 'bc523970', 'phui-two-column-view-css' => 'fcfbe347', - 'phui-workboard-color-css' => '6da20b15', - 'phui-workboard-view-css' => 'fe70ad9c', + 'phui-workboard-color-css' => 'ac6fe6a7', + 'phui-workboard-view-css' => 'e09eb53a', 'phui-workcard-view-css' => '0c62d7c5', 'phui-workpanel-view-css' => '92197373', 'phuix-action-list-view' => 'b5c256b8', 'phuix-action-view' => '8cf6d262', 'phuix-autocomplete' => '6d86ce8b', 'phuix-dropdown-menu' => '82e270da', 'phuix-form-control-view' => 'e15869a8', 'phuix-icon-view' => 'bff6884b', 'policy-css' => '957ea14c', 'policy-edit-css' => '815c66f7', 'policy-transaction-detail-css' => '82100a43', 'ponder-view-css' => 'fbd45f96', 'project-card-view-css' => '9418c97d', 'project-view-css' => '55d99221', 'releeph-core' => '9b3c5733', 'releeph-preview-branch' => 'b7a6f4a5', 'releeph-request-differential-create-dialog' => '8d8b92cd', 'releeph-request-typeahead-css' => '667a48ae', 'setup-issue-css' => 'f794cfc3', 'sprite-login-css' => '6dbbbd97', 'sprite-tokens-css' => '9cdfd599', 'syntax-default-css' => '9923583c', 'syntax-highlighting-css' => '769d3498', 'tokens-css' => '3d0f239e', 'typeahead-browse-css' => '8904346a', 'unhandled-exception-css' => '4c96257a', ), 'requires' => array( '013ffff9' => array( 'javelin-install', 'javelin-util', 'javelin-request', 'javelin-typeahead-source', ), '01774ab2' => array( 'javelin-dom', 'javelin-util', 'javelin-stratcom', 'javelin-install', 'javelin-aphlict', 'javelin-workflow', 'javelin-router', 'javelin-behavior-device', 'javelin-vector', ), '019f36c4' => array( 'javelin-behavior', 'javelin-dom', 'javelin-util', 'javelin-stratcom', 'javelin-workflow', 'phabricator-draggable-list', ), '01fca1f0' => array( 'javelin-behavior', 'javelin-workflow', 'javelin-json', 'javelin-dom', 'phabricator-keyboard-shortcut', ), '0300eae6' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-workflow', 'javelin-dom', 'phuix-form-control-view', 'phuix-icon-view', 'javelin-behavior-phabricator-gesture', ), '05270951' => array( 'javelin-util', 'javelin-magical-init', ), '054a0f0b' => array( 'javelin-behavior', 'javelin-dom', 'javelin-util', 'phabricator-tooltip', ), '056da01b' => array( 'aphront-typeahead-control-css', 'phui-tag-view-css', ), '065227cc' => array( 'javelin-behavior', 'javelin-dom', 'javelin-stratcom', 'javelin-workflow', ), '06c32383' => array( 'javelin-behavior', 'javelin-typeahead-ondemand-source', 'javelin-typeahead', 'javelin-dom', 'javelin-uri', 'javelin-util', 'javelin-stratcom', 'phabricator-prefab', 'phuix-icon-view', ), '08675c6d' => array( 'javelin-behavior', 'javelin-behavior-device', 'javelin-stratcom', 'javelin-dom', 'javelin-magical-init', 'javelin-vector', 'javelin-request', 'javelin-util', ), '087e919c' => array( 'javelin-install', 'javelin-dom', 'javelin-stratcom', 'javelin-vector', ), '0a0b10e9' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', ), '0a3f3021' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-workflow', 'javelin-dom', 'javelin-router', ), '0f764c35' => array( 'javelin-install', 'javelin-util', ), '116cf19b' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', 'phabricator-phtize', 'phabricator-textareautils', 'javelin-workflow', 'javelin-vector', 'phuix-autocomplete', ), '12884df9' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', ), '13c739ea' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-workflow', 'javelin-dom', 'javelin-uri', 'phabricator-textareautils', ), '1499a8cb' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', 'javelin-history', ), '14a1faae' => array( 'javelin-behavior', 'javelin-dom', 'javelin-util', 'javelin-vector', 'javelin-stratcom', 'javelin-workflow', 'javelin-workboard-controller', ), '1aa4c968' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', 'phuix-dropdown-menu', ), '1ad0a787' => array( 'javelin-install', 'javelin-reactor', 'javelin-util', 'javelin-reactor-node-calmer', ), '1ae869f2' => array( 'javelin-install', 'javelin-util', 'phabricator-keyboard-shortcut-manager', ), '1bd28176' => array( 'javelin-install', 'javelin-dom', 'javelin-vector', 'javelin-request', 'javelin-uri', ), '1def2711' => array( 'javelin-install', 'javelin-dom', 'javelin-reactor-dom', ), '1e911d0f' => array( 'javelin-stratcom', 'javelin-request', 'javelin-dom', 'javelin-vector', 'javelin-install', 'javelin-util', 'javelin-mask', 'javelin-uri', 'javelin-routable', ), '21df4ff5' => array( 'javelin-install', 'javelin-workboard-card', ), '2290aeef' => array( 'javelin-install', 'javelin-dom', 'javelin-json', 'javelin-workflow', 'javelin-util', ), '2926fff2' => array( 'javelin-behavior', 'javelin-dom', ), '29274e2b' => array( 'javelin-install', 'javelin-util', ), '2b8de964' => array( 'javelin-install', 'javelin-util', ), '2c426492' => array( 'javelin-behavior', 'javelin-dom', 'javelin-stratcom', 'phabricator-keyboard-shortcut', ), '2caa8fb8' => array( 'javelin-install', 'javelin-event', ), '2ee659ce' => array( 'javelin-install', ), '320810c8' => array( 'javelin-install', 'javelin-dom', 'javelin-vector', ), '327a00d1' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', 'javelin-workflow', ), '3ab51e2c' => array( 'javelin-behavior', 'javelin-behavior-device', 'javelin-stratcom', 'javelin-vector', 'javelin-dom', 'javelin-magical-init', ), '3cb0b2fc' => array( 'javelin-behavior', 'javelin-dom', 'javelin-stratcom', 'javelin-workflow', 'javelin-util', 'javelin-uri', ), '3f5d6dbf' => array( 'javelin-behavior', 'javelin-dom', 'phortune-credit-card-form', ), '40a6a403' => array( 'javelin-install', 'javelin-dom', 'javelin-reactor-dom', ), 42126667 => array( 'javelin-behavior', 'javelin-dom', 'javelin-request', ), '42fcb747' => array( 'javelin-behavior', 'javelin-behavior-device', 'javelin-stratcom', 'phabricator-tooltip', ), '44959b73' => array( 'javelin-util', 'javelin-uri', 'javelin-install', ), '453c5375' => array( 'javelin-behavior', 'javelin-dom', ), '469c0d9e' => array( 'javelin-behavior', 'javelin-dom', 'javelin-workflow', ), 47830651 => array( 'javelin-behavior', 'javelin-dom', 'javelin-view-renderer', 'javelin-install', ), '47c794d8' => array( 'javelin-install', 'javelin-dom', 'javelin-reactor-dom', ), 48086888 => array( 'javelin-behavior', 'javelin-dom', 'javelin-workflow', ), '484a6e22' => array( 'javelin-behavior', 'javelin-dom', 'phabricator-drag-and-drop-file-upload', 'phabricator-textareautils', ), '491416b3' => array( 'javelin-behavior', 'javelin-uri', 'phabricator-notification', ), '49ae8328' => array( 'javelin-behavior', 'javelin-dom', 'javelin-stratcom', ), '49e20786' => array( 'javelin-behavior', 'javelin-request', 'javelin-stratcom', 'javelin-vector', 'javelin-dom', 'javelin-uri', 'javelin-behavior-device', 'phabricator-title', ), '4a021c10' => array( 'javelin-install', 'javelin-util', 'javelin-stratcom', 'javelin-dom', 'javelin-vector', ), '4b3c4443' => array( 'phuix-icon-view', ), '4b700e9e' => array( 'javelin-behavior', 'javelin-dom', 'javelin-util', 'phabricator-shaped-request', ), '4c193c96' => array( 'javelin-behavior', 'javelin-uri', 'phabricator-notification', ), '4e3e79a6' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', ), '4fbbc3e9' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', 'javelin-util', 'javelin-vector', 'differential-inline-comment-editor', ), '4fdb476d' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', ), '503e17fd' => array( 'javelin-install', 'javelin-typeahead-source', 'javelin-util', ), '519705ea' => array( 'javelin-install', 'javelin-dom', 'javelin-reactor-dom', ), '522431f7' => array( 'javelin-behavior', 'javelin-util', 'javelin-dom', 'javelin-stratcom', 'javelin-vector', 'javelin-typeahead-static-source', ), '5359e785' => array( 'javelin-install', 'javelin-util', 'javelin-websocket', 'javelin-leader', 'javelin-json', ), '54b612ba' => array( 'javelin-color', 'javelin-install', 'javelin-util', ), '54f314a0' => array( 'javelin-install', 'javelin-util', 'javelin-request', 'javelin-typeahead-source', ), '558829c2' => array( 'javelin-stratcom', 'javelin-behavior', 'javelin-vector', 'javelin-dom', ), '55baf5ed' => array( 'javelin-install', 'javelin-dom', 'javelin-util', 'javelin-vector', 'javelin-stratcom', 'javelin-workflow', 'phabricator-drag-and-drop-file-upload', 'javelin-workboard-board', ), '568931f3' => array( 'javelin-behavior', 'javelin-util', 'javelin-dom', 'javelin-stratcom', 'javelin-vector', ), '58dea2fa' => array( 'javelin-install', 'javelin-util', 'javelin-request', 'javelin-dom', 'javelin-uri', 'phabricator-file-upload', ), '59a7976a' => array( 'javelin-install', 'javelin-dom', 'javelin-fx', ), '59b251eb' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-vector', 'javelin-dom', ), '5a13c79f' => array( 'javelin-install', 'javelin-dom', 'javelin-stratcom', 'javelin-util', 'javelin-vector', 'javelin-magical-init', ), '5c54cbf3' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', ), '5e9f347c' => array( 'javelin-behavior', 'multirow-row-manager', 'javelin-dom', 'javelin-util', 'phabricator-prefab', 'javelin-json', ), 60479091 => array( 'phabricator-busy', 'javelin-behavior', ), '60821bc7' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', ), '61cbc29a' => array( 'javelin-magical-init', 'javelin-util', ), '62dfea03' => array( 'javelin-install', 'javelin-util', ), '6323f942' => array( 'javelin-install', 'javelin-util', 'javelin-dom', 'javelin-vector', ), '635de1ec' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-workflow', 'javelin-dom', ), '64a5550f' => array( 'javelin-dom', 'javelin-util', 'javelin-stratcom', 'javelin-install', 'javelin-request', 'javelin-workflow', ), '680ea2c8' => array( 'javelin-install', 'javelin-dom', 'phabricator-notification', ), '6882e80a' => array( 'javelin-dom', ), '69adf288' => array( 'javelin-install', ), '6ad39b6f' => array( 'javelin-install', 'javelin-event', 'javelin-util', 'javelin-magical-init', ), '6b8ef10b' => array( 'javelin-install', ), '6c0e62fa' => array( 'javelin-install', 'javelin-typeahead-source', ), '6c2b09a2' => array( 'javelin-install', 'javelin-util', ), '6d3e1947' => array( 'javelin-behavior', 'javelin-diffusion-locate-file-source', 'javelin-dom', 'javelin-typeahead', 'javelin-uri', ), '6d86ce8b' => array( 'javelin-install', 'javelin-dom', 'phuix-icon-view', 'phabricator-prefab', ), '70baed2f' => array( 'javelin-install', 'javelin-dom', 'javelin-vector', 'javelin-util', ), 71237763 => array( 'javelin-behavior', 'javelin-dom', 'javelin-stratcom', 'javelin-workflow', 'phabricator-draggable-list', ), '7319e029' => array( 'javelin-behavior', 'javelin-dom', ), '73d09eef' => array( 'javelin-behavior', 'javelin-vector', 'javelin-dom', ), '769d3498' => array( 'syntax-default-css', ), '76b9fc3e' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-workflow', 'javelin-dom', 'phabricator-draggable-list', ), '76f4ebed' => array( 'javelin-install', 'javelin-reactor', 'javelin-util', ), '782ab6e7' => array( 'javelin-behavior', 'javelin-dom', 'javelin-util', 'phabricator-prefab', 'multirow-row-manager', 'javelin-json', ), '7927a7d3' => array( 'javelin-behavior', 'javelin-quicksand', ), '7a68dda3' => array( 'owners-path-editor', 'javelin-behavior', ), '7b98d7c5' => array( 'javelin-behavior', 'javelin-dom', 'javelin-stratcom', 'javelin-util', ), '7cbe244b' => array( 'javelin-install', 'javelin-util', 'javelin-request', 'javelin-router', ), '7e41274a' => array( 'javelin-install', ), '7ebaeed3' => array( 'herald-rule-editor', 'javelin-behavior', ), '7ee2b591' => array( 'javelin-behavior', 'javelin-history', ), '805b806a' => array( 'javelin-magical-init', 'javelin-install', 'javelin-util', 'javelin-vector', 'javelin-stratcom', ), '82e270da' => array( 'javelin-install', 'javelin-util', 'javelin-dom', 'javelin-vector', 'javelin-stratcom', ), '834a1173' => array( 'javelin-behavior', 'javelin-scrollbar', ), '8499b6ab' => array( 'javelin-behavior', 'javelin-dom', 'javelin-stratcom', ), '85ee8ce6' => array( 'aphront-dialog-view-css', ), '8604caa8' => array( 'javelin-behavior', 'javelin-dom', 'javelin-stratcom', 'javelin-workflow', 'javelin-util', 'phabricator-notification', 'conpherence-thread-manager', ), '8694b1df' => array( 'javelin-behavior', 'javelin-dom', 'javelin-stratcom', 'phabricator-tooltip', 'changeset-view-manager', ), '88236f00' => array( 'javelin-behavior', 'phabricator-keyboard-shortcut', 'javelin-stratcom', ), '886fd850' => array( 'javelin-install', 'javelin-reactor-dom', 'javelin-view-html', 'javelin-view-interpreter', 'javelin-view-renderer', ), '887ad43f' => array( 'javelin-behavior', 'javelin-request', 'javelin-stratcom', 'javelin-dom', ), '8a41885b' => array( 'javelin-install', 'javelin-dom', ), '8bdb2835' => array( 'phui-fontkit-css', ), '8ce821c5' => array( 'phabricator-notification', 'javelin-stratcom', 'javelin-behavior', ), '8cf6d262' => array( 'javelin-install', 'javelin-dom', 'javelin-util', ), '8d3bc1b2' => array( 'javelin-dom', 'javelin-util', 'javelin-stratcom', 'javelin-install', ), '8ff5e24c' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', ), '901935ef' => array( 'javelin-behavior', 'javelin-dom', 'javelin-request', ), 92197373 => array( 'phui-workcard-view-css', ), '92b9ec77' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', ), '93d0c9e3' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-workflow', 'javelin-dom', ), '9414ff18' => array( 'javelin-behavior', 'javelin-resource', 'javelin-stratcom', 'javelin-workflow', 'javelin-util', ), '949c0fe5' => array( 'javelin-install', ), '94b750d2' => array( 'javelin-install', 'javelin-stratcom', 'javelin-util', 'javelin-behavior', 'javelin-json', 'javelin-dom', 'javelin-resource', 'javelin-routable', ), '94c65b72' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', 'phabricator-busy', ), '988040b4' => array( 'javelin-install', 'javelin-dom', 'javelin-reactor-dom', ), '9a6b9324' => array( 'javelin-behavior', 'javelin-dom', 'javelin-util', 'javelin-stratcom', 'javelin-workflow', 'phuix-dropdown-menu', 'phuix-action-list-view', 'phuix-action-view', 'phabricator-phtize', 'changeset-view-manager', ), '9bdbbab0' => array( 'javelin-behavior', 'javelin-dom', 'javelin-util', 'javelin-workflow', 'javelin-stratcom', ), '9eb55204' => array( 'javelin-behavior', 'javelin-dom', 'javelin-util', 'javelin-stratcom', 'javelin-workflow', 'javelin-behavior-device', 'javelin-history', 'javelin-vector', 'javelin-scrollbar', 'phabricator-title', 'phabricator-shaped-request', 'conpherence-thread-manager', ), '9ef7d354' => array( 'phui-inline-comment-view-css', ), '9f36c42d' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', 'javelin-vector', ), 'a0b57eb8' => array( 'javelin-behavior', 'javelin-dom', 'javelin-stratcom', 'javelin-workflow', 'javelin-util', 'phabricator-keyboard-shortcut', ), 'a0e564c2' => array( 'javelin-behavior', 'javelin-dom', 'javelin-stratcom', 'javelin-behavior-device', 'javelin-scrollbar', 'javelin-quicksand', 'phabricator-keyboard-shortcut', 'conpherence-thread-manager', ), 'a155550f' => array( 'javelin-install', 'javelin-dom', 'javelin-reactor-dom', ), 'a2828756' => array( 'javelin-dom', 'javelin-util', 'javelin-stratcom', 'javelin-install', 'javelin-workflow', 'javelin-router', 'javelin-behavior-device', 'javelin-vector', ), 'a464fe03' => array( 'javelin-behavior', 'javelin-uri', 'phabricator-notification', ), 'a6f7a73b' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', ), 'a80d0378' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', ), 'a8d8459d' => array( 'javelin-behavior', 'javelin-dom', 'javelin-stratcom', ), 'a8da01f0' => array( 'javelin-behavior', 'javelin-uri', 'phabricator-keyboard-shortcut', ), 'a9f88de2' => array( 'javelin-behavior', 'javelin-dom', 'javelin-stratcom', 'javelin-workflow', 'javelin-fx', 'javelin-util', ), 'aa1733d0' => array( 'multirow-row-manager', 'javelin-install', 'path-typeahead', 'javelin-dom', 'javelin-util', 'phabricator-prefab', ), 'ab2f381b' => array( 'javelin-request', 'javelin-behavior', 'javelin-dom', 'javelin-router', 'javelin-util', 'phabricator-busy', ), 'b003d4fb' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', 'phuix-dropdown-menu', ), 'b064af76' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', 'javelin-request', 'javelin-util', 'phabricator-shaped-request', ), 'b1f0ccee' => array( 'javelin-install', 'javelin-dom', 'javelin-reactor-dom', ), 'b23b49e6' => array( 'javelin-behavior', 'javelin-dom', 'javelin-util', 'javelin-request', 'phabricator-shaped-request', ), 'b25d5444' => array( 'javelin-install', 'javelin-util', 'javelin-dom', 'javelin-typeahead-normalizer', ), 'b2b4fbaf' => array( 'javelin-behavior', 'javelin-dom', 'javelin-uri', 'javelin-request', ), 'b3a4b884' => array( 'javelin-behavior', 'phabricator-prefab', ), 'b3e7d692' => array( 'javelin-install', ), 'b42eddc7' => array( 'javelin-install', 'javelin-dom', 'javelin-typeahead-preloaded-source', 'javelin-util', ), 'b59e1e96' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-workflow', 'javelin-dom', 'phabricator-draggable-list', ), 'b5c256b8' => array( 'javelin-install', 'javelin-dom', ), 'b5d57730' => array( 'javelin-install', 'javelin-stratcom', 'javelin-dom', 'javelin-util', ), 'b6993408' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', 'javelin-json', 'phabricator-draggable-list', ), 'ba158207' => array( 'javelin-behavior', 'javelin-uri', 'phabricator-notification', ), 'bb1dd507' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', 'javelin-vector', 'javelin-install', ), 'bcaccd64' => array( 'javelin-behavior', 'javelin-behavior-device', 'javelin-stratcom', 'javelin-vector', 'phui-hovercard', ), 'bdaf4d04' => array( 'javelin-behavior', 'javelin-dom', 'javelin-util', 'javelin-request', ), 'bee502c8' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', 'javelin-workflow', 'javelin-quicksand', 'phabricator-phtize', 'phabricator-drag-and-drop-file-upload', 'phabricator-draggable-list', ), 'bf5374ef' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', ), 'bff6884b' => array( 'javelin-install', 'javelin-dom', ), 'c587b80f' => array( 'javelin-install', ), 'c7ccd872' => array( 'phui-fontkit-css', ), 'c8e57404' => array( 'javelin-behavior', 'javelin-dom', 'javelin-uri', 'javelin-mask', 'phabricator-drag-and-drop-file-upload', ), 'c90a04fc' => array( 'javelin-dom', 'javelin-dynval', 'javelin-reactor', 'javelin-reactornode', 'javelin-install', 'javelin-util', ), 'c989ade3' => array( 'javelin-install', 'javelin-util', 'javelin-stratcom', ), 'ca3f91eb' => array( 'javelin-behavior', 'javelin-dom', 'javelin-stratcom', 'phabricator-phtize', ), 'ccf1cbf8' => array( 'javelin-install', 'javelin-dom', 'javelin-stratcom', 'javelin-util', 'phabricator-notification-css', ), 'cf86d16a' => array( 'javelin-behavior', 'javelin-dom', 'javelin-workflow', 'phabricator-drag-and-drop-file-upload', ), 'cfd23f37' => array( 'javelin-install', 'javelin-util', 'javelin-dom', 'javelin-typeahead', 'javelin-tokenizer', 'javelin-typeahead-preloaded-source', 'javelin-typeahead-ondemand-source', 'javelin-dom', 'javelin-stratcom', 'javelin-util', ), 'd0c516d5' => array( 'javelin-behavior', 'javelin-dom', 'javelin-util', 'phuix-dropdown-menu', 'phuix-action-list-view', 'phuix-action-view', 'javelin-workflow', 'phuix-icon-view', ), 'd19198c8' => array( 'javelin-install', 'javelin-dom', 'javelin-util', 'javelin-dynval', 'javelin-reactor-dom', ), 'd254d646' => array( 'javelin-util', ), 'd4505101' => array( 'javelin-stratcom', 'javelin-install', 'javelin-uri', 'javelin-util', ), 'd4a14807' => array( 'javelin-install', 'javelin-dom', 'javelin-view', ), 'd4eecc63' => array( 'javelin-behavior', 'javelin-dom', 'javelin-stratcom', ), 'd6a7e717' => array( 'multirow-row-manager', 'javelin-install', 'javelin-util', 'javelin-dom', 'javelin-stratcom', 'javelin-json', 'phabricator-prefab', ), 'd7a74243' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-workflow', 'javelin-dom', 'phabricator-draggable-list', ), 'd835b03a' => array( 'javelin-behavior', 'javelin-dom', 'javelin-util', 'phabricator-shaped-request', ), 'de2e896f' => array( 'javelin-behavior', 'javelin-dom', 'javelin-typeahead', 'javelin-typeahead-ondemand-source', 'javelin-dom', ), 'df5e11d2' => array( 'javelin-install', ), 'e0ec7f2f' => array( 'javelin-behavior', 'javelin-dom', 'javelin-request', 'javelin-util', ), 'e10f8e18' => array( 'javelin-behavior', 'javelin-dom', 'phabricator-prefab', ), 'e15869a8' => array( 'javelin-install', 'javelin-dom', ), 'e1d25dfb' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-workflow', 'javelin-dom', 'phabricator-draggable-list', ), 'e1ff79b1' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', ), 'e292eaf4' => array( 'javelin-install', ), 'e2e0a072' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-workflow', 'javelin-dom', 'phabricator-draggable-list', ), 'e379b58e' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-vector', 'javelin-dom', 'javelin-uri', ), 'e4232876' => array( 'javelin-behavior', 'javelin-dom', 'javelin-vector', 'phui-chart-css', ), 'e4cc26b3' => array( 'javelin-behavior', 'javelin-dom', ), 'e5339c43' => array( 'javelin-behavior', 'javelin-dom', 'javelin-stratcom', 'javelin-uri', ), 'e5822781' => array( 'javelin-behavior', 'javelin-dom', 'javelin-json', 'javelin-workflow', 'javelin-magical-init', ), 'e6e25838' => array( 'javelin-install', ), 'e9581f08' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-workflow', 'javelin-dom', 'phabricator-draggable-list', ), 'ea681761' => array( 'javelin-behavior', 'javelin-aphlict', 'phabricator-phtize', 'javelin-dom', ), 'edd1ba66' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', 'javelin-uri', 'phabricator-notification', ), 'edf8a145' => array( 'javelin-behavior', 'javelin-uri', ), 'efe49472' => array( 'javelin-install', 'javelin-util', ), 'f01586dc' => array( 'javelin-behavior', 'javelin-dom', 'javelin-util', 'javelin-workflow', 'javelin-json', ), 'f03e17be' => array( 'phui-theme-css', ), 'f2e58483' => array( 'javelin-behavior', 'javelin-dom', 'javelin-util', 'javelin-workflow', 'javelin-stratcom', 'conpherence-thread-manager', ), 'f411b6ae' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-util', 'javelin-dom', 'javelin-request', 'phabricator-keyboard-shortcut', ), 'f6555212' => array( 'javelin-install', 'javelin-reactornode', 'javelin-util', 'javelin-reactor', ), 'f7fc67ec' => array( 'javelin-install', 'javelin-typeahead', 'javelin-dom', 'javelin-request', 'javelin-typeahead-ondemand-source', 'javelin-util', ), 'f829edb3' => array( 'javelin-view', 'javelin-install', 'javelin-dom', ), 'f8ba29d7' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', 'javelin-mask', 'javelin-util', 'phabricator-busy', ), 'fa0f4fc2' => array( 'javelin-behavior', 'javelin-dom', 'javelin-vector', 'javelin-magical-init', ), 'fb20ac8d' => array( 'javelin-behavior', 'javelin-aphlict', 'javelin-stratcom', 'javelin-request', 'javelin-uri', 'javelin-dom', 'javelin-json', 'javelin-router', 'javelin-util', 'javelin-leader', 'javelin-sound', 'phabricator-notification', ), 'fbe497e7' => array( 'javelin-behavior', 'javelin-util', 'javelin-stratcom', 'javelin-dom', 'javelin-vector', 'javelin-magical-init', 'javelin-request', 'javelin-history', 'javelin-workflow', 'javelin-mask', 'javelin-behavior-device', 'phabricator-keyboard-shortcut', ), 'fc91ab6c' => array( 'javelin-behavior', 'javelin-dom', 'phortune-credit-card-form', ), 'fe287620' => array( 'javelin-install', 'javelin-dom', 'javelin-view-visitor', 'javelin-util', ), 'fe7cb52a' => array( 'javelin-install', 'javelin-dom', 'javelin-util', 'javelin-stratcom', 'javelin-workflow', 'phabricator-draggable-list', 'javelin-workboard-column', ), 'fea0eb47' => array( 'javelin-install', ), ), 'packages' => array( 'conpherence.pkg.css' => array( 'conpherence-durable-column-view', 'conpherence-menu-css', 'conpherence-message-pane-css', 'conpherence-notification-css', 'conpherence-transaction-css', 'conpherence-update-css', 'conpherence-participant-pane-css', 'conpherence-header-pane-css', ), 'conpherence.pkg.js' => array( 'javelin-behavior-conpherence-drag-and-drop-photo', 'javelin-behavior-conpherence-menu', 'javelin-behavior-conpherence-participant-pane', 'javelin-behavior-conpherence-pontificate', 'javelin-behavior-toggle-widget', ), 'core.pkg.css' => array( 'phabricator-core-css', 'phabricator-zindex-css', 'phui-button-css', 'phui-theme-css', 'phabricator-standard-page-view', 'aphront-dialog-view-css', 'phui-form-view-css', 'aphront-panel-view-css', 'aphront-table-view-css', 'aphront-tokenizer-control-css', 'aphront-typeahead-control-css', 'aphront-list-filter-view-css', 'application-search-view-css', 'phabricator-remarkup-css', 'syntax-highlighting-css', 'syntax-default-css', 'phui-pager-css', 'aphront-tooltip-css', 'phabricator-flag-css', 'phui-info-view-css', 'phabricator-main-menu-view', 'phabricator-notification-css', 'phabricator-notification-menu-css', 'lightbox-attachment-css', 'phui-header-view-css', 'phabricator-nav-view-css', 'phui-basic-nav-view-css', 'phui-crumbs-view-css', 'phui-object-item-list-view-css', 'global-drag-and-drop-css', 'phui-spacing-css', 'phui-form-css', 'phui-icon-view-css', 'phui-profile-menu-css', 'phabricator-application-launch-view-css', 'phabricator-action-list-view-css', 'phui-property-list-view-css', 'phui-tag-view-css', 'phui-list-view-css', 'font-fontawesome', 'font-lato', 'font-aleo', 'phui-font-icon-base-css', 'phui-fontkit-css', 'phui-box-css', 'phui-object-box-css', 'phui-timeline-view-css', 'phui-two-column-view-css', 'phui-curtain-view-css', 'sprite-login-css', 'sprite-tokens-css', 'tokens-css', 'auth-css', 'phui-status-list-view-css', 'phui-feed-story-css', 'phabricator-feed-css', 'phabricator-dashboard-css', 'aphront-multi-column-view-css', ), 'core.pkg.js' => array( 'javelin-util', 'javelin-install', 'javelin-event', 'javelin-stratcom', 'javelin-behavior', 'javelin-resource', 'javelin-request', 'javelin-vector', 'javelin-dom', 'javelin-json', 'javelin-uri', 'javelin-workflow', 'javelin-mask', 'javelin-typeahead', 'javelin-typeahead-normalizer', 'javelin-typeahead-source', 'javelin-typeahead-preloaded-source', 'javelin-typeahead-ondemand-source', 'javelin-tokenizer', 'javelin-history', 'javelin-router', 'javelin-routable', 'javelin-behavior-aphront-basic-tokenizer', 'javelin-behavior-workflow', 'javelin-behavior-aphront-form-disable-on-submit', 'phabricator-keyboard-shortcut-manager', 'phabricator-keyboard-shortcut', 'javelin-behavior-phabricator-keyboard-shortcuts', 'javelin-behavior-refresh-csrf', 'javelin-behavior-phabricator-watch-anchor', 'javelin-behavior-phabricator-autofocus', 'phuix-dropdown-menu', 'phuix-action-list-view', 'phuix-action-view', 'phuix-icon-view', 'phabricator-phtize', 'javelin-behavior-phabricator-oncopy', 'phabricator-tooltip', 'javelin-behavior-phabricator-tooltips', 'phabricator-prefab', 'javelin-behavior-device', 'javelin-behavior-toggle-class', 'javelin-behavior-lightbox-attachments', 'phabricator-busy', 'javelin-aphlict', 'phabricator-notification', 'javelin-behavior-aphlict-listen', 'javelin-behavior-phabricator-search-typeahead', 'javelin-behavior-aphlict-dropdown', 'javelin-behavior-history-install', 'javelin-behavior-phabricator-gesture', 'javelin-behavior-phabricator-active-nav', 'javelin-behavior-phabricator-nav', 'javelin-behavior-phabricator-remarkup-assist', 'phabricator-textareautils', 'phabricator-file-upload', 'javelin-behavior-global-drag-and-drop', 'javelin-behavior-phabricator-reveal-content', 'phui-hovercard', 'javelin-behavior-phui-hovercards', 'javelin-color', 'javelin-fx', 'phabricator-draggable-list', 'javelin-behavior-phabricator-transaction-list', 'javelin-behavior-phabricator-show-older-transactions', 'javelin-behavior-phui-dropdown-menu', 'javelin-behavior-doorkeeper-tag', 'phabricator-title', 'javelin-leader', 'javelin-websocket', 'javelin-behavior-dashboard-async-panel', 'javelin-behavior-dashboard-tab-panel', 'javelin-quicksand', 'javelin-behavior-quicksand-blacklist', 'javelin-behavior-high-security-warning', 'javelin-behavior-read-only-warning', 'javelin-scrollbar', 'javelin-behavior-scrollbar', 'javelin-behavior-durable-column', 'conpherence-thread-manager', 'javelin-behavior-detect-timezone', 'javelin-behavior-setup-check-https', ), 'darkconsole.pkg.js' => array( 'javelin-behavior-dark-console', 'javelin-behavior-error-log', ), 'differential.pkg.css' => array( 'differential-core-view-css', 'differential-changeset-view-css', 'differential-revision-history-css', 'differential-revision-list-css', 'differential-table-of-contents-css', 'differential-revision-comment-css', 'differential-revision-add-comment-css', 'phabricator-object-selector-css', 'phabricator-content-source-view-css', 'inline-comment-summary-css', 'phui-inline-comment-view-css', 'phabricator-filetree-view-css', ), 'differential.pkg.js' => array( 'phabricator-drag-and-drop-file-upload', 'phabricator-shaped-request', 'javelin-behavior-differential-feedback-preview', 'javelin-behavior-differential-edit-inline-comments', 'javelin-behavior-differential-populate', 'javelin-behavior-differential-diff-radios', 'javelin-behavior-differential-comment-jump', 'javelin-behavior-differential-add-reviewers-and-ccs', 'javelin-behavior-differential-keyboard-navigation', 'javelin-behavior-aphront-drag-and-drop-textarea', 'javelin-behavior-phabricator-object-selector', 'javelin-behavior-repository-crossreference', 'javelin-behavior-load-blame', 'differential-inline-comment-editor', 'javelin-behavior-differential-dropdown-menus', 'javelin-behavior-differential-toggle-files', 'javelin-behavior-differential-user-select', 'javelin-behavior-aphront-more', 'changeset-view-manager', ), 'diffusion.pkg.css' => array( 'diffusion-icons-css', ), 'diffusion.pkg.js' => array( 'javelin-behavior-diffusion-pull-lastmodified', 'javelin-behavior-diffusion-commit-graph', 'javelin-behavior-audit-preview', ), 'maniphest.pkg.css' => array( 'maniphest-task-summary-css', ), 'maniphest.pkg.js' => array( 'javelin-behavior-maniphest-batch-selector', 'javelin-behavior-maniphest-subpriority-editor', 'javelin-behavior-maniphest-list-editor', ), ), ); diff --git a/src/applications/config/controller/PhabricatorConfigAllController.php b/src/applications/config/controller/PhabricatorConfigAllController.php index 3881c9859f..421e0078cf 100644 --- a/src/applications/config/controller/PhabricatorConfigAllController.php +++ b/src/applications/config/controller/PhabricatorConfigAllController.php @@ -1,78 +1,78 @@ getViewer(); $db_values = id(new PhabricatorConfigEntry()) ->loadAllWhere('namespace = %s', 'default'); $db_values = mpull($db_values, null, 'getConfigKey'); $rows = array(); $options = PhabricatorApplicationConfigOptions::loadAllOptions(); ksort($options); foreach ($options as $option) { $key = $option->getKey(); if ($option->getHidden()) { $value = phutil_tag('em', array(), pht('Hidden')); } else { $value = PhabricatorEnv::getEnvConfig($key); $value = PhabricatorConfigJSON::prettyPrintJSON($value); } $db_value = idx($db_values, $key); $rows[] = array( phutil_tag( 'a', array( 'href' => $this->getApplicationURI('edit/'.$key.'/'), ), $key), $value, $db_value && !$db_value->getIsDeleted() ? pht('Customized') : '', ); } $table = id(new AphrontTableView($rows)) ->setColumnClasses( array( '', 'wide', )) ->setHeaders( array( pht('Key'), pht('Value'), pht('Customized'), )); $title = pht('Current Settings'); $crumbs = $this ->buildApplicationCrumbs() ->addTextCrumb($title) ->setBorder(true); $header = id(new PHUIHeaderView()) ->setHeader($title) ->setProfileHeader(true); $nav = $this->buildSideNavView(); $nav->selectFilter('all/'); $content = id(new PhabricatorConfigPageView()) ->setHeader($header) ->setContent($table); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) ->setNavigation($nav) ->appendChild($content) - ->addFrameClass('white-background'); + ->addClass('white-background'); } } diff --git a/src/applications/config/controller/PhabricatorConfigApplicationController.php b/src/applications/config/controller/PhabricatorConfigApplicationController.php index 7b36cb9c8b..10f639adc7 100644 --- a/src/applications/config/controller/PhabricatorConfigApplicationController.php +++ b/src/applications/config/controller/PhabricatorConfigApplicationController.php @@ -1,61 +1,61 @@ getViewer(); $nav = $this->buildSideNavView(); $nav->selectFilter('application/'); $groups = PhabricatorApplicationConfigOptions::loadAll(); $apps_list = $this->buildConfigOptionsList($groups, 'apps'); $title = pht('Application Settings'); $header = id(new PHUIHeaderView()) ->setHeader($title) ->setProfileHeader(true); $crumbs = $this ->buildApplicationCrumbs() ->addTextCrumb(pht('Applications')) ->setBorder(true); $content = id(new PhabricatorConfigPageView()) ->setHeader($header) ->setContent($apps_list); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) ->setNavigation($nav) ->appendChild($content) - ->addFrameClass('white-background'); + ->addClass('white-background'); } private function buildConfigOptionsList(array $groups, $type) { assert_instances_of($groups, 'PhabricatorApplicationConfigOptions'); $list = new PHUIObjectItemListView(); $list->setBig(true); $groups = msort($groups, 'getName'); foreach ($groups as $group) { if ($group->getGroup() == $type) { $icon = id(new PHUIIconView()) ->setIcon($group->getIcon()) ->setBackground('bg-violet'); $item = id(new PHUIObjectItemView()) ->setHeader($group->getName()) ->setHref('/config/group/'.$group->getKey().'/') ->addAttribute($group->getDescription()) ->setImageIcon($icon); $list->addItem($item); } } return $list; } } diff --git a/src/applications/config/controller/PhabricatorConfigCacheController.php b/src/applications/config/controller/PhabricatorConfigCacheController.php index 53c2b87381..91b0be27cf 100644 --- a/src/applications/config/controller/PhabricatorConfigCacheController.php +++ b/src/applications/config/controller/PhabricatorConfigCacheController.php @@ -1,193 +1,193 @@ getViewer(); $nav = $this->buildSideNavView(); $nav->selectFilter('cache/'); $title = pht('Cache Status'); $header = id(new PHUIHeaderView()) ->setHeader($title) ->setProfileHeader(true); $crumbs = $this ->buildApplicationCrumbs() ->addTextCrumb(pht('Cache Status')) ->setBorder(true); $code_box = $this->renderCodeBox(); $data_box = $this->renderDataBox(); $page = array( $code_box, $data_box, ); $content = id(new PhabricatorConfigPageView()) ->setHeader($header) ->setContent($page); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) ->setNavigation($nav) ->appendChild($content) - ->addFrameClass('white-background'); + ->addClass('white-background'); } private function renderCodeBox() { $cache = PhabricatorOpcodeCacheSpec::getActiveCacheSpec(); $properties = id(new PHUIPropertyListView()); $this->renderCommonProperties($properties, $cache); $purge_button = id(new PHUIButtonView()) ->setText(pht('Purge Caches')) ->setHref('/config/cache/purge/') ->setTag('a') ->setWorkflow(true) ->setIcon('fa-exclamation-triangle'); $header = id(new PHUIHeaderView()) ->setHeader(pht('Opcode Cache')) ->addActionLink($purge_button); return id(new PHUIObjectBoxView()) ->setHeader($header) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->addPropertyList($properties); } private function renderDataBox() { $cache = PhabricatorDataCacheSpec::getActiveCacheSpec(); $properties = id(new PHUIPropertyListView()); $this->renderCommonProperties($properties, $cache); $table = null; if ($cache->getName() !== null) { $total_memory = $cache->getTotalMemory(); $summary = $cache->getCacheSummary(); $summary = isort($summary, 'total'); $summary = array_reverse($summary, true); $rows = array(); foreach ($summary as $key => $info) { $rows[] = array( $key, pht('%s', new PhutilNumber($info['count'])), phutil_format_bytes($info['max']), phutil_format_bytes($info['total']), sprintf('%.1f%%', (100 * ($info['total'] / $total_memory))), ); } $table = id(new AphrontTableView($rows)) ->setHeaders( array( pht('Pattern'), pht('Count'), pht('Largest'), pht('Total'), pht('Usage'), )) ->setColumnClasses( array( 'wide', 'n', 'n', 'n', 'n', )); } return id(new PHUIObjectBoxView()) ->setHeaderText(pht('Data Cache')) ->addPropertyList($properties) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->setTable($table); } private function renderCommonProperties( PHUIPropertyListView $properties, PhabricatorCacheSpec $cache) { if ($cache->getName() !== null) { $name = $this->renderYes($cache->getName()); } else { $name = $this->renderNo(pht('None')); } $properties->addProperty(pht('Cache'), $name); if ($cache->getIsEnabled()) { $enabled = $this->renderYes(pht('Enabled')); } else { $enabled = $this->renderNo(pht('Not Enabled')); } $properties->addProperty(pht('Enabled'), $enabled); $version = $cache->getVersion(); if ($version) { $properties->addProperty(pht('Version'), $this->renderInfo($version)); } if ($cache->getName() === null) { return; } $mem_total = $cache->getTotalMemory(); $mem_used = $cache->getUsedMemory(); if ($mem_total) { $percent = 100 * ($mem_used / $mem_total); $properties->addProperty( pht('Memory Usage'), pht( '%s of %s', phutil_tag('strong', array(), sprintf('%.1f%%', $percent)), phutil_format_bytes($mem_total))); } $entry_count = $cache->getEntryCount(); if ($entry_count !== null) { $properties->addProperty( pht('Cache Entries'), pht('%s', new PhutilNumber($entry_count))); } } private function renderYes($info) { return array( id(new PHUIIconView())->setIcon('fa-check', 'green'), ' ', $info, ); } private function renderNo($info) { return array( id(new PHUIIconView())->setIcon('fa-times-circle', 'red'), ' ', $info, ); } private function renderInfo($info) { return array( id(new PHUIIconView())->setIcon('fa-info-circle', 'grey'), ' ', $info, ); } } diff --git a/src/applications/config/controller/PhabricatorConfigClusterDatabasesController.php b/src/applications/config/controller/PhabricatorConfigClusterDatabasesController.php index 3f2dc62285..44659ab24e 100644 --- a/src/applications/config/controller/PhabricatorConfigClusterDatabasesController.php +++ b/src/applications/config/controller/PhabricatorConfigClusterDatabasesController.php @@ -1,214 +1,214 @@ buildSideNavView(); $nav->selectFilter('cluster/databases/'); $title = pht('Cluster Database Status'); $doc_href = PhabricatorEnv::getDoclink('Cluster: Databases'); $header = id(new PHUIHeaderView()) ->setHeader($title) ->setProfileHeader(true) ->addActionLink( id(new PHUIButtonView()) ->setIcon('fa-book') ->setHref($doc_href) ->setTag('a') ->setText(pht('Documentation'))); $crumbs = $this ->buildApplicationCrumbs($nav) ->addTextCrumb($title) ->setBorder(true); $database_status = $this->buildClusterDatabaseStatus(); $content = id(new PhabricatorConfigPageView()) ->setHeader($header) ->setContent($database_status); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) ->setNavigation($nav) ->appendChild($content) - ->addFrameClass('white-background'); + ->addClass('white-background'); } private function buildClusterDatabaseStatus() { $viewer = $this->getViewer(); $databases = PhabricatorDatabaseRef::queryAll(); $connection_map = PhabricatorDatabaseRef::getConnectionStatusMap(); $replica_map = PhabricatorDatabaseRef::getReplicaStatusMap(); Javelin::initBehavior('phabricator-tooltips'); $rows = array(); foreach ($databases as $database) { $messages = array(); if ($database->getIsMaster()) { $role_icon = id(new PHUIIconView()) ->setIcon('fa-database sky') ->addSigil('has-tooltip') ->setMetadata( array( 'tip' => pht('Master'), )); } else { $role_icon = id(new PHUIIconView()) ->setIcon('fa-download') ->addSigil('has-tooltip') ->setMetadata( array( 'tip' => pht('Replica'), )); } if ($database->getDisabled()) { $conn_icon = 'fa-times'; $conn_color = 'grey'; $conn_label = pht('Disabled'); } else { $status = $database->getConnectionStatus(); $info = idx($connection_map, $status, array()); $conn_icon = idx($info, 'icon'); $conn_color = idx($info, 'color'); $conn_label = idx($info, 'label'); if ($status === PhabricatorDatabaseRef::STATUS_OKAY) { $latency = $database->getConnectionLatency(); $latency = (int)(1000000 * $latency); $conn_label = pht('%s us', new PhutilNumber($latency)); } } $connection = array( id(new PHUIIconView())->setIcon("{$conn_icon} {$conn_color}"), ' ', $conn_label, ); if ($database->getDisabled()) { $replica_icon = 'fa-times'; $replica_color = 'grey'; $replica_label = pht('Disabled'); } else { $status = $database->getReplicaStatus(); $info = idx($replica_map, $status, array()); $replica_icon = idx($info, 'icon'); $replica_color = idx($info, 'color'); $replica_label = idx($info, 'label'); if ($database->getIsMaster()) { if ($status === PhabricatorDatabaseRef::REPLICATION_OKAY) { $replica_icon = 'fa-database'; } } else { switch ($status) { case PhabricatorDatabaseRef::REPLICATION_OKAY: case PhabricatorDatabaseRef::REPLICATION_SLOW: $delay = $database->getReplicaDelay(); if ($delay) { $replica_label = pht('%ss Behind', new PhutilNumber($delay)); } else { $replica_label = pht('Up to Date'); } break; } } } $replication = array( id(new PHUIIconView())->setIcon("{$replica_icon} {$replica_color}"), ' ', $replica_label, ); $health = $database->getHealthRecord(); $health_up = $health->getUpEventCount(); $health_down = $health->getDownEventCount(); if ($health->getIsHealthy()) { $health_icon = id(new PHUIIconView()) ->setIcon('fa-plus green'); } else { $health_icon = id(new PHUIIconView()) ->setIcon('fa-times red'); $messages[] = pht( 'UNHEALTHY: This database has failed recent health checks. Traffic '. 'will not be sent to it until it recovers.'); } $health_count = pht( '%s / %s', new PhutilNumber($health_up), new PhutilNumber($health_up + $health_down)); $health_status = array( $health_icon, ' ', $health_count, ); $conn_message = $database->getConnectionMessage(); if ($conn_message) { $messages[] = $conn_message; } $replica_message = $database->getReplicaMessage(); if ($replica_message) { $messages[] = $replica_message; } $messages = phutil_implode_html(phutil_tag('br'), $messages); $rows[] = array( $role_icon, $database->getHost(), $database->getPort(), $database->getUser(), $connection, $replication, $health_status, $messages, ); } $table = id(new AphrontTableView($rows)) ->setNoDataString( pht('Phabricator is not configured in cluster mode.')) ->setHeaders( array( null, pht('Host'), pht('Port'), pht('User'), pht('Connection'), pht('Replication'), pht('Health'), pht('Messages'), )) ->setColumnClasses( array( null, null, null, null, null, null, null, 'wide', )); return $table; } } diff --git a/src/applications/config/controller/PhabricatorConfigClusterNotificationsController.php b/src/applications/config/controller/PhabricatorConfigClusterNotificationsController.php index de38632ce7..d0d26d0613 100644 --- a/src/applications/config/controller/PhabricatorConfigClusterNotificationsController.php +++ b/src/applications/config/controller/PhabricatorConfigClusterNotificationsController.php @@ -1,164 +1,164 @@ buildSideNavView(); $nav->selectFilter('cluster/notifications/'); $title = pht('Cluster Notifications'); $doc_href = PhabricatorEnv::getDoclink('Cluster: Notifications'); $header = id(new PHUIHeaderView()) ->setHeader($title) ->setProfileHeader(true) ->addActionLink( id(new PHUIButtonView()) ->setIcon('fa-book') ->setHref($doc_href) ->setTag('a') ->setText(pht('Documentation'))); $crumbs = $this ->buildApplicationCrumbs($nav) ->addTextCrumb($title) ->setBorder(true); $notification_status = $this->buildClusterNotificationStatus(); $content = id(new PhabricatorConfigPageView()) ->setHeader($header) ->setContent($notification_status); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) ->setNavigation($nav) ->appendChild($content) - ->addFrameClass('white-background'); + ->addClass('white-background'); } private function buildClusterNotificationStatus() { $viewer = $this->getViewer(); $servers = PhabricatorNotificationServerRef::newRefs(); Javelin::initBehavior('phabricator-tooltips'); $rows = array(); foreach ($servers as $server) { if ($server->isAdminServer()) { $type_icon = 'fa-database sky'; $type_tip = pht('Admin Server'); } else { $type_icon = 'fa-bell sky'; $type_tip = pht('Client Server'); } $type_icon = id(new PHUIIconView()) ->setIcon($type_icon) ->addSigil('has-tooltip') ->setMetadata( array( 'tip' => $type_tip, )); $messages = array(); $details = array(); if ($server->isAdminServer()) { try { $details = $server->loadServerStatus(); $status_icon = 'fa-exchange green'; $status_label = pht('Version %s', idx($details, 'version')); } catch (Exception $ex) { $status_icon = 'fa-times red'; $status_label = pht('Connection Error'); $messages[] = $ex->getMessage(); } } else { try { $server->testClient(); $status_icon = 'fa-exchange green'; $status_label = pht('Connected'); } catch (Exception $ex) { $status_icon = 'fa-times red'; $status_label = pht('Connection Error'); $messages[] = $ex->getMessage(); } } if ($details) { $uptime = idx($details, 'uptime'); $uptime = $uptime / 1000; $uptime = phutil_format_relative_time_detailed($uptime); $clients = pht( '%s Active / %s Total', new PhutilNumber(idx($details, 'clients.active')), new PhutilNumber(idx($details, 'clients.total'))); $stats = pht( '%s In / %s Out', new PhutilNumber(idx($details, 'messages.in')), new PhutilNumber(idx($details, 'messages.out'))); } else { $uptime = null; $clients = null; $stats = null; } $status_view = array( id(new PHUIIconView())->setIcon($status_icon), ' ', $status_label, ); $messages = phutil_implode_html(phutil_tag('br'), $messages); $rows[] = array( $type_icon, $server->getProtocol(), $server->getHost(), $server->getPort(), $status_view, $uptime, $clients, $stats, $messages, ); } $table = id(new AphrontTableView($rows)) ->setNoDataString( pht('No notification servers are configured.')) ->setHeaders( array( null, pht('Proto'), pht('Host'), pht('Port'), pht('Status'), pht('Uptime'), pht('Clients'), pht('Messages'), null, )) ->setColumnClasses( array( null, null, null, null, null, null, null, null, 'wide', )); return $table; } } diff --git a/src/applications/config/controller/PhabricatorConfigClusterRepositoriesController.php b/src/applications/config/controller/PhabricatorConfigClusterRepositoriesController.php index 3a7418affb..b3fd9915b1 100644 --- a/src/applications/config/controller/PhabricatorConfigClusterRepositoriesController.php +++ b/src/applications/config/controller/PhabricatorConfigClusterRepositoriesController.php @@ -1,420 +1,420 @@ buildSideNavView(); $nav->selectFilter('cluster/repositories/'); $title = pht('Cluster Repository Status'); $doc_href = PhabricatorEnv::getDoclink('Cluster: Repositories'); $header = id(new PHUIHeaderView()) ->setHeader($title) ->setProfileHeader(true) ->addActionLink( id(new PHUIButtonView()) ->setIcon('fa-book') ->setHref($doc_href) ->setTag('a') ->setText(pht('Documentation'))); $crumbs = $this ->buildApplicationCrumbs($nav) ->addTextCrumb(pht('Repository Servers')) ->setBorder(true); $repository_status = $this->buildClusterRepositoryStatus(); $repository_errors = $this->buildClusterRepositoryErrors(); $content = id(new PhabricatorConfigPageView()) ->setHeader($header) ->setContent( array( $repository_status, $repository_errors, )); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) ->setNavigation($nav) ->appendChild($content) - ->addFrameClass('white-background'); + ->addClass('white-background'); } private function buildClusterRepositoryStatus() { $viewer = $this->getViewer(); Javelin::initBehavior('phabricator-tooltips'); $all_services = id(new AlmanacServiceQuery()) ->setViewer($viewer) ->withServiceTypes( array( AlmanacClusterRepositoryServiceType::SERVICETYPE, )) ->needBindings(true) ->needProperties(true) ->execute(); $all_services = mpull($all_services, null, 'getPHID'); $all_repositories = id(new PhabricatorRepositoryQuery()) ->setViewer($viewer) ->withTypes( array( PhabricatorRepositoryType::REPOSITORY_TYPE_GIT, )) ->execute(); $all_repositories = mpull($all_repositories, null, 'getPHID'); $all_versions = id(new PhabricatorRepositoryWorkingCopyVersion()) ->loadAll(); $all_devices = $this->getDevices($all_services, false); $all_active_devices = $this->getDevices($all_services, true); $leader_versions = $this->getLeaderVersionsByRepository( $all_repositories, $all_versions, $all_active_devices); $push_times = $this->loadLeaderPushTimes($leader_versions); $repository_groups = mgroup($all_repositories, 'getAlmanacServicePHID'); $repository_versions = mgroup($all_versions, 'getRepositoryPHID'); $rows = array(); foreach ($all_services as $service) { $service_phid = $service->getPHID(); if ($service->getAlmanacPropertyValue('closed')) { $status_icon = 'fa-folder'; $status_tip = pht('Closed'); } else { $status_icon = 'fa-folder-open green'; $status_tip = pht('Open'); } $status_icon = id(new PHUIIconView()) ->setIcon($status_icon) ->addSigil('has-tooltip') ->setMetadata( array( 'tip' => $status_tip, )); $devices = idx($all_devices, $service_phid, array()); $active_devices = idx($all_active_devices, $service_phid, array()); $device_icon = 'fa-server green'; $device_label = pht( '%s Active', phutil_count($active_devices)); $device_status = array( id(new PHUIIconView())->setIcon($device_icon), ' ', $device_label, ); $repositories = idx($repository_groups, $service_phid, array()); $repository_status = pht( '%s', phutil_count($repositories)); $no_leader = array(); $full_sync = array(); $partial_sync = array(); $no_sync = array(); $lag = array(); // Threshold in seconds before we start complaining that repositories // are not synchronized when there is only one leader. $threshold = phutil_units('5 minutes in seconds'); $messages = array(); foreach ($repositories as $repository) { $repository_phid = $repository->getPHID(); $leader_version = idx($leader_versions, $repository_phid); if ($leader_version === null) { $no_leader[] = $repository; $messages[] = pht( 'Repository %s has an ambiguous leader.', $viewer->renderHandle($repository_phid)->render()); continue; } $versions = idx($repository_versions, $repository_phid, array()); // Filter out any versions for devices which are no longer active. foreach ($versions as $key => $version) { $version_device_phid = $version->getDevicePHID(); if (empty($active_devices[$version_device_phid])) { unset($versions[$key]); } } $leaders = 0; foreach ($versions as $version) { if ($version->getRepositoryVersion() == $leader_version) { $leaders++; } } if ($leaders == count($active_devices)) { $full_sync[] = $repository; } else { $push_epoch = idx($push_times, $repository_phid); if ($push_epoch) { $duration = (PhabricatorTime::getNow() - $push_epoch); $lag[] = $duration; } else { $duration = null; } if ($leaders >= 2 || ($duration && ($duration < $threshold))) { $partial_sync[] = $repository; } else { $no_sync[] = $repository; if ($push_epoch) { $messages[] = pht( 'Repository %s has unreplicated changes (for %s).', $viewer->renderHandle($repository_phid)->render(), phutil_format_relative_time($duration)); } else { $messages[] = pht( 'Repository %s has unreplicated changes.', $viewer->renderHandle($repository_phid)->render()); } } } } $with_lag = false; if ($no_leader) { $replication_icon = 'fa-times red'; $replication_label = pht('Ambiguous Leader'); } else if ($no_sync) { $replication_icon = 'fa-refresh yellow'; $replication_label = pht('Unsynchronized'); $with_lag = true; } else if ($partial_sync) { $replication_icon = 'fa-refresh green'; $replication_label = pht('Partial'); $with_lag = true; } else if ($full_sync) { $replication_icon = 'fa-check green'; $replication_label = pht('Synchronized'); } else { $replication_icon = 'fa-times grey'; $replication_label = pht('No Repositories'); } if ($with_lag && $lag) { $lag_status = phutil_format_relative_time(max($lag)); $lag_status = pht(' (%s)', $lag_status); } else { $lag_status = null; } $replication_status = array( id(new PHUIIconView())->setIcon($replication_icon), ' ', $replication_label, $lag_status, ); $messages = phutil_implode_html(phutil_tag('br'), $messages); $rows[] = array( $status_icon, $viewer->renderHandle($service->getPHID()), $device_status, $repository_status, $replication_status, $messages, ); } return id(new AphrontTableView($rows)) ->setNoDataString( pht('No repository cluster services are configured.')) ->setHeaders( array( null, pht('Service'), pht('Devices'), pht('Repos'), pht('Sync'), pht('Messages'), )) ->setColumnClasses( array( null, 'pri', null, null, null, 'wide', )); } private function getDevices( array $all_services, $only_active) { $devices = array(); foreach ($all_services as $service) { $map = array(); foreach ($service->getBindings() as $binding) { if ($only_active && $binding->getIsDisabled()) { continue; } $device = $binding->getDevice(); $device_phid = $device->getPHID(); $map[$device_phid] = $device; } $devices[$service->getPHID()] = $map; } return $devices; } private function getLeaderVersionsByRepository( array $all_repositories, array $all_versions, array $active_devices) { $version_map = mgroup($all_versions, 'getRepositoryPHID'); $result = array(); foreach ($all_repositories as $repository_phid => $repository) { $service_phid = $repository->getAlmanacServicePHID(); if (!$service_phid) { continue; } $devices = idx($active_devices, $service_phid); if (!$devices) { continue; } $versions = idx($version_map, $repository_phid, array()); $versions = mpull($versions, null, 'getDevicePHID'); $versions = array_select_keys($versions, array_keys($devices)); if (!$versions) { continue; } $leader = (int)max(mpull($versions, 'getRepositoryVersion')); $result[$repository_phid] = $leader; } return $result; } private function loadLeaderPushTimes(array $leader_versions) { $viewer = $this->getViewer(); if (!$leader_versions) { return array(); } $events = id(new PhabricatorRepositoryPushEventQuery()) ->setViewer($viewer) ->withIDs($leader_versions) ->execute(); $events = mpull($events, null, 'getID'); $result = array(); foreach ($leader_versions as $key => $version) { $event = idx($events, $version); if (!$event) { continue; } $result[$key] = $event->getEpoch(); } return $result; } private function buildClusterRepositoryErrors() { $viewer = $this->getViewer(); $messages = id(new PhabricatorRepositoryStatusMessage())->loadAllWhere( 'statusCode IN (%Ls)', array( PhabricatorRepositoryStatusMessage::CODE_ERROR, )); $repository_ids = mpull($messages, 'getRepositoryID'); if ($repository_ids) { // NOTE: We're bypassing policies when loading repositories because we // want to show errors exist even if the viewer can't see the repository. // We use handles to describe the repository below, so the viewer won't // actually be able to see any particulars if they can't see the // repository. $repositories = id(new PhabricatorRepositoryQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) ->withIDs($repository_ids) ->execute(); $repositories = mpull($repositories, null, 'getID'); } $rows = array(); foreach ($messages as $message) { $repository = idx($repositories, $message->getRepositoryID()); if (!$repository) { continue; } if (!$repository->isTracked()) { continue; } $icon = id(new PHUIIconView()) ->setIcon('fa-exclamation-triangle red'); $rows[] = array( $icon, $viewer->renderHandle($repository->getPHID()), phutil_tag( 'a', array( 'href' => $repository->getPathURI('manage/status/'), ), $message->getStatusTypeName()), ); } return id(new AphrontTableView($rows)) ->setNoDataString( pht('No active repositories have outstanding errors.')) ->setHeaders( array( null, pht('Repository'), pht('Error'), )) ->setColumnClasses( array( null, 'pri', 'wide', )); } } diff --git a/src/applications/config/controller/PhabricatorConfigDatabaseIssueController.php b/src/applications/config/controller/PhabricatorConfigDatabaseIssueController.php index 6302ccbb47..f1a91d4d5b 100644 --- a/src/applications/config/controller/PhabricatorConfigDatabaseIssueController.php +++ b/src/applications/config/controller/PhabricatorConfigDatabaseIssueController.php @@ -1,171 +1,171 @@ getViewer(); $query = $this->buildSchemaQuery(); $actual = $query->loadActualSchema(); $expect = $query->loadExpectedSchema(); $comp = $query->buildComparisonSchema($expect, $actual); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb(pht('Database Issues')); $crumbs->setBorder(true); // Collect all open issues. $issues = array(); foreach ($comp->getDatabases() as $database_name => $database) { foreach ($database->getLocalIssues() as $issue) { $issues[] = array( $database_name, null, null, null, $issue, ); } foreach ($database->getTables() as $table_name => $table) { foreach ($table->getLocalIssues() as $issue) { $issues[] = array( $database_name, $table_name, null, null, $issue, ); } foreach ($table->getColumns() as $column_name => $column) { foreach ($column->getLocalIssues() as $issue) { $issues[] = array( $database_name, $table_name, 'column', $column_name, $issue, ); } } foreach ($table->getKeys() as $key_name => $key) { foreach ($key->getLocalIssues() as $issue) { $issues[] = array( $database_name, $table_name, 'key', $key_name, $issue, ); } } } } // Sort all open issues so that the most severe issues appear first. $order = array(); $counts = array(); foreach ($issues as $key => $issue) { $const = $issue[4]; $status = PhabricatorConfigStorageSchema::getIssueStatus($const); $severity = PhabricatorConfigStorageSchema::getStatusSeverity($status); $order[$key] = sprintf( '~%d~%s%s%s', 9 - $severity, $issue[0], $issue[1], $issue[3]); if (empty($counts[$status])) { $counts[$status] = 0; } $counts[$status]++; } asort($order); $issues = array_select_keys($issues, array_keys($order)); // Render the issues. $rows = array(); foreach ($issues as $issue) { $const = $issue[4]; $database_link = phutil_tag( 'a', array( 'href' => $this->getApplicationURI('/database/'.$issue[0].'/'), ), $issue[0]); $rows[] = array( $this->renderIcon( PhabricatorConfigStorageSchema::getIssueStatus($const)), $database_link, $issue[1], $issue[2], $issue[3], PhabricatorConfigStorageSchema::getIssueDescription($const), ); } $table = id(new AphrontTableView($rows)) ->setNoDataString( pht('No databases have any issues.')) ->setHeaders( array( null, pht('Database'), pht('Table'), pht('Type'), pht('Column/Key'), pht('Issue'), )) ->setColumnClasses( array( null, null, null, null, null, 'wide', )); $errors = array(); if (isset($counts[PhabricatorConfigStorageSchema::STATUS_FAIL])) { $errors[] = pht( 'Detected %s serious issue(s) with the schemata.', new PhutilNumber($counts[PhabricatorConfigStorageSchema::STATUS_FAIL])); } if (isset($counts[PhabricatorConfigStorageSchema::STATUS_WARN])) { $errors[] = pht( 'Detected %s warning(s) with the schemata.', new PhutilNumber($counts[PhabricatorConfigStorageSchema::STATUS_WARN])); } $title = pht('Database Issues'); $header = id(new PHUIHeaderView()) ->setHeader($title) ->setProfileHeader(true); $nav = $this->buildSideNavView(); $nav->selectFilter('dbissue/'); $content = id(new PhabricatorConfigPageView()) ->setHeader($header) ->setContent($table); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) ->setNavigation($nav) ->appendChild($content) - ->addFrameClass('white-background'); + ->addClass('white-background'); } } diff --git a/src/applications/config/controller/PhabricatorConfigDatabaseStatusController.php b/src/applications/config/controller/PhabricatorConfigDatabaseStatusController.php index c21d284c17..bdeb254437 100644 --- a/src/applications/config/controller/PhabricatorConfigDatabaseStatusController.php +++ b/src/applications/config/controller/PhabricatorConfigDatabaseStatusController.php @@ -1,748 +1,748 @@ getViewer(); $this->database = $request->getURIData('database'); $this->table = $request->getURIData('table'); $this->column = $request->getURIData('column'); $this->key = $request->getURIData('key'); $query = $this->buildSchemaQuery(); $actual = $query->loadActualSchema(); $expect = $query->loadExpectedSchema(); $comp = $query->buildComparisonSchema($expect, $actual); if ($this->column) { return $this->renderColumn( $comp, $expect, $actual, $this->database, $this->table, $this->column); } else if ($this->key) { return $this->renderKey( $comp, $expect, $actual, $this->database, $this->table, $this->key); } else if ($this->table) { return $this->renderTable( $comp, $expect, $actual, $this->database, $this->table); } else if ($this->database) { return $this->renderDatabase( $comp, $expect, $actual, $this->database); } else { return $this->renderServer( $comp, $expect, $actual); } } private function buildResponse($title, $body) { $nav = $this->buildSideNavView(); $nav->selectFilter('database/'); if (!$title) { $title = pht('Database Status'); } $crumbs = $this->buildApplicationCrumbs(); $crumbs->setBorder(true); if ($this->database) { $crumbs->addTextCrumb( pht('Database Status'), $this->getApplicationURI('database/')); if ($this->table) { $crumbs->addTextCrumb( $this->database, $this->getApplicationURI('database/'.$this->database.'/')); if ($this->column || $this->key) { $crumbs->addTextCrumb( $this->table, $this->getApplicationURI( 'database/'.$this->database.'/'.$this->table.'/')); if ($this->column) { $crumbs->addTextCrumb($this->column); } else { $crumbs->addTextCrumb($this->key); } } else { $crumbs->addTextCrumb($this->table); } } else { $crumbs->addTextCrumb($this->database); } } else { $crumbs->addTextCrumb(pht('Database Status')); } $doc_link = PhabricatorEnv::getDoclink('Managing Storage Adjustments'); $header = id(new PHUIHeaderView()) ->setHeader($title) ->setProfileHeader(true) ->addActionLink( id(new PHUIButtonView()) ->setTag('a') ->setIcon('fa-book') ->setHref($doc_link) ->setText(pht('Learn More'))); $content = id(new PhabricatorConfigPageView()) ->setHeader($header) ->setContent($body); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) ->setNavigation($nav) ->appendChild($content) - ->addFrameClass('white-background'); + ->addClass('white-background'); } private function renderServer( PhabricatorConfigServerSchema $comp, PhabricatorConfigServerSchema $expect, PhabricatorConfigServerSchema $actual) { $charset_issue = PhabricatorConfigStorageSchema::ISSUE_CHARSET; $collation_issue = PhabricatorConfigStorageSchema::ISSUE_COLLATION; $rows = array(); foreach ($comp->getDatabases() as $database_name => $database) { $actual_database = $actual->getDatabase($database_name); if ($actual_database) { $charset = $actual_database->getCharacterSet(); $collation = $actual_database->getCollation(); } else { $charset = null; $collation = null; } $status = $database->getStatus(); $issues = $database->getIssues(); $rows[] = array( $this->renderIcon($status), phutil_tag( 'a', array( 'href' => $this->getApplicationURI( '/database/'.$database_name.'/'), ), $database_name), $this->renderAttr($charset, $database->hasIssue($charset_issue)), $this->renderAttr($collation, $database->hasIssue($collation_issue)), ); } $table = id(new AphrontTableView($rows)) ->setHeaders( array( null, pht('Database'), pht('Charset'), pht('Collation'), )) ->setColumnClasses( array( null, 'wide pri', null, null, )); $title = pht('Database Status'); $properties = $this->buildProperties( array( ), $comp->getIssues()); return $this->buildResponse($title, array($properties, $table)); } private function renderDatabase( PhabricatorConfigServerSchema $comp, PhabricatorConfigServerSchema $expect, PhabricatorConfigServerSchema $actual, $database_name) { $collation_issue = PhabricatorConfigStorageSchema::ISSUE_COLLATION; $database = $comp->getDatabase($database_name); if (!$database) { return new Aphront404Response(); } $rows = array(); foreach ($database->getTables() as $table_name => $table) { $status = $table->getStatus(); $rows[] = array( $this->renderIcon($status), phutil_tag( 'a', array( 'href' => $this->getApplicationURI( '/database/'.$database_name.'/'.$table_name.'/'), ), $table_name), $this->renderAttr( $table->getCollation(), $table->hasIssue($collation_issue)), ); } $table = id(new AphrontTableView($rows)) ->setHeaders( array( null, pht('Table'), pht('Collation'), )) ->setColumnClasses( array( null, 'wide pri', null, )); $title = pht('Database: %s', $database_name); $actual_database = $actual->getDatabase($database_name); if ($actual_database) { $actual_charset = $actual_database->getCharacterSet(); $actual_collation = $actual_database->getCollation(); } else { $actual_charset = null; $actual_collation = null; } $expect_database = $expect->getDatabase($database_name); if ($expect_database) { $expect_charset = $expect_database->getCharacterSet(); $expect_collation = $expect_database->getCollation(); } else { $expect_charset = null; $expect_collation = null; } $properties = $this->buildProperties( array( array( pht('Character Set'), $actual_charset, ), array( pht('Expected Character Set'), $expect_charset, ), array( pht('Collation'), $actual_collation, ), array( pht('Expected Collation'), $expect_collation, ), ), $database->getIssues()); return $this->buildResponse($title, array($properties, $table)); } private function renderTable( PhabricatorConfigServerSchema $comp, PhabricatorConfigServerSchema $expect, PhabricatorConfigServerSchema $actual, $database_name, $table_name) { $type_issue = PhabricatorConfigStorageSchema::ISSUE_COLUMNTYPE; $charset_issue = PhabricatorConfigStorageSchema::ISSUE_CHARSET; $collation_issue = PhabricatorConfigStorageSchema::ISSUE_COLLATION; $nullable_issue = PhabricatorConfigStorageSchema::ISSUE_NULLABLE; $unique_issue = PhabricatorConfigStorageSchema::ISSUE_UNIQUE; $columns_issue = PhabricatorConfigStorageSchema::ISSUE_KEYCOLUMNS; $longkey_issue = PhabricatorConfigStorageSchema::ISSUE_LONGKEY; $auto_issue = PhabricatorConfigStorageSchema::ISSUE_AUTOINCREMENT; $database = $comp->getDatabase($database_name); if (!$database) { return new Aphront404Response(); } $table = $database->getTable($table_name); if (!$table) { return new Aphront404Response(); } $actual_database = $actual->getDatabase($database_name); $actual_table = null; if ($actual_database) { $actual_table = $actual_database->getTable($table_name); } $expect_database = $expect->getDatabase($database_name); $expect_table = null; if ($expect_database) { $expect_table = $expect_database->getTable($table_name); } $rows = array(); foreach ($table->getColumns() as $column_name => $column) { $expect_column = null; if ($expect_table) { $expect_column = $expect_table->getColumn($column_name); } $status = $column->getStatus(); $data_type = null; if ($expect_column) { $data_type = $expect_column->getDataType(); } $rows[] = array( $this->renderIcon($status), phutil_tag( 'a', array( 'href' => $this->getApplicationURI( 'database/'. $database_name.'/'. $table_name.'/'. 'col/'. $column_name.'/'), ), $column_name), $data_type, $this->renderAttr( $column->getColumnType(), $column->hasIssue($type_issue)), $this->renderAttr( $this->renderBoolean($column->getNullable()), $column->hasIssue($nullable_issue)), $this->renderAttr( $this->renderBoolean($column->getAutoIncrement()), $column->hasIssue($auto_issue)), $this->renderAttr( $column->getCharacterSet(), $column->hasIssue($charset_issue)), $this->renderAttr( $column->getCollation(), $column->hasIssue($collation_issue)), ); } $table_view = id(new AphrontTableView($rows)) ->setHeaders( array( null, pht('Column'), pht('Data Type'), pht('Column Type'), pht('Nullable'), pht('Autoincrement'), pht('Character Set'), pht('Collation'), )) ->setColumnClasses( array( null, 'wide pri', null, null, null, null, null, )); $key_rows = array(); foreach ($table->getKeys() as $key_name => $key) { $expect_key = null; if ($expect_table) { $expect_key = $expect_table->getKey($key_name); } $status = $key->getStatus(); $size = 0; foreach ($key->getColumnNames() as $column_spec) { list($column_name, $prefix) = $key->getKeyColumnAndPrefix($column_spec); $column = $table->getColumn($column_name); if (!$column) { $size = 0; break; } $size += $column->getKeyByteLength($prefix); } $size_formatted = null; if ($size) { $size_formatted = $this->renderAttr( $size, $key->hasIssue($longkey_issue)); } $key_rows[] = array( $this->renderIcon($status), phutil_tag( 'a', array( 'href' => $this->getApplicationURI( 'database/'. $database_name.'/'. $table_name.'/'. 'key/'. $key_name.'/'), ), $key_name), $this->renderAttr( implode(', ', $key->getColumnNames()), $key->hasIssue($columns_issue)), $this->renderAttr( $this->renderBoolean($key->getUnique()), $key->hasIssue($unique_issue)), $size_formatted, ); } $keys_view = id(new AphrontTableView($key_rows)) ->setHeaders( array( null, pht('Key'), pht('Columns'), pht('Unique'), pht('Size'), )) ->setColumnClasses( array( null, 'wide pri', null, null, null, )); $title = pht('Database: %s.%s', $database_name, $table_name); if ($actual_table) { $actual_collation = $actual_table->getCollation(); } else { $actual_collation = null; } if ($expect_table) { $expect_collation = $expect_table->getCollation(); } else { $expect_collation = null; } $properties = $this->buildProperties( array( array( pht('Collation'), $actual_collation, ), array( pht('Expected Collation'), $expect_collation, ), ), $table->getIssues()); return $this->buildResponse( $title, array($properties, $table_view, $keys_view)); } private function renderColumn( PhabricatorConfigServerSchema $comp, PhabricatorConfigServerSchema $expect, PhabricatorConfigServerSchema $actual, $database_name, $table_name, $column_name) { $database = $comp->getDatabase($database_name); if (!$database) { return new Aphront404Response(); } $table = $database->getTable($table_name); if (!$table) { return new Aphront404Response(); } $column = $table->getColumn($column_name); if (!$column) { return new Aphront404Response(); } $actual_database = $actual->getDatabase($database_name); $actual_table = null; $actual_column = null; if ($actual_database) { $actual_table = $actual_database->getTable($table_name); if ($actual_table) { $actual_column = $actual_table->getColumn($column_name); } } $expect_database = $expect->getDatabase($database_name); $expect_table = null; $expect_column = null; if ($expect_database) { $expect_table = $expect_database->getTable($table_name); if ($expect_table) { $expect_column = $expect_table->getColumn($column_name); } } if ($actual_column) { $actual_coltype = $actual_column->getColumnType(); $actual_charset = $actual_column->getCharacterSet(); $actual_collation = $actual_column->getCollation(); $actual_nullable = $actual_column->getNullable(); $actual_auto = $actual_column->getAutoIncrement(); } else { $actual_coltype = null; $actual_charset = null; $actual_collation = null; $actual_nullable = null; $actual_auto = null; } if ($expect_column) { $data_type = $expect_column->getDataType(); $expect_coltype = $expect_column->getColumnType(); $expect_charset = $expect_column->getCharacterSet(); $expect_collation = $expect_column->getCollation(); $expect_nullable = $expect_column->getNullable(); $expect_auto = $expect_column->getAutoIncrement(); } else { $data_type = null; $expect_coltype = null; $expect_charset = null; $expect_collation = null; $expect_nullable = null; $expect_auto = null; } $title = pht( 'Database Status: %s.%s.%s', $database_name, $table_name, $column_name); $properties = $this->buildProperties( array( array( pht('Data Type'), $data_type, ), array( pht('Column Type'), $actual_coltype, ), array( pht('Expected Column Type'), $expect_coltype, ), array( pht('Character Set'), $actual_charset, ), array( pht('Expected Character Set'), $expect_charset, ), array( pht('Collation'), $actual_collation, ), array( pht('Expected Collation'), $expect_collation, ), array( pht('Nullable'), $this->renderBoolean($actual_nullable), ), array( pht('Expected Nullable'), $this->renderBoolean($expect_nullable), ), array( pht('Autoincrement'), $this->renderBoolean($actual_auto), ), array( pht('Expected Autoincrement'), $this->renderBoolean($expect_auto), ), ), $column->getIssues()); return $this->buildResponse($title, $properties); } private function renderKey( PhabricatorConfigServerSchema $comp, PhabricatorConfigServerSchema $expect, PhabricatorConfigServerSchema $actual, $database_name, $table_name, $key_name) { $database = $comp->getDatabase($database_name); if (!$database) { return new Aphront404Response(); } $table = $database->getTable($table_name); if (!$table) { return new Aphront404Response(); } $key = $table->getKey($key_name); if (!$key) { return new Aphront404Response(); } $actual_database = $actual->getDatabase($database_name); $actual_table = null; $actual_key = null; if ($actual_database) { $actual_table = $actual_database->getTable($table_name); if ($actual_table) { $actual_key = $actual_table->getKey($key_name); } } $expect_database = $expect->getDatabase($database_name); $expect_table = null; $expect_key = null; if ($expect_database) { $expect_table = $expect_database->getTable($table_name); if ($expect_table) { $expect_key = $expect_table->getKey($key_name); } } if ($actual_key) { $actual_columns = $actual_key->getColumnNames(); $actual_unique = $actual_key->getUnique(); } else { $actual_columns = array(); $actual_unique = null; } if ($expect_key) { $expect_columns = $expect_key->getColumnNames(); $expect_unique = $expect_key->getUnique(); } else { $expect_columns = array(); $expect_unique = null; } $title = pht( 'Database Status: %s.%s (%s)', $database_name, $table_name, $key_name); $properties = $this->buildProperties( array( array( pht('Unique'), $this->renderBoolean($actual_unique), ), array( pht('Expected Unique'), $this->renderBoolean($expect_unique), ), array( pht('Columns'), implode(', ', $actual_columns), ), array( pht('Expected Columns'), implode(', ', $expect_columns), ), ), $key->getIssues()); return $this->buildResponse($title, $properties); } private function buildProperties(array $properties, array $issues) { $view = id(new PHUIPropertyListView()) ->setUser($this->getRequest()->getUser()); foreach ($properties as $property) { list($key, $value) = $property; $view->addProperty($key, $value); } $status_view = new PHUIStatusListView(); if (!$issues) { $status_view->addItem( id(new PHUIStatusItemView()) ->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green') ->setTarget(pht('No Schema Issues'))); } else { foreach ($issues as $issue) { $note = PhabricatorConfigStorageSchema::getIssueDescription($issue); $status = PhabricatorConfigStorageSchema::getIssueStatus($issue); switch ($status) { case PhabricatorConfigStorageSchema::STATUS_WARN: $icon = PHUIStatusItemView::ICON_WARNING; $color = 'yellow'; break; case PhabricatorConfigStorageSchema::STATUS_FAIL: default: $icon = PHUIStatusItemView::ICON_REJECT; $color = 'red'; break; } $item = id(new PHUIStatusItemView()) ->setTarget(PhabricatorConfigStorageSchema::getIssueName($issue)) ->setIcon($icon, $color) ->setNote($note); $status_view->addItem($item); } } $view->addProperty(pht('Schema Status'), $status_view); return phutil_tag_div('config-page-property', $view); } } diff --git a/src/applications/config/controller/PhabricatorConfigGroupController.php b/src/applications/config/controller/PhabricatorConfigGroupController.php index 1630fac007..6e713f7eab 100644 --- a/src/applications/config/controller/PhabricatorConfigGroupController.php +++ b/src/applications/config/controller/PhabricatorConfigGroupController.php @@ -1,121 +1,121 @@ getViewer(); $group_key = $request->getURIData('key'); $groups = PhabricatorApplicationConfigOptions::loadAll(); $options = idx($groups, $group_key); if (!$options) { return new Aphront404Response(); } $group_uri = PhabricatorConfigGroupConstants::getGroupURI( $options->getGroup()); $group_name = PhabricatorConfigGroupConstants::getGroupShortName( $options->getGroup()); $nav = $this->buildSideNavView(); $nav->selectFilter($group_uri); $title = pht('%s Configuration', $options->getName()); $list = $this->buildOptionList($options->getOptions()); $crumbs = $this ->buildApplicationCrumbs() ->addTextCrumb($group_name, $this->getApplicationURI($group_uri)) ->addTextCrumb($options->getName()) ->setBorder(true); $header = id(new PHUIHeaderView()) ->setHeader($title) ->setProfileHeader(true); $content = id(new PhabricatorConfigPageView()) ->setHeader($header) ->setContent($list); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) ->setNavigation($nav) ->appendChild($content) - ->addFrameClass('white-background'); + ->addClass('white-background'); } private function buildOptionList(array $options) { assert_instances_of($options, 'PhabricatorConfigOption'); require_celerity_resource('config-options-css'); $db_values = array(); if ($options) { $db_values = id(new PhabricatorConfigEntry())->loadAllWhere( 'configKey IN (%Ls) AND namespace = %s', mpull($options, 'getKey'), 'default'); $db_values = mpull($db_values, null, 'getConfigKey'); } $engine = id(new PhabricatorMarkupEngine()) ->setViewer($this->getRequest()->getUser()); foreach ($options as $option) { $engine->addObject($option, 'summary'); } $engine->process(); $list = new PHUIObjectItemListView(); $list->setBig(true); foreach ($options as $option) { $summary = $engine->getOutput($option, 'summary'); $item = id(new PHUIObjectItemView()) ->setHeader($option->getKey()) ->setHref('/config/edit/'.$option->getKey().'/') ->addAttribute($summary); $label = pht('Current Value:'); $color = null; $db_value = idx($db_values, $option->getKey()); if ($db_value && !$db_value->getIsDeleted()) { $item->setEffect('visited'); $color = 'violet'; $label = pht('Customized Value:'); } if ($option->getHidden()) { $item->setStatusIcon('fa-eye-slash grey', pht('Hidden')); $item->setDisabled(true); } else if ($option->getLocked()) { $item->setStatusIcon('fa-lock '.$color, pht('Locked')); } else { $item->setStatusIcon('fa-pencil-square-o '.$color, pht('Editable')); } if (!$option->getHidden()) { $current_value = PhabricatorEnv::getEnvConfig($option->getKey()); $current_value = PhabricatorConfigJSON::prettyPrintJSON( $current_value); $current_value = phutil_tag( 'div', array( 'class' => 'config-options-current-value', ), array( phutil_tag('span', array(), $label), ' '.$current_value, )); $item->appendChild($current_value); } $list->addItem($item); } return $list; } } diff --git a/src/applications/config/controller/PhabricatorConfigHistoryController.php b/src/applications/config/controller/PhabricatorConfigHistoryController.php index 749ad3ffe4..eb7fbf607b 100644 --- a/src/applications/config/controller/PhabricatorConfigHistoryController.php +++ b/src/applications/config/controller/PhabricatorConfigHistoryController.php @@ -1,56 +1,56 @@ getViewer(); $id = $request->getURIData('id'); $xactions = id(new PhabricatorConfigTransactionQuery()) ->setViewer($viewer) ->needComments(true) ->execute(); $object = new PhabricatorConfigEntry(); $xaction = $object->getApplicationTransactionTemplate(); $view = $xaction->getApplicationTransactionViewObject(); $timeline = $view ->setUser($viewer) ->setTransactions($xactions) ->setRenderAsFeed(true) ->setObjectPHID(PhabricatorPHIDConstants::PHID_VOID); $timeline->setShouldTerminate(true); $object->willRenderTimeline($timeline, $this->getRequest()); $title = pht('Settings History'); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb($title); $crumbs->setBorder(true); $nav = $this->buildSideNavView(); $nav->selectFilter('history/'); $header = id(new PHUIHeaderView()) ->setHeader($title) ->setProfileHeader(true); $content = id(new PhabricatorConfigPageView()) ->setHeader($header) ->setContent($timeline); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) ->setNavigation($nav) ->appendChild($content) - ->addFrameClass('white-background'); + ->addClass('white-background'); } } diff --git a/src/applications/config/controller/PhabricatorConfigIssueListController.php b/src/applications/config/controller/PhabricatorConfigIssueListController.php index b24c5e74ad..a5553a34bb 100644 --- a/src/applications/config/controller/PhabricatorConfigIssueListController.php +++ b/src/applications/config/controller/PhabricatorConfigIssueListController.php @@ -1,117 +1,117 @@ getViewer(); $nav = $this->buildSideNavView(); $nav->selectFilter('issue/'); $issues = PhabricatorSetupCheck::runNormalChecks(); PhabricatorSetupCheck::setOpenSetupIssueKeys( PhabricatorSetupCheck::getUnignoredIssueKeys($issues), $update_database = true); $important = $this->buildIssueList( $issues, PhabricatorSetupCheck::GROUP_IMPORTANT, 'fa-warning'); $php = $this->buildIssueList( $issues, PhabricatorSetupCheck::GROUP_PHP, 'fa-code'); $mysql = $this->buildIssueList( $issues, PhabricatorSetupCheck::GROUP_MYSQL, 'fa-database'); $other = $this->buildIssueList( $issues, PhabricatorSetupCheck::GROUP_OTHER, 'fa-question-circle'); $no_issues = null; if (empty($issues)) { $no_issues = id(new PHUIInfoView()) ->setTitle(pht('No Issues')) ->appendChild( pht('Your install has no current setup issues to resolve.')) ->setSeverity(PHUIInfoView::SEVERITY_NOTICE); } $title = pht('Setup Issues'); $header = id(new PHUIHeaderView()) ->setHeader($title) ->setProfileHeader(true); $crumbs = $this ->buildApplicationCrumbs($nav) ->addTextCrumb(pht('Setup Issues')) ->setBorder(true); $page = array( $no_issues, $important, $php, $mysql, $other, ); $content = id(new PhabricatorConfigPageView()) ->setHeader($header) ->setContent($page); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) ->setNavigation($nav) ->appendChild($content) - ->addFrameClass('white-background'); + ->addClass('white-background'); } private function buildIssueList(array $issues, $group, $fonticon) { assert_instances_of($issues, 'PhabricatorSetupIssue'); $list = new PHUIObjectItemListView(); $list->setBig(true); $ignored_items = array(); $items = 0; foreach ($issues as $issue) { if ($issue->getGroup() == $group) { $items++; $href = $this->getApplicationURI('/issue/'.$issue->getIssueKey().'/'); $item = id(new PHUIObjectItemView()) ->setHeader($issue->getName()) ->setHref($href) ->addAttribute($issue->getSummary()); if (!$issue->getIsIgnored()) { $icon = id(new PHUIIconView()) ->setIcon($fonticon) ->setBackground('bg-sky'); $item->setImageIcon($icon); $list->addItem($item); } else { $icon = id(new PHUIIconView()) ->setIcon('fa-eye-slash') ->setBackground('bg-grey'); $item->setDisabled(true); $item->setImageIcon($icon); $ignored_items[] = $item; } } } foreach ($ignored_items as $item) { $list->addItem($item); } if ($items == 0) { return null; } else { return $list; } } } diff --git a/src/applications/config/controller/PhabricatorConfigIssueViewController.php b/src/applications/config/controller/PhabricatorConfigIssueViewController.php index dc7e5e2097..57d7b75137 100644 --- a/src/applications/config/controller/PhabricatorConfigIssueViewController.php +++ b/src/applications/config/controller/PhabricatorConfigIssueViewController.php @@ -1,68 +1,68 @@ getViewer(); $issue_key = $request->getURIData('key'); $issues = PhabricatorSetupCheck::runNormalChecks(); PhabricatorSetupCheck::setOpenSetupIssueKeys( PhabricatorSetupCheck::getUnignoredIssueKeys($issues), $update_database = true); $nav = $this->buildSideNavView(); $nav->selectFilter('issue/'); if (empty($issues[$issue_key])) { $content = id(new PHUIInfoView()) ->setSeverity(PHUIInfoView::SEVERITY_NOTICE) ->setTitle(pht('Issue Resolved')) ->appendChild(pht('This setup issue has been resolved. ')) ->appendChild( phutil_tag( 'a', array( 'href' => $this->getApplicationURI('issue/'), ), pht('Return to Open Issue List'))); $title = pht('Resolved Issue'); } else { $issue = $issues[$issue_key]; $content = $this->renderIssue($issue); $title = $issue->getShortName(); } $crumbs = $this ->buildApplicationCrumbs() ->setBorder(true) ->addTextCrumb(pht('Setup Issues'), $this->getApplicationURI('issue/')) ->addTextCrumb($title, $request->getRequestURI()) ->setBorder(true); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) ->setNavigation($nav) ->appendChild($content) - ->addFrameClass('white-background'); + ->addClass('white-background'); } private function renderIssue(PhabricatorSetupIssue $issue) { require_celerity_resource('setup-issue-css'); $view = new PhabricatorSetupIssueView(); $view->setIssue($issue); $container = phutil_tag( 'div', array( 'class' => 'setup-issue-background', ), $view->render()); return $container; } } diff --git a/src/applications/config/controller/PhabricatorConfigListController.php b/src/applications/config/controller/PhabricatorConfigListController.php index 0458dfd194..517fe014a9 100644 --- a/src/applications/config/controller/PhabricatorConfigListController.php +++ b/src/applications/config/controller/PhabricatorConfigListController.php @@ -1,61 +1,61 @@ getViewer(); $nav = $this->buildSideNavView(); $nav->selectFilter('/'); $groups = PhabricatorApplicationConfigOptions::loadAll(); $core_list = $this->buildConfigOptionsList($groups, 'core'); $title = pht('Core Settings'); $header = id(new PHUIHeaderView()) ->setHeader($title) ->setProfileHeader(true); $crumbs = $this ->buildApplicationCrumbs() ->addTextCrumb(pht('Core')) ->setBorder(true); $content = id(new PhabricatorConfigPageView()) ->setHeader($header) ->setContent($core_list); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) ->setNavigation($nav) ->appendChild($content) - ->addFrameClass('white-background'); + ->addClass('white-background'); } private function buildConfigOptionsList(array $groups, $type) { assert_instances_of($groups, 'PhabricatorApplicationConfigOptions'); $list = new PHUIObjectItemListView(); $list->setBig(true); $groups = msort($groups, 'getName'); foreach ($groups as $group) { if ($group->getGroup() == $type) { $icon = id(new PHUIIconView()) ->setIcon($group->getIcon()) ->setBackground('bg-blue'); $item = id(new PHUIObjectItemView()) ->setHeader($group->getName()) ->setHref('/config/group/'.$group->getKey().'/') ->addAttribute($group->getDescription()) ->setImageIcon($icon); $list->addItem($item); } } return $list; } } diff --git a/src/applications/config/controller/PhabricatorConfigModuleController.php b/src/applications/config/controller/PhabricatorConfigModuleController.php index 7848e45eb2..e10d70561b 100644 --- a/src/applications/config/controller/PhabricatorConfigModuleController.php +++ b/src/applications/config/controller/PhabricatorConfigModuleController.php @@ -1,42 +1,42 @@ getViewer(); $key = $request->getURIData('module'); $all_modules = PhabricatorConfigModule::getAllModules(); if (empty($all_modules[$key])) { return new Aphront404Response(); } $module = $all_modules[$key]; $content = $module->renderModuleStatus($request); $title = $module->getModuleName(); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb($title); $crumbs->setBorder(true); $nav = $this->buildSideNavView(); $nav->selectFilter('module/'.$key.'/'); $header = id(new PHUIHeaderView()) ->setHeader($title) ->setProfileHeader(true); $content = id(new PhabricatorConfigPageView()) ->setHeader($header) ->setContent($content); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) ->setNavigation($nav) ->appendChild($content) - ->addFrameClass('white-background'); + ->addClass('white-background'); } } diff --git a/src/applications/config/controller/PhabricatorConfigVersionController.php b/src/applications/config/controller/PhabricatorConfigVersionController.php index 82f2da6a23..15877ddbd7 100644 --- a/src/applications/config/controller/PhabricatorConfigVersionController.php +++ b/src/applications/config/controller/PhabricatorConfigVersionController.php @@ -1,93 +1,93 @@ getViewer(); $title = pht('Version Information'); $crumbs = $this ->buildApplicationCrumbs() ->addTextCrumb($title) ->setBorder(true); $versions = $this->renderModuleStatus($viewer); $nav = $this->buildSideNavView(); $nav->selectFilter('version/'); $header = id(new PHUIHeaderView()) ->setHeader($title) ->setProfileHeader(true); $content = id(new PhabricatorConfigPageView()) ->setHeader($header) ->setContent($versions); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) ->setNavigation($nav) ->appendChild($content) - ->addFrameClass('white-background'); + ->addClass('white-background'); } public function renderModuleStatus($viewer) { $versions = $this->loadVersions($viewer); $version_property_list = id(new PHUIPropertyListView()); foreach ($versions as $name => $version) { $version_property_list->addProperty($name, $version); } $phabricator_root = dirname(phutil_get_library_root('phabricator')); $version_path = $phabricator_root.'/conf/local/VERSION'; if (Filesystem::pathExists($version_path)) { $version_from_file = Filesystem::readFile($version_path); $version_property_list->addProperty( pht('Local Version'), $version_from_file); } return $version_property_list; } private function loadVersions(PhabricatorUser $viewer) { $specs = array( 'phabricator', 'arcanist', 'phutil', ); $all_libraries = PhutilBootloader::getInstance()->getAllLibraries(); // This puts the core libraries at the top: $other_libraries = array_diff($all_libraries, $specs); $specs = array_merge($specs, $other_libraries); $futures = array(); foreach ($specs as $lib) { $root = dirname(phutil_get_library_root($lib)); $futures[$lib] = id(new ExecFuture('git log --format=%s -n 1 --', '%H %ct')) ->setCWD($root); } $results = array(); foreach ($futures as $key => $future) { list($err, $stdout) = $future->resolve(); if (!$err) { list($hash, $epoch) = explode(' ', $stdout); $version = pht('%s (%s)', $hash, phabricator_date($epoch, $viewer)); } else { $version = pht('Unknown'); } $results[$key] = $version; } return $results; } } diff --git a/src/applications/home/controller/PhabricatorHomeMainController.php b/src/applications/home/controller/PhabricatorHomeMainController.php index 3984f63623..405959fe67 100644 --- a/src/applications/home/controller/PhabricatorHomeMainController.php +++ b/src/applications/home/controller/PhabricatorHomeMainController.php @@ -1,259 +1,259 @@ getViewer(); $dashboard = PhabricatorDashboardInstall::getDashboard( $viewer, $viewer->getPHID(), get_class($this->getCurrentApplication())); if (!$dashboard) { $dashboard = PhabricatorDashboardInstall::getDashboard( $viewer, PhabricatorHomeApplication::DASHBOARD_DEFAULT, get_class($this->getCurrentApplication())); } if ($dashboard) { $content = id(new PhabricatorDashboardRenderingEngine()) ->setViewer($viewer) ->setDashboard($dashboard) ->renderDashboard(); } else { $content = $this->buildMainResponse(); } if (!$request->getURIData('only')) { $nav = $this->buildNav(); $nav->appendChild( array( $content, id(new PhabricatorGlobalUploadTargetView())->setUser($viewer), )); $content = $nav; } return $this->newPage() ->setTitle('Phabricator') - ->addFrameClass('phabricator-home') + ->addClass('phabricator-home') ->appendChild($content); } private function buildMainResponse() { require_celerity_resource('phabricator-dashboard-css'); $viewer = $this->getViewer(); $has_maniphest = PhabricatorApplication::isClassInstalledForViewer( 'PhabricatorManiphestApplication', $viewer); $has_diffusion = PhabricatorApplication::isClassInstalledForViewer( 'PhabricatorDiffusionApplication', $viewer); $has_differential = PhabricatorApplication::isClassInstalledForViewer( 'PhabricatorDifferentialApplication', $viewer); $revision_panel = null; if ($has_differential) { $revision_panel = $this->buildRevisionPanel(); } $tasks_panel = null; if ($has_maniphest) { $tasks_panel = $this->buildTasksPanel(); } $repository_panel = null; if ($has_diffusion) { $repository_panel = $this->buildRepositoryPanel(); } $feed_panel = $this->buildFeedPanel(); $dashboard = id(new AphrontMultiColumnView()) ->setFluidlayout(true) ->setGutter(AphrontMultiColumnView::GUTTER_LARGE); $main_panel = phutil_tag( 'div', array( 'class' => 'homepage-panel', ), array( $revision_panel, $tasks_panel, $repository_panel, )); $dashboard->addColumn($main_panel, 'thirds'); $side_panel = phutil_tag( 'div', array( 'class' => 'homepage-side-panel', ), array( $feed_panel, )); $dashboard->addColumn($side_panel, 'third'); $view = id(new PHUIBoxView()) ->addClass('dashboard-view') ->appendChild($dashboard); return $view; } private function buildHomepagePanel($title, $href, $view) { $title = phutil_tag( 'a', array( 'href' => $href, ), $title); $icon = id(new PHUIIconView()) ->setIcon('fa-search') ->setHref($href); $header = id(new PHUIHeaderView()) ->setHeader($title) ->addActionItem($icon); $box = id(new PHUIObjectBoxView()) ->setHeader($header); if ($view->getObjectList()) { $box->setObjectList($view->getObjectList()); } if ($view->getContent()) { $box->appendChild($view->getContent()); } return $box; } private function buildRevisionPanel() { $viewer = $this->getViewer(); if (!$viewer->isLoggedIn()) { return null; } $engine = new DifferentialRevisionSearchEngine(); $engine->setViewer($viewer); $saved = $engine->buildSavedQueryFromBuiltin('active'); $query = $engine->buildQueryFromSavedQuery($saved); $pager = $engine->newPagerForSavedQuery($saved); $pager->setPageSize(15); $results = $engine->executeQuery($query, $pager); $view = $engine->renderResults($results, $saved); $title = pht('Active Revisions'); $href = '/differential/query/active/'; return $this->buildHomepagePanel($title, $href, $view); } private function buildTasksPanel() { $viewer = $this->getViewer(); $query = 'assigned'; $title = pht('Assigned Tasks'); $href = '/maniphest/query/assigned/'; if (!$viewer->isLoggedIn()) { $query = 'open'; $title = pht('Open Tasks'); $href = '/maniphest/query/open/'; } $engine = new ManiphestTaskSearchEngine(); $engine->setViewer($viewer); $saved = $engine->buildSavedQueryFromBuiltin($query); $query = $engine->buildQueryFromSavedQuery($saved); $pager = $engine->newPagerForSavedQuery($saved); $pager->setPageSize(15); $results = $engine->executeQuery($query, $pager); $view = $engine->renderResults($results, $saved); return $this->buildHomepagePanel($title, $href, $view); } public function buildFeedPanel() { $viewer = $this->getViewer(); $engine = new PhabricatorFeedSearchEngine(); $engine->setViewer($viewer); $saved = $engine->buildSavedQueryFromBuiltin('all'); $query = $engine->buildQueryFromSavedQuery($saved); $pager = $engine->newPagerForSavedQuery($saved); $pager->setPageSize(40); $results = $engine->executeQuery($query, $pager); $view = $engine->renderResults($results, $saved); // Low tech NUX. if (!$results && ($viewer->getIsAdmin() == 1)) { $instance = PhabricatorEnv::getEnvConfig('cluster.instance'); if (!$instance) { $content = pht(<<setObjectList($list); $view->setNoDataString($welcome); } $title = pht('Recent Activity'); $href = '/feed/'; return $this->buildHomepagePanel($title, $href, $view); } public function buildRepositoryPanel() { $viewer = $this->getViewer(); $engine = new PhabricatorRepositorySearchEngine(); $engine->setViewer($viewer); $saved = $engine->buildSavedQueryFromBuiltin('active'); $query = $engine->buildQueryFromSavedQuery($saved); $pager = $engine->newPagerForSavedQuery($saved); $pager->setPageSize(5); $results = $engine->executeQuery($query, $pager); $view = $engine->renderResults($results, $saved); $title = pht('Active Repositories'); $href = '/diffusion/'; return $this->buildHomepagePanel($title, $href, $view); } } diff --git a/src/applications/project/controller/PhabricatorProjectBoardViewController.php b/src/applications/project/controller/PhabricatorProjectBoardViewController.php index a30201185e..107d3dc0d0 100644 --- a/src/applications/project/controller/PhabricatorProjectBoardViewController.php +++ b/src/applications/project/controller/PhabricatorProjectBoardViewController.php @@ -1,1075 +1,1075 @@ getUser(); $response = $this->loadProject(); if ($response) { return $response; } $project = $this->getProject(); $this->readRequestState(); $board_uri = $this->getApplicationURI('board/'.$project->getID().'/'); $search_engine = id(new ManiphestTaskSearchEngine()) ->setViewer($viewer) ->setBaseURI($board_uri) ->setIsBoardView(true); if ($request->isFormPost() && !$request->getBool('initialize')) { $saved = $search_engine->buildSavedQueryFromRequest($request); $search_engine->saveQuery($saved); $filter_form = id(new AphrontFormView()) ->setUser($viewer); $search_engine->buildSearchForm($filter_form, $saved); if ($search_engine->getErrors()) { return $this->newDialog() ->setWidth(AphrontDialogView::WIDTH_FULL) ->setTitle(pht('Advanced Filter')) ->appendChild($filter_form->buildLayoutView()) ->setErrors($search_engine->getErrors()) ->setSubmitURI($board_uri) ->addSubmitButton(pht('Apply Filter')) ->addCancelButton($board_uri); } return id(new AphrontRedirectResponse())->setURI( $this->getURIWithState( $search_engine->getQueryResultsPageURI($saved->getQueryKey()))); } $query_key = $this->getDefaultFilter($project); $request_query = $request->getStr('filter'); if (strlen($request_query)) { $query_key = $request_query; } $uri_query = $request->getURIData('queryKey'); if (strlen($uri_query)) { $query_key = $uri_query; } $this->queryKey = $query_key; $custom_query = null; if ($search_engine->isBuiltinQuery($query_key)) { $saved = $search_engine->buildSavedQueryFromBuiltin($query_key); } else { $saved = id(new PhabricatorSavedQueryQuery()) ->setViewer($viewer) ->withQueryKeys(array($query_key)) ->executeOne(); if (!$saved) { return new Aphront404Response(); } $custom_query = $saved; } if ($request->getURIData('filter')) { $filter_form = id(new AphrontFormView()) ->setUser($viewer); $search_engine->buildSearchForm($filter_form, $saved); return $this->newDialog() ->setWidth(AphrontDialogView::WIDTH_FULL) ->setTitle(pht('Advanced Filter')) ->appendChild($filter_form->buildLayoutView()) ->setSubmitURI($board_uri) ->addSubmitButton(pht('Apply Filter')) ->addCancelButton($board_uri); } $task_query = $search_engine->buildQueryFromSavedQuery($saved); $select_phids = array($project->getPHID()); if ($project->getHasSubprojects() || $project->getHasMilestones()) { $descendants = id(new PhabricatorProjectQuery()) ->setViewer($viewer) ->withAncestorProjectPHIDs($select_phids) ->execute(); foreach ($descendants as $descendant) { $select_phids[] = $descendant->getPHID(); } } $tasks = $task_query ->withEdgeLogicPHIDs( PhabricatorProjectObjectHasProjectEdgeType::EDGECONST, PhabricatorQueryConstraint::OPERATOR_ANCESTOR, array($select_phids)) ->setOrder(ManiphestTaskQuery::ORDER_PRIORITY) ->setViewer($viewer) ->execute(); $tasks = mpull($tasks, null, 'getPHID'); $board_phid = $project->getPHID(); // Regardless of display order, pass tasks to the layout engine in ID order // so layout is consistent. $board_tasks = msort($tasks, 'getID'); $layout_engine = id(new PhabricatorBoardLayoutEngine()) ->setViewer($viewer) ->setBoardPHIDs(array($board_phid)) ->setObjectPHIDs(array_keys($board_tasks)) ->setFetchAllBoards(true) ->executeLayout(); $columns = $layout_engine->getColumns($board_phid); if (!$columns || !$project->getHasWorkboard()) { $has_normal_columns = false; foreach ($columns as $column) { if (!$column->getProxyPHID()) { $has_normal_columns = true; break; } } $can_edit = PhabricatorPolicyFilter::hasCapability( $viewer, $project, PhabricatorPolicyCapability::CAN_EDIT); if (!$has_normal_columns) { if (!$can_edit) { $content = $this->buildNoAccessContent($project); } else { $content = $this->buildInitializeContent($project); } } else { if (!$can_edit) { $content = $this->buildDisabledContent($project); } else { $content = $this->buildEnableContent($project); } } if ($content instanceof AphrontResponse) { return $content; } $nav = $this->getProfileMenu(); $nav->selectFilter(PhabricatorProject::PANEL_WORKBOARD); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb(pht('Workboard')); return $this->newPage() ->setTitle( array( $project->getDisplayName(), pht('Workboard'), )) ->setNavigation($nav) ->setCrumbs($crumbs) ->appendChild($content); } $task_can_edit_map = id(new PhabricatorPolicyFilter()) ->setViewer($viewer) ->requireCapabilities(array(PhabricatorPolicyCapability::CAN_EDIT)) ->apply($tasks); // If this is a batch edit, select the editable tasks in the chosen column // and ship the user into the batch editor. $batch_edit = $request->getStr('batch'); if ($batch_edit) { if ($batch_edit !== self::BATCH_EDIT_ALL) { $column_id_map = mpull($columns, null, 'getID'); $batch_column = idx($column_id_map, $batch_edit); if (!$batch_column) { return new Aphront404Response(); } $batch_task_phids = $layout_engine->getColumnObjectPHIDs( $board_phid, $batch_column->getPHID()); foreach ($batch_task_phids as $key => $batch_task_phid) { if (empty($task_can_edit_map[$batch_task_phid])) { unset($batch_task_phids[$key]); } } $batch_tasks = array_select_keys($tasks, $batch_task_phids); } else { $batch_tasks = $task_can_edit_map; } if (!$batch_tasks) { $cancel_uri = $this->getURIWithState($board_uri); return $this->newDialog() ->setTitle(pht('No Editable Tasks')) ->appendParagraph( pht( 'The selected column contains no visible tasks which you '. 'have permission to edit.')) ->addCancelButton($board_uri); } $batch_ids = mpull($batch_tasks, 'getID'); $batch_ids = implode(',', $batch_ids); $batch_uri = new PhutilURI('/maniphest/batch/'); $batch_uri->setQueryParam('board', $this->id); $batch_uri->setQueryParam('batch', $batch_ids); return id(new AphrontRedirectResponse()) ->setURI($batch_uri); } $board_id = celerity_generate_unique_node_id(); $board = id(new PHUIWorkboardView()) ->setUser($viewer) ->setID($board_id) ->addSigil('jx-workboard') ->setMetadata( array( 'boardPHID' => $project->getPHID(), )); $visible_columns = array(); $column_phids = array(); $visible_phids = array(); foreach ($columns as $column) { if (!$this->showHidden) { if ($column->isHidden()) { continue; } } $proxy = $column->getProxy(); if ($proxy && !$proxy->isMilestone()) { // TODO: For now, don't show subproject columns because we can't // handle tasks with multiple positions yet. continue; } $task_phids = $layout_engine->getColumnObjectPHIDs( $board_phid, $column->getPHID()); $column_tasks = array_select_keys($tasks, $task_phids); // If we aren't using "natural" order, reorder the column by the original // query order. if ($this->sortKey != PhabricatorProjectColumn::ORDER_NATURAL) { $column_tasks = array_select_keys($column_tasks, array_keys($tasks)); } $column_phid = $column->getPHID(); $visible_columns[$column_phid] = $column; $column_phids[$column_phid] = $column_tasks; foreach ($column_tasks as $phid => $task) { $visible_phids[$phid] = $phid; } } $rendering_engine = id(new PhabricatorBoardRenderingEngine()) ->setViewer($viewer) ->setObjects(array_select_keys($tasks, $visible_phids)) ->setEditMap($task_can_edit_map) ->setExcludedProjectPHIDs($select_phids); $templates = array(); $column_maps = array(); $all_tasks = array(); foreach ($visible_columns as $column_phid => $column) { $column_tasks = $column_phids[$column_phid]; $panel = id(new PHUIWorkpanelView()) ->setHeader($column->getDisplayName()) ->setSubHeader($column->getDisplayType()) ->addSigil('workpanel'); $proxy = $column->getProxy(); if ($proxy) { $proxy_id = $proxy->getID(); $href = $this->getApplicationURI("view/{$proxy_id}/"); $panel->setHref($href); } $header_icon = $column->getHeaderIcon(); if ($header_icon) { $panel->setHeaderIcon($header_icon); } $display_class = $column->getDisplayClass(); if ($display_class) { $panel->addClass($display_class); } if ($column->isHidden()) { $panel->addClass('project-panel-hidden'); } $column_menu = $this->buildColumnMenu($project, $column); $panel->addHeaderAction($column_menu); $count_tag = id(new PHUITagView()) ->setType(PHUITagView::TYPE_SHADE) ->setShade(PHUITagView::COLOR_BLUE) ->addSigil('column-points') ->setName( javelin_tag( 'span', array( 'sigil' => 'column-points-content', ), pht('-'))) ->setStyle('display: none'); $panel->setHeaderTag($count_tag); $cards = id(new PHUIObjectItemListView()) ->setUser($viewer) ->setFlush(true) ->setAllowEmptyList(true) ->addSigil('project-column') ->setItemClass('phui-workcard') ->setMetadata( array( 'columnPHID' => $column->getPHID(), 'pointLimit' => $column->getPointLimit(), )); foreach ($column_tasks as $task) { $object_phid = $task->getPHID(); $card = $rendering_engine->renderCard($object_phid); $templates[$object_phid] = hsprintf('%s', $card->getItem()); $column_maps[$column_phid][] = $object_phid; $all_tasks[$object_phid] = $task; } $panel->setCards($cards); $board->addPanel($panel); } $behavior_config = array( 'moveURI' => $this->getApplicationURI('move/'.$project->getID().'/'), 'createURI' => $this->getCreateURI(), 'uploadURI' => '/file/dropupload/', 'coverURI' => $this->getApplicationURI('cover/'), 'chunkThreshold' => PhabricatorFileStorageEngine::getChunkThreshold(), 'pointsEnabled' => ManiphestTaskPoints::getIsEnabled(), 'boardPHID' => $project->getPHID(), 'order' => $this->sortKey, 'templateMap' => $templates, 'columnMaps' => $column_maps, 'orderMaps' => mpull($all_tasks, 'getWorkboardOrderVectors'), 'propertyMaps' => mpull($all_tasks, 'getWorkboardProperties'), 'boardID' => $board_id, 'projectPHID' => $project->getPHID(), ); $this->initBehavior('project-boards', $behavior_config); $sort_menu = $this->buildSortMenu( $viewer, $project, $this->sortKey); $filter_menu = $this->buildFilterMenu( $viewer, $project, $custom_query, $search_engine, $query_key); $manage_menu = $this->buildManageMenu($project, $this->showHidden); $header_link = phutil_tag( 'a', array( 'href' => $this->getApplicationURI('profile/'.$project->getID().'/'), ), $project->getName()); $board_box = id(new PHUIBoxView()) ->appendChild($board) ->addClass('project-board-wrapper'); $nav = $this->getProfileMenu(); $divider = id(new PHUIListItemView()) ->setType(PHUIListItemView::TYPE_DIVIDER); $fullscreen = $this->buildFullscreenMenu(); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb(pht('Workboard')); $crumbs->setBorder(true); $crumbs->addAction($sort_menu); $crumbs->addAction($filter_menu); $crumbs->addAction($divider); $crumbs->addAction($manage_menu); $crumbs->addAction($fullscreen); $page = $this->newPage() ->setTitle( array( $project->getDisplayName(), pht('Workboard'), )) ->setPageObjectPHIDs(array($project->getPHID())) ->setShowFooter(false) ->setNavigation($nav) ->setCrumbs($crumbs) ->addQuicksandConfig( array( 'boardConfig' => $behavior_config, )) ->appendChild( array( $board_box, )); $background = $project->getDisplayWorkboardBackgroundColor(); if ($background !== null) { require_celerity_resource('phui-workboard-color-css'); $background_color_class = "phui-workboard-{$background}"; - $page->addFrameClass('phui-workboard-color'); - $page->addFrameClass($background_color_class); + $page->addClass('phui-workboard-color'); + $page->addClass($background_color_class); } return $page; } private function readRequestState() { $request = $this->getRequest(); $project = $this->getProject(); $this->showHidden = $request->getBool('hidden'); $this->id = $project->getID(); $sort_key = $this->getDefaultSort($project); $request_sort = $request->getStr('order'); if ($this->isValidSort($request_sort)) { $sort_key = $request_sort; } $this->sortKey = $sort_key; } private function getDefaultSort(PhabricatorProject $project) { $default_sort = $project->getDefaultWorkboardSort(); if ($this->isValidSort($default_sort)) { return $default_sort; } return PhabricatorProjectColumn::DEFAULT_ORDER; } private function getDefaultFilter(PhabricatorProject $project) { $default_filter = $project->getDefaultWorkboardFilter(); if (strlen($default_filter)) { return $default_filter; } return 'open'; } private function isValidSort($sort) { switch ($sort) { case PhabricatorProjectColumn::ORDER_NATURAL: case PhabricatorProjectColumn::ORDER_PRIORITY: return true; } return false; } private function buildSortMenu( PhabricatorUser $viewer, PhabricatorProject $project, $sort_key) { $sort_icon = id(new PHUIIconView()) ->setIcon('fa-sort-amount-asc bluegrey'); $named = array( PhabricatorProjectColumn::ORDER_NATURAL => pht('Natural'), PhabricatorProjectColumn::ORDER_PRIORITY => pht('Sort by Priority'), ); $base_uri = $this->getURIWithState(); $items = array(); foreach ($named as $key => $name) { $is_selected = ($key == $sort_key); if ($is_selected) { $active_order = $name; } $item = id(new PhabricatorActionView()) ->setIcon('fa-sort-amount-asc') ->setSelected($is_selected) ->setName($name); $uri = $base_uri->alter('order', $key); $item->setHref($uri); $items[] = $item; } $id = $project->getID(); $save_uri = "default/{$id}/sort/"; $save_uri = $this->getApplicationURI($save_uri); $save_uri = $this->getURIWithState($save_uri, $force = true); $can_edit = PhabricatorPolicyFilter::hasCapability( $viewer, $project, PhabricatorPolicyCapability::CAN_EDIT); $items[] = id(new PhabricatorActionView()) ->setIcon('fa-floppy-o') ->setName(pht('Save as Default')) ->setHref($save_uri) ->setWorkflow(true) ->setDisabled(!$can_edit); $sort_menu = id(new PhabricatorActionListView()) ->setUser($viewer); foreach ($items as $item) { $sort_menu->addAction($item); } $sort_button = id(new PHUIListItemView()) ->setName($active_order) ->setIcon('fa-sort-amount-asc') ->setHref('#') ->addSigil('boards-dropdown-menu') ->setMetadata( array( 'items' => hsprintf('%s', $sort_menu), )); return $sort_button; } private function buildFilterMenu( PhabricatorUser $viewer, PhabricatorProject $project, $custom_query, PhabricatorApplicationSearchEngine $engine, $query_key) { $named = array( 'open' => pht('Open Tasks'), 'all' => pht('All Tasks'), ); if ($viewer->isLoggedIn()) { $named['assigned'] = pht('Assigned to Me'); } if ($custom_query) { $named[$custom_query->getQueryKey()] = pht('Custom Filter'); } $items = array(); foreach ($named as $key => $name) { $is_selected = ($key == $query_key); if ($is_selected) { $active_filter = $name; } $is_custom = false; if ($custom_query) { $is_custom = ($key == $custom_query->getQueryKey()); } $item = id(new PhabricatorActionView()) ->setIcon('fa-search') ->setSelected($is_selected) ->setName($name); if ($is_custom) { $uri = $this->getApplicationURI( 'board/'.$this->id.'/filter/query/'.$key.'/'); $item->setWorkflow(true); } else { $uri = $engine->getQueryResultsPageURI($key); } $uri = $this->getURIWithState($uri) ->setQueryParam('filter', null); $item->setHref($uri); $items[] = $item; } $id = $project->getID(); $filter_uri = $this->getApplicationURI("board/{$id}/filter/"); $filter_uri = $this->getURIWithState($filter_uri, $force = true); $items[] = id(new PhabricatorActionView()) ->setIcon('fa-cog') ->setHref($filter_uri) ->setWorkflow(true) ->setName(pht('Advanced Filter...')); $save_uri = "default/{$id}/filter/"; $save_uri = $this->getApplicationURI($save_uri); $save_uri = $this->getURIWithState($save_uri, $force = true); $can_edit = PhabricatorPolicyFilter::hasCapability( $viewer, $project, PhabricatorPolicyCapability::CAN_EDIT); $items[] = id(new PhabricatorActionView()) ->setIcon('fa-floppy-o') ->setName(pht('Save as Default')) ->setHref($save_uri) ->setWorkflow(true) ->setDisabled(!$can_edit); $filter_menu = id(new PhabricatorActionListView()) ->setUser($viewer); foreach ($items as $item) { $filter_menu->addAction($item); } $filter_button = id(new PHUIListItemView()) ->setName($active_filter) ->setIcon('fa-search') ->setHref('#') ->addSigil('boards-dropdown-menu') ->setMetadata( array( 'items' => hsprintf('%s', $filter_menu), )); return $filter_button; } private function buildManageMenu( PhabricatorProject $project, $show_hidden) { $request = $this->getRequest(); $viewer = $request->getUser(); $id = $project->getID(); $manage_uri = $this->getApplicationURI("board/{$id}/manage/"); $add_uri = $this->getApplicationURI("board/{$id}/edit/"); $can_edit = PhabricatorPolicyFilter::hasCapability( $viewer, $project, PhabricatorPolicyCapability::CAN_EDIT); $manage_items = array(); $manage_items[] = id(new PhabricatorActionView()) ->setIcon('fa-plus') ->setName(pht('Add Column')) ->setHref($add_uri) ->setDisabled(!$can_edit) ->setWorkflow(true); $manage_items[] = id(new PhabricatorActionView()) ->setIcon('fa-pencil') ->setName(pht('Manage Board')) ->setHref($manage_uri); if ($show_hidden) { $hidden_uri = $this->getURIWithState() ->setQueryParam('hidden', null); $hidden_icon = 'fa-eye-slash'; $hidden_text = pht('Hide Hidden Columns'); } else { $hidden_uri = $this->getURIWithState() ->setQueryParam('hidden', 'true'); $hidden_icon = 'fa-eye'; $hidden_text = pht('Show Hidden Columns'); } $manage_items[] = id(new PhabricatorActionView()) ->setIcon($hidden_icon) ->setName($hidden_text) ->setHref($hidden_uri); $batch_edit_uri = $request->getRequestURI(); $batch_edit_uri->setQueryParam('batch', self::BATCH_EDIT_ALL); $can_batch_edit = PhabricatorPolicyFilter::hasCapability( $viewer, PhabricatorApplication::getByClass('PhabricatorManiphestApplication'), ManiphestBulkEditCapability::CAPABILITY); $manage_items[] = id(new PhabricatorActionView()) ->setIcon('fa-list-ul') ->setName(pht('Batch Edit Visible Tasks...')) ->setHref($batch_edit_uri) ->setDisabled(!$can_batch_edit); $manage_menu = id(new PhabricatorActionListView()) ->setUser($viewer); foreach ($manage_items as $item) { $manage_menu->addAction($item); } $manage_button = id(new PHUIListItemView()) ->setIcon('fa-cog') ->setHref('#') ->addSigil('boards-dropdown-menu') ->addSigil('has-tooltip') ->setMetadata( array( 'tip' => pht('Manage'), 'align' => 'S', 'items' => hsprintf('%s', $manage_menu), )); return $manage_button; } private function buildFullscreenMenu() { $up = id(new PHUIListItemView()) ->setIcon('fa-arrows-alt') ->setHref('#') ->addClass('phui-workboard-expand-icon') ->addSigil('jx-toggle-class') ->addSigil('has-tooltip') ->setMetaData(array( 'tip' => pht('Fullscreen'), 'map' => array( 'phabricator-standard-page' => 'phui-workboard-fullscreen', ), )); return $up; } private function buildColumnMenu( PhabricatorProject $project, PhabricatorProjectColumn $column) { $request = $this->getRequest(); $viewer = $request->getUser(); $can_edit = PhabricatorPolicyFilter::hasCapability( $viewer, $project, PhabricatorPolicyCapability::CAN_EDIT); $column_items = array(); if ($column->getProxyPHID()) { $default_phid = $column->getProxyPHID(); } else { $default_phid = $column->getProjectPHID(); } $column_items[] = id(new PhabricatorActionView()) ->setIcon('fa-plus') ->setName(pht('Create Task...')) ->setHref($this->getCreateURI()) ->addSigil('column-add-task') ->setMetadata( array( 'columnPHID' => $column->getPHID(), 'boardPHID' => $project->getPHID(), 'projectPHID' => $default_phid, )); $batch_edit_uri = $request->getRequestURI(); $batch_edit_uri->setQueryParam('batch', $column->getID()); $can_batch_edit = PhabricatorPolicyFilter::hasCapability( $viewer, PhabricatorApplication::getByClass('PhabricatorManiphestApplication'), ManiphestBulkEditCapability::CAPABILITY); $column_items[] = id(new PhabricatorActionView()) ->setIcon('fa-list-ul') ->setName(pht('Batch Edit Tasks...')) ->setHref($batch_edit_uri) ->setDisabled(!$can_batch_edit); $can_hide = ($can_edit && !$column->isDefaultColumn()); $hide_uri = 'board/'.$this->id.'/hide/'.$column->getID().'/'; $hide_uri = $this->getApplicationURI($hide_uri); $hide_uri = $this->getURIWithState($hide_uri); if (!$column->isHidden()) { $column_items[] = id(new PhabricatorActionView()) ->setName(pht('Hide Column')) ->setIcon('fa-eye-slash') ->setHref($hide_uri) ->setDisabled(!$can_hide) ->setWorkflow(true); } else { $column_items[] = id(new PhabricatorActionView()) ->setName(pht('Show Column')) ->setIcon('fa-eye') ->setHref($hide_uri) ->setDisabled(!$can_hide) ->setWorkflow(true); } $column_menu = id(new PhabricatorActionListView()) ->setUser($viewer); foreach ($column_items as $item) { $column_menu->addAction($item); } $column_button = id(new PHUIIconView()) ->setIcon('fa-caret-down') ->setHref('#') ->addSigil('boards-dropdown-menu') ->setMetadata( array( 'items' => hsprintf('%s', $column_menu), )); return $column_button; } /** * Add current state parameters (like order and the visibility of hidden * columns) to a URI. * * This allows actions which toggle or adjust one piece of state to keep * the rest of the board state persistent. If no URI is provided, this method * starts with the request URI. * * @param string|null URI to add state parameters to. * @param bool True to explicitly include all state. * @return PhutilURI URI with state parameters. */ private function getURIWithState($base = null, $force = false) { $project = $this->getProject(); if ($base === null) { $base = $this->getRequest()->getRequestURI(); } $base = new PhutilURI($base); if ($force || ($this->sortKey != $this->getDefaultSort($project))) { $base->setQueryParam('order', $this->sortKey); } else { $base->setQueryParam('order', null); } if ($force || ($this->queryKey != $this->getDefaultFilter($project))) { $base->setQueryParam('filter', $this->queryKey); } else { $base->setQueryParam('filter', null); } $base->setQueryParam('hidden', $this->showHidden ? 'true' : null); return $base; } private function getCreateURI() { $viewer = $this->getViewer(); // TODO: This should be cleaned up, but maybe we're going to make options // for each column or board? $edit_config = id(new ManiphestEditEngine()) ->setViewer($viewer) ->loadDefaultEditConfiguration(); if ($edit_config) { $form_key = $edit_config->getIdentifier(); $create_uri = "/maniphest/task/edit/form/{$form_key}/"; } else { $create_uri = '/maniphest/task/edit/'; } return $create_uri; } private function buildInitializeContent(PhabricatorProject $project) { $request = $this->getRequest(); $viewer = $this->getViewer(); $type = $request->getStr('initialize-type'); $id = $project->getID(); $profile_uri = $this->getApplicationURI("profile/{$id}/"); $board_uri = $this->getApplicationURI("board/{$id}/"); $import_uri = $this->getApplicationURI("board/{$id}/import/"); $set_default = $request->getBool('default'); if ($set_default) { $this ->getProfilePanelEngine() ->adjustDefault(PhabricatorProject::PANEL_WORKBOARD); } if ($request->isFormPost()) { if ($type == 'backlog-only') { $column = PhabricatorProjectColumn::initializeNewColumn($viewer) ->setSequence(0) ->setProperty('isDefault', true) ->setProjectPHID($project->getPHID()) ->save(); $project->setHasWorkboard(1)->save(); return id(new AphrontRedirectResponse()) ->setURI($board_uri); } else { return id(new AphrontRedirectResponse()) ->setURI($import_uri); } } // TODO: Tailor this UI if the project is already a parent project. We // should not offer options for creating a parent project workboard, since // they can't have their own columns. $new_selector = id(new AphrontFormRadioButtonControl()) ->setLabel(pht('Columns')) ->setName('initialize-type') ->setValue('backlog-only') ->addButton( 'backlog-only', pht('New Empty Board'), pht('Create a new board with just a backlog column.')) ->addButton( 'import', pht('Import Columns'), pht('Import board columns from another project.')); $default_checkbox = id(new AphrontFormCheckboxControl()) ->setLabel(pht('Make Default')) ->addCheckbox( 'default', 1, pht('Make the workboard the default view for this project.'), true); $form = id(new AphrontFormView()) ->setUser($viewer) ->addHiddenInput('initialize', 1) ->appendRemarkupInstructions( pht('The workboard for this project has not been created yet.')) ->appendControl($new_selector) ->appendControl($default_checkbox) ->appendControl( id(new AphrontFormSubmitControl()) ->addCancelButton($profile_uri) ->setValue(pht('Create Workboard'))); $box = id(new PHUIObjectBoxView()) ->setHeaderText(pht('Create Workboard')) ->setForm($form); return $box; } private function buildNoAccessContent(PhabricatorProject $project) { $viewer = $this->getViewer(); $id = $project->getID(); $profile_uri = $this->getApplicationURI("profile/{$id}/"); return $this->newDialog() ->setTitle(pht('Unable to Create Workboard')) ->appendParagraph( pht( 'The workboard for this project has not been created yet, '. 'but you do not have permission to create it. Only users '. 'who can edit this project can create a workboard for it.')) ->addCancelButton($profile_uri); } private function buildEnableContent(PhabricatorProject $project) { $request = $this->getRequest(); $viewer = $this->getViewer(); $id = $project->getID(); $profile_uri = $this->getApplicationURI("profile/{$id}/"); $board_uri = $this->getApplicationURI("board/{$id}/"); if ($request->isFormPost()) { $xactions = array(); $xactions[] = id(new PhabricatorProjectTransaction()) ->setTransactionType(PhabricatorProjectTransaction::TYPE_HASWORKBOARD) ->setNewValue(1); id(new PhabricatorProjectTransactionEditor()) ->setActor($viewer) ->setContentSourceFromRequest($request) ->setContinueOnNoEffect(true) ->setContinueOnMissingFields(true) ->applyTransactions($project, $xactions); return id(new AphrontRedirectResponse()) ->setURI($board_uri); } return $this->newDialog() ->setTitle(pht('Workboard Disabled')) ->addHiddenInput('initialize', 1) ->appendParagraph( pht( 'This workboard has been disabled, but can be restored to its '. 'former glory.')) ->addCancelButton($profile_uri) ->addSubmitButton(pht('Enable Workboard')); } private function buildDisabledContent(PhabricatorProject $project) { $viewer = $this->getViewer(); $id = $project->getID(); $profile_uri = $this->getApplicationURI("profile/{$id}/"); return $this->newDialog() ->setTitle(pht('Workboard Disabled')) ->appendParagraph( pht( 'This workboard has been disabled, and you do not have permission '. 'to enable it. Only users who can edit this project can restore '. 'the workboard.')) ->addCancelButton($profile_uri); } } diff --git a/src/applications/search/controller/PhabricatorApplicationSearchController.php b/src/applications/search/controller/PhabricatorApplicationSearchController.php index 818f16d055..d36d279c55 100644 --- a/src/applications/search/controller/PhabricatorApplicationSearchController.php +++ b/src/applications/search/controller/PhabricatorApplicationSearchController.php @@ -1,500 +1,500 @@ preface = $preface; return $this; } public function getPreface() { return $this->preface; } public function setQueryKey($query_key) { $this->queryKey = $query_key; return $this; } protected function getQueryKey() { return $this->queryKey; } public function setNavigation(AphrontSideNavFilterView $navigation) { $this->navigation = $navigation; return $this; } protected function getNavigation() { return $this->navigation; } public function setSearchEngine( PhabricatorApplicationSearchEngine $search_engine) { $this->searchEngine = $search_engine; return $this; } protected function getSearchEngine() { return $this->searchEngine; } protected function validateDelegatingController() { $parent = $this->getDelegatingController(); if (!$parent) { throw new Exception( pht('You must delegate to this controller, not invoke it directly.')); } $engine = $this->getSearchEngine(); if (!$engine) { throw new PhutilInvalidStateException('setEngine'); } $engine->setViewer($this->getRequest()->getUser()); $parent = $this->getDelegatingController(); } public function processRequest() { $this->validateDelegatingController(); $key = $this->getQueryKey(); if ($key == 'edit') { return $this->processEditRequest(); } else { return $this->processSearchRequest(); } } private function processSearchRequest() { $parent = $this->getDelegatingController(); $request = $this->getRequest(); $user = $request->getUser(); $engine = $this->getSearchEngine(); $nav = $this->getNavigation(); if (!$nav) { $nav = $this->buildNavigation(); } if ($request->isFormPost()) { $saved_query = $engine->buildSavedQueryFromRequest($request); $engine->saveQuery($saved_query); return id(new AphrontRedirectResponse())->setURI( $engine->getQueryResultsPageURI($saved_query->getQueryKey()).'#R'); } $named_query = null; $run_query = true; $query_key = $this->queryKey; if ($this->queryKey == 'advanced') { $run_query = false; $query_key = $request->getStr('query'); } else if (!strlen($this->queryKey)) { $found_query_data = false; if ($request->isHTTPGet() || $request->isQuicksand()) { // If this is a GET request and it has some query data, don't // do anything unless it's only before= or after=. We'll build and // execute a query from it below. This allows external tools to build // URIs like "/query/?users=a,b". $pt_data = $request->getPassthroughRequestData(); $exempt = array( 'before' => true, 'after' => true, 'nux' => true, ); foreach ($pt_data as $pt_key => $pt_value) { if (isset($exempt[$pt_key])) { continue; } $found_query_data = true; break; } } if (!$found_query_data) { // Otherwise, there's no query data so just run the user's default // query for this application. $query_key = head_key($engine->loadEnabledNamedQueries()); } } if ($engine->isBuiltinQuery($query_key)) { $saved_query = $engine->buildSavedQueryFromBuiltin($query_key); $named_query = idx($engine->loadEnabledNamedQueries(), $query_key); } else if ($query_key) { $saved_query = id(new PhabricatorSavedQueryQuery()) ->setViewer($user) ->withQueryKeys(array($query_key)) ->executeOne(); if (!$saved_query) { return new Aphront404Response(); } $named_query = idx($engine->loadEnabledNamedQueries(), $query_key); } else { $saved_query = $engine->buildSavedQueryFromRequest($request); // Save the query to generate a query key, so "Save Custom Query..." and // other features like Maniphest's "Export..." work correctly. $engine->saveQuery($saved_query); } $nav->selectFilter( 'query/'.$saved_query->getQueryKey(), 'query/advanced'); $form = id(new AphrontFormView()) ->setUser($user) ->setAction($request->getPath()); $engine->buildSearchForm($form, $saved_query); $errors = $engine->getErrors(); if ($errors) { $run_query = false; } $submit = id(new AphrontFormSubmitControl()) ->setValue(pht('Execute Query')); if ($run_query && !$named_query && $user->isLoggedIn()) { $submit->addCancelButton( '/search/edit/'.$saved_query->getQueryKey().'/', pht('Save Custom Query...')); } // TODO: A "Create Dashboard Panel" action goes here somewhere once // we sort out T5307. $form->appendChild($submit); $body = array(); if ($this->getPreface()) { $body[] = $this->getPreface(); } if ($named_query) { $title = $named_query->getQueryName(); } else { $title = pht('Advanced Search'); } $header = id(new PHUIHeaderView()) ->setHeader($title) ->setProfileHeader(true); $box = id(new PHUIObjectBoxView()) ->setHeader($header) ->addClass('application-search-results'); if ($run_query || $named_query) { $box->setShowHide( pht('Edit Query'), pht('Hide Query'), $form, $this->getApplicationURI('query/advanced/?query='.$query_key), (!$named_query ? true : false)); } else { $box->setForm($form); } $body[] = $box; $more_crumbs = null; if ($run_query) { $exec_errors = array(); $box->setAnchor( id(new PhabricatorAnchorView()) ->setAnchorName('R')); try { $engine->setRequest($request); $query = $engine->buildQueryFromSavedQuery($saved_query); $pager = $engine->newPagerForSavedQuery($saved_query); $pager->readFromRequest($request); $objects = $engine->executeQuery($query, $pager); $force_nux = $request->getBool('nux'); if (!$objects || $force_nux) { $nux_view = $this->renderNewUserView($engine, $force_nux); } else { $nux_view = null; } if ($nux_view) { $box->appendChild($nux_view); } else { $list = $engine->renderResults($objects, $saved_query); if (!($list instanceof PhabricatorApplicationSearchResultView)) { throw new Exception( pht( 'SearchEngines must render a "%s" object, but this engine '. '(of class "%s") rendered something else.', 'PhabricatorApplicationSearchResultView', get_class($engine))); } if ($list->getActions()) { foreach ($list->getActions() as $action) { $header->addActionLink($action); } } if ($list->getObjectList()) { $box->setObjectList($list->getObjectList()); } if ($list->getTable()) { $box->setTable($list->getTable()); } if ($list->getInfoView()) { $box->setInfoView($list->getInfoView()); } if ($list->getContent()) { $box->appendChild($list->getContent()); } $result_header = $list->getHeader(); if ($result_header) { $box->setHeader($result_header); } $more_crumbs = $list->getCrumbs(); if ($pager->willShowPagingControls()) { $pager_box = id(new PHUIBoxView()) ->setColor(PHUIBoxView::GREY) ->addClass('application-search-pager') ->appendChild($pager); $body[] = $pager_box; } } } catch (PhabricatorTypeaheadInvalidTokenException $ex) { $exec_errors[] = pht( 'This query specifies an invalid parameter. Review the '. 'query parameters and correct errors.'); } // The engine may have encountered additional errors during rendering; // merge them in and show everything. foreach ($engine->getErrors() as $error) { $exec_errors[] = $error; } $errors = $exec_errors; } if ($errors) { $box->setFormErrors($errors, pht('Query Errors')); } $crumbs = $parent ->buildApplicationCrumbs() ->setBorder(true); if ($more_crumbs) { $query_uri = $engine->getQueryResultsPageURI($saved_query->getQueryKey()); $crumbs->addTextCrumb($title, $query_uri); foreach ($more_crumbs as $crumb) { $crumbs->addCrumb($crumb); } } else { $crumbs->addTextCrumb($title); } + $nav->addClass('application-search-view'); require_celerity_resource('application-search-view-css'); return $this->newPage() ->setApplicationMenu($this->buildApplicationMenu()) ->setTitle(pht('Query: %s', $title)) ->setCrumbs($crumbs) ->setNavigation($nav) - ->addFrameClass('application-search-view') ->appendChild($body); } private function processEditRequest() { $parent = $this->getDelegatingController(); $request = $this->getRequest(); $user = $request->getUser(); $engine = $this->getSearchEngine(); $nav = $this->getNavigation(); if (!$nav) { $nav = $this->buildNavigation(); } $named_queries = $engine->loadAllNamedQueries(); $list_id = celerity_generate_unique_node_id(); $list = new PHUIObjectItemListView(); $list->setUser($user); $list->setID($list_id); Javelin::initBehavior( 'search-reorder-queries', array( 'listID' => $list_id, 'orderURI' => '/search/order/'.get_class($engine).'/', )); foreach ($named_queries as $named_query) { $class = get_class($engine); $key = $named_query->getQueryKey(); $item = id(new PHUIObjectItemView()) ->setHeader($named_query->getQueryName()) ->setHref($engine->getQueryResultsPageURI($key)); if ($named_query->getIsBuiltin() && $named_query->getIsDisabled()) { $icon = 'fa-plus'; } else { $icon = 'fa-times'; } $item->addAction( id(new PHUIListItemView()) ->setIcon($icon) ->setHref('/search/delete/'.$key.'/'.$class.'/') ->setWorkflow(true)); if ($named_query->getIsBuiltin()) { if ($named_query->getIsDisabled()) { $item->addIcon('fa-times lightgreytext', pht('Disabled')); $item->setDisabled(true); } else { $item->addIcon('fa-lock lightgreytext', pht('Builtin')); } } else { $item->addAction( id(new PHUIListItemView()) ->setIcon('fa-pencil') ->setHref('/search/edit/'.$key.'/')); } $item->setGrippable(true); $item->addSigil('named-query'); $item->setMetadata( array( 'queryKey' => $named_query->getQueryKey(), )); $list->addItem($item); } $list->setNoDataString(pht('No saved queries.')); $crumbs = $parent ->buildApplicationCrumbs() ->addTextCrumb(pht('Saved Queries'), $engine->getQueryManagementURI()) ->setBorder(true); $nav->selectFilter('query/edit'); $header = id(new PHUIHeaderView()) ->setHeader(pht('Saved Queries')) ->setProfileHeader(true); $box = id(new PHUIObjectBoxView()) ->setHeader($header) ->setObjectList($list) ->addClass('application-search-results'); + $nav->addClass('application-search-view'); require_celerity_resource('application-search-view-css'); return $this->newPage() ->setApplicationMenu($this->buildApplicationMenu()) ->setTitle(pht('Saved Queries')) ->setCrumbs($crumbs) ->setNavigation($nav) - ->addFrameClass('application-search-view') ->appendChild($box); } public function buildApplicationMenu() { $menu = $this->getDelegatingController() ->buildApplicationMenu(); if ($menu instanceof PHUIApplicationMenuView) { $menu->setSearchEngine($this->getSearchEngine()); } return $menu; } private function buildNavigation() { $viewer = $this->getViewer(); $engine = $this->getSearchEngine(); $nav = id(new AphrontSideNavFilterView()) ->setUser($viewer) ->setBaseURI(new PhutilURI($this->getApplicationURI())); $engine->addNavigationItems($nav->getMenu()); return $nav; } private function renderNewUserView( PhabricatorApplicationSearchEngine $engine, $force_nux) { // Don't render NUX if the user has clicked away from the default page. if (strlen($this->getQueryKey())) { return null; } // Don't put NUX in panels because it would be weird. if ($engine->isPanelContext()) { return null; } // Try to render the view itself first, since this should be very cheap // (just returning some text). $nux_view = $engine->renderNewUserView(); if (!$nux_view) { return null; } $query = $engine->newQuery(); if (!$query) { return null; } // Try to load any object at all. If we can, the application has seen some // use so we just render the normal view. if (!$force_nux) { $object = $query ->setViewer(PhabricatorUser::getOmnipotentUser()) ->setLimit(1) ->execute(); if ($object) { return null; } } return $nux_view; } } diff --git a/src/view/page/PhabricatorStandardPageView.php b/src/view/page/PhabricatorStandardPageView.php index 53603c2eb6..dc2dfe186e 100644 --- a/src/view/page/PhabricatorStandardPageView.php +++ b/src/view/page/PhabricatorStandardPageView.php @@ -1,905 +1,891 @@ showFooter = $show_footer; return $this; } public function getShowFooter() { return $this->showFooter; } public function setApplicationMenu($application_menu) { // NOTE: For now, this can either be a PHUIListView or a // PHUIApplicationMenuView. $this->applicationMenu = $application_menu; return $this; } public function getApplicationMenu() { return $this->applicationMenu; } public function setApplicationName($application_name) { $this->applicationName = $application_name; return $this; } public function setDisableConsole($disable) { $this->disableConsole = $disable; return $this; } public function getApplicationName() { return $this->applicationName; } public function setBaseURI($base_uri) { $this->baseURI = $base_uri; return $this; } public function getBaseURI() { return $this->baseURI; } public function setShowChrome($show_chrome) { $this->showChrome = $show_chrome; return $this; } public function getShowChrome() { return $this->showChrome; } public function addClass($class) { $this->classes[] = $class; return $this; } - public function addFrameClass($class) { - $this->frameClasses[] = $class; - return $this; - } - public function setPageObjectPHIDs(array $phids) { $this->pageObjects = $phids; return $this; } public function setShowDurableColumn($show) { $this->showDurableColumn = $show; return $this; } public function getShowDurableColumn() { $request = $this->getRequest(); if (!$request) { return false; } $viewer = $request->getUser(); if (!$viewer->isLoggedIn()) { return false; } $conpherence_installed = PhabricatorApplication::isClassInstalledForViewer( 'PhabricatorConpherenceApplication', $viewer); if (!$conpherence_installed) { return false; } if ($this->isQuicksandBlacklistURI()) { return false; } return true; } private function isQuicksandBlacklistURI() { $request = $this->getRequest(); if (!$request) { return false; } $patterns = $this->getQuicksandURIPatternBlacklist(); $path = $request->getRequestURI()->getPath(); foreach ($patterns as $pattern) { if (preg_match('(^'.$pattern.'$)', $path)) { return true; } } return false; } public function getDurableColumnVisible() { $column_key = PhabricatorConpherenceColumnVisibleSetting::SETTINGKEY; return (bool)$this->getUserPreference($column_key, false); } public function getDurableColumnMinimize() { $column_key = PhabricatorConpherenceColumnMinimizeSetting::SETTINGKEY; return (bool)$this->getUserPreference($column_key, false); } public function addQuicksandConfig(array $config) { $this->quicksandConfig = $config + $this->quicksandConfig; return $this; } public function getQuicksandConfig() { return $this->quicksandConfig; } public function setCrumbs(PHUICrumbsView $crumbs) { $this->crumbs = $crumbs; return $this; } public function getCrumbs() { return $this->crumbs; } public function setNavigation(AphrontSideNavFilterView $navigation) { $this->navigation = $navigation; return $this; } public function getNavigation() { return $this->navigation; } public function getTitle() { $glyph_key = PhabricatorTitleGlyphsSetting::SETTINGKEY; $glyph_on = PhabricatorTitleGlyphsSetting::VALUE_TITLE_GLYPHS; $glyph_setting = $this->getUserPreference($glyph_key, $glyph_on); $use_glyph = ($glyph_setting == $glyph_on); $title = parent::getTitle(); $prefix = null; if ($use_glyph) { $prefix = $this->getGlyph(); } else { $application_name = $this->getApplicationName(); if (strlen($application_name)) { $prefix = '['.$application_name.']'; } } if (strlen($prefix)) { $title = $prefix.' '.$title; } return $title; } protected function willRenderPage() { parent::willRenderPage(); if (!$this->getRequest()) { throw new Exception( pht( 'You must set the %s to render a %s.', 'Request', __CLASS__)); } $console = $this->getConsole(); require_celerity_resource('phabricator-core-css'); require_celerity_resource('phabricator-zindex-css'); require_celerity_resource('phui-button-css'); require_celerity_resource('phui-spacing-css'); require_celerity_resource('phui-form-css'); require_celerity_resource('phabricator-standard-page-view'); require_celerity_resource('conpherence-durable-column-view'); require_celerity_resource('font-lato'); require_celerity_resource('font-aleo'); Javelin::initBehavior('workflow', array()); $request = $this->getRequest(); $user = null; if ($request) { $user = $request->getUser(); } if ($user) { if ($user->isUserActivated()) { $offset = $user->getTimeZoneOffset(); $ignore_key = PhabricatorTimezoneIgnoreOffsetSetting::SETTINGKEY; $ignore = $user->getUserSetting($ignore_key); Javelin::initBehavior( 'detect-timezone', array( 'offset' => $offset, 'uri' => '/settings/timezone/', 'message' => pht( 'Your browser timezone setting differs from the timezone '. 'setting in your profile, click to reconcile.'), 'ignoreKey' => $ignore_key, 'ignore' => $ignore, )); if ($user->getIsAdmin()) { $server_https = $request->isHTTPS(); $server_protocol = $server_https ? 'HTTPS' : 'HTTP'; $client_protocol = $server_https ? 'HTTP' : 'HTTPS'; $doc_name = 'Configuring a Preamble Script'; $doc_href = PhabricatorEnv::getDoclink($doc_name); Javelin::initBehavior( 'setup-check-https', array( 'server_https' => $server_https, 'doc_name' => pht('See Documentation'), 'doc_href' => $doc_href, 'message' => pht( 'Phabricator thinks you are using %s, but your '. 'client is conviced that it is using %s. This is a serious '. 'misconfiguration with subtle, but significant, consequences.', $server_protocol, $client_protocol), )); } } $default_img_uri = celerity_get_resource_uri( 'rsrc/image/icon/fatcow/document_black.png'); $download_form = phabricator_form( $user, array( 'action' => '#', 'method' => 'POST', 'class' => 'lightbox-download-form', 'sigil' => 'download', ), phutil_tag( 'button', array(), pht('Download'))); Javelin::initBehavior( 'lightbox-attachments', array( 'defaultImageUri' => $default_img_uri, 'downloadForm' => $download_form, )); } Javelin::initBehavior('aphront-form-disable-on-submit'); Javelin::initBehavior('toggle-class', array()); Javelin::initBehavior('history-install'); Javelin::initBehavior('phabricator-gesture'); $current_token = null; if ($user) { $current_token = $user->getCSRFToken(); } Javelin::initBehavior( 'refresh-csrf', array( 'tokenName' => AphrontRequest::getCSRFTokenName(), 'header' => AphrontRequest::getCSRFHeaderName(), 'viaHeader' => AphrontRequest::getViaHeaderName(), 'current' => $current_token, )); Javelin::initBehavior('device'); Javelin::initBehavior( 'high-security-warning', $this->getHighSecurityWarningConfig()); if (PhabricatorEnv::isReadOnly()) { Javelin::initBehavior( 'read-only-warning', array( 'message' => PhabricatorEnv::getReadOnlyMessage(), 'uri' => PhabricatorEnv::getReadOnlyURI(), )); } if ($console) { require_celerity_resource('aphront-dark-console-css'); $headers = array(); if (DarkConsoleXHProfPluginAPI::isProfilerStarted()) { $headers[DarkConsoleXHProfPluginAPI::getProfilerHeader()] = 'page'; } if (DarkConsoleServicesPlugin::isQueryAnalyzerRequested()) { $headers[DarkConsoleServicesPlugin::getQueryAnalyzerHeader()] = true; } Javelin::initBehavior( 'dark-console', $this->getConsoleConfig()); // Change this to initBehavior when there is some behavior to initialize require_celerity_resource('javelin-behavior-error-log'); } if ($user) { $viewer = $user; } else { $viewer = new PhabricatorUser(); } $menu = id(new PhabricatorMainMenuView()) ->setUser($viewer); if ($this->getController()) { $menu->setController($this->getController()); } $application_menu = $this->getApplicationMenu(); if ($application_menu) { if ($application_menu instanceof PHUIApplicationMenuView) { $crumbs = $this->getCrumbs(); if ($crumbs) { $application_menu->setCrumbs($crumbs); } $application_menu = $application_menu->buildListView(); } $menu->setApplicationMenu($application_menu); } $this->menuContent = $menu->render(); } protected function getHead() { $monospaced = null; $request = $this->getRequest(); if ($request) { $user = $request->getUser(); if ($user) { $monospaced = $user->getUserSetting( PhabricatorMonospacedFontSetting::SETTINGKEY); } } $response = CelerityAPI::getStaticResourceResponse(); $font_css = null; if (!empty($monospaced)) { // We can't print this normally because escaping quotation marks will // break the CSS. Instead, filter it strictly and then mark it as safe. $monospaced = new PhutilSafeHTML( PhabricatorMonospacedFontSetting::filterMonospacedCSSRule( $monospaced)); $font_css = hsprintf( '', $monospaced); } return hsprintf( '%s%s%s', parent::getHead(), $font_css, $response->renderSingleResource('javelin-magical-init', 'phabricator')); } public function setGlyph($glyph) { $this->glyph = $glyph; return $this; } public function getGlyph() { return $this->glyph; } protected function willSendResponse($response) { $request = $this->getRequest(); $response = parent::willSendResponse($response); $console = $request->getApplicationConfiguration()->getConsole(); if ($console) { $response = PhutilSafeHTML::applyFunction( 'str_replace', hsprintf(''), $console->render($request), $response); } return $response; } protected function getBody() { $user = null; $request = $this->getRequest(); if ($request) { $user = $request->getUser(); } $header_chrome = null; if ($this->getShowChrome()) { $header_chrome = $this->menuContent; } $classes = array(); $classes[] = 'main-page-frame'; $developer_warning = null; if (PhabricatorEnv::getEnvConfig('phabricator.developer-mode') && DarkConsoleErrorLogPluginAPI::getErrors()) { $developer_warning = phutil_tag_div( 'aphront-developer-error-callout', pht( 'This page raised PHP errors. Find them in DarkConsole '. 'or the error log.')); } $main_page = phutil_tag( 'div', array( 'id' => 'phabricator-standard-page', 'class' => 'phabricator-standard-page', ), array( $developer_warning, $header_chrome, phutil_tag( 'div', array( 'id' => 'phabricator-standard-page-body', 'class' => 'phabricator-standard-page-body', ), $this->renderPageBodyContent()), )); $durable_column = null; if ($this->getShowDurableColumn()) { $is_visible = $this->getDurableColumnVisible(); $is_minimize = $this->getDurableColumnMinimize(); $durable_column = id(new ConpherenceDurableColumnView()) ->setSelectedConpherence(null) ->setUser($user) ->setQuicksandConfig($this->buildQuicksandConfig()) ->setVisible($is_visible) ->setMinimize($is_minimize) ->setInitialLoad(true); if ($is_minimize) { $this->classes[] = 'minimize-column'; } } Javelin::initBehavior('quicksand-blacklist', array( 'patterns' => $this->getQuicksandURIPatternBlacklist(), )); return phutil_tag( 'div', array( 'class' => implode(' ', $classes), ), array( $main_page, $durable_column, )); } private function renderPageBodyContent() { $console = $this->getConsole(); $body = parent::getBody(); $footer = $this->renderFooter(); $nav = $this->getNavigation(); if ($nav) { $crumbs = $this->getCrumbs(); if ($crumbs) { $nav->setCrumbs($crumbs); } $nav->appendChild($body); $nav->appendFooter($footer); - $content = $nav; + $content = phutil_implode_html('', array($nav->render())); } else { $content = array(); $crumbs = $this->getCrumbs(); if ($crumbs) { $content[] = $crumbs; } $content[] = $body; $content[] = $footer; - } - - $frame_classes = $this->frameClasses; - $frame_classes[] = 'main-page-background'; - $content = phutil_tag( - 'div', - array( - 'class' => implode(' ', $frame_classes), - ), - $content); + $content = phutil_implode_html('', $content); + } return array( ($console ? hsprintf('') : null), $content, ); } protected function getTail() { $request = $this->getRequest(); $user = $request->getUser(); $tail = array( parent::getTail(), ); $response = CelerityAPI::getStaticResourceResponse(); if ($request->isHTTPS()) { $with_protocol = 'https'; } else { $with_protocol = 'http'; } $servers = PhabricatorNotificationServerRef::getEnabledClientServers( $with_protocol); if ($servers) { if ($user && $user->isLoggedIn()) { // TODO: We could tell the browser about all the servers and let it // do random reconnects to improve reliability. shuffle($servers); $server = head($servers); $client_uri = $server->getWebsocketURI(); Javelin::initBehavior( 'aphlict-listen', array( 'websocketURI' => (string)$client_uri, ) + $this->buildAphlictListenConfigData()); } } $tail[] = $response->renderHTMLFooter(); return $tail; } protected function getBodyClasses() { $classes = array(); if (!$this->getShowChrome()) { $classes[] = 'phabricator-chromeless-page'; } $agent = AphrontRequest::getHTTPHeader('User-Agent'); // Try to guess the device resolution based on UA strings to avoid a flash // of incorrectly-styled content. $device_guess = 'device-desktop'; if (preg_match('@iPhone|iPod|(Android.*Chrome/[.0-9]* Mobile)@', $agent)) { $device_guess = 'device-phone device'; } else if (preg_match('@iPad|(Android.*Chrome/)@', $agent)) { $device_guess = 'device-tablet device'; } $classes[] = $device_guess; if (preg_match('@Windows@', $agent)) { $classes[] = 'platform-windows'; } else if (preg_match('@Macintosh@', $agent)) { $classes[] = 'platform-mac'; } else if (preg_match('@X11@', $agent)) { $classes[] = 'platform-linux'; } if ($this->getRequest()->getStr('__print__')) { $classes[] = 'printable'; } if ($this->getRequest()->getStr('__aural__')) { $classes[] = 'audible'; } $classes[] = 'phui-theme-'.PhabricatorEnv::getEnvConfig('ui.header-color'); foreach ($this->classes as $class) { $classes[] = $class; } return implode(' ', $classes); } private function getConsole() { if ($this->disableConsole) { return null; } return $this->getRequest()->getApplicationConfiguration()->getConsole(); } private function getConsoleConfig() { $user = $this->getRequest()->getUser(); $headers = array(); if (DarkConsoleXHProfPluginAPI::isProfilerStarted()) { $headers[DarkConsoleXHProfPluginAPI::getProfilerHeader()] = 'page'; } if (DarkConsoleServicesPlugin::isQueryAnalyzerRequested()) { $headers[DarkConsoleServicesPlugin::getQueryAnalyzerHeader()] = true; } if ($user) { $setting_tab = PhabricatorDarkConsoleTabSetting::SETTINGKEY; $setting_visible = PhabricatorDarkConsoleVisibleSetting::SETTINGKEY; $tab = $user->getUserSetting($setting_tab); $visible = $user->getUserSetting($setting_visible); } else { $tab = null; $visible = true; } return array( // NOTE: We use a generic label here to prevent input reflection // and mitigate compression attacks like BREACH. See discussion in // T3684. 'uri' => pht('Main Request'), 'selected' => $tab, 'visible' => $visible, 'headers' => $headers, ); } private function getHighSecurityWarningConfig() { $user = $this->getRequest()->getUser(); $show = false; if ($user->hasSession()) { $hisec = ($user->getSession()->getHighSecurityUntil() - time()); if ($hisec > 0) { $show = true; } } return array( 'show' => $show, 'uri' => '/auth/session/downgrade/', 'message' => pht( 'Your session is in high security mode. When you '. 'finish using it, click here to leave.'), ); } private function renderFooter() { if (!$this->getShowChrome()) { return null; } if (!$this->getShowFooter()) { return null; } $items = PhabricatorEnv::getEnvConfig('ui.footer-items'); if (!$items) { return null; } $foot = array(); foreach ($items as $item) { $name = idx($item, 'name', pht('Unnamed Footer Item')); $href = idx($item, 'href'); if (!PhabricatorEnv::isValidURIForLink($href)) { $href = null; } if ($href !== null) { $tag = 'a'; } else { $tag = 'span'; } $foot[] = phutil_tag( $tag, array( 'href' => $href, ), $name); } $foot = phutil_implode_html(" \xC2\xB7 ", $foot); return phutil_tag( 'div', array( 'class' => 'phabricator-standard-page-footer grouped', ), $foot); } public function renderForQuicksand() { parent::willRenderPage(); $response = $this->renderPageBodyContent(); $response = $this->willSendResponse($response); $extra_config = $this->getQuicksandConfig(); return array( 'content' => hsprintf('%s', $response), ) + $this->buildQuicksandConfig() + $extra_config; } private function buildQuicksandConfig() { $viewer = $this->getRequest()->getUser(); $controller = $this->getController(); $dropdown_query = id(new AphlictDropdownDataQuery()) ->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; $console = $this->getConsole(); if ($console) { $console_config = $this->getConsoleConfig(); } $upload_enabled = false; if ($controller) { $upload_enabled = $controller->isGlobalDragAndDropUploadEnabled(); } $application_class = null; $application_search_icon = null; $controller = $this->getController(); if ($controller) { $application = $controller->getCurrentApplication(); if ($application) { $application_class = get_class($application); if ($application->getApplicationSearchDocumentTypes()) { $application_search_icon = $application->getIcon(); } } } return array( 'title' => $this->getTitle(), 'aphlictDropdownData' => array( $dropdown_query->getNotificationData(), $dropdown_query->getConpherenceData(), ), 'globalDragAndDrop' => $upload_enabled, 'aphlictDropdowns' => $rendered_dropdowns, 'hisecWarningConfig' => $hisec_warning_config, 'consoleConfig' => $console_config, 'applicationClass' => $application_class, 'applicationSearchIcon' => $application_search_icon, ) + $this->buildAphlictListenConfigData(); } private function buildAphlictListenConfigData() { $user = $this->getRequest()->getUser(); $subscriptions = $this->pageObjects; $subscriptions[] = $user->getPHID(); return array( 'pageObjects' => array_fill_keys($this->pageObjects, true), 'subscriptions' => $subscriptions, ); } private function getQuicksandURIPatternBlacklist() { $applications = PhabricatorApplication::getAllApplications(); $blacklist = array(); foreach ($applications as $application) { $blacklist[] = $application->getQuicksandURIPatternBlacklist(); } return array_mergev($blacklist); } private function getUserPreference($key, $default = null) { $request = $this->getRequest(); if (!$request) { return $default; } $user = $request->getUser(); if (!$user) { return $default; } return $user->getUserSetting($key); } public function produceAphrontResponse() { $controller = $this->getController(); if (!$this->getApplicationMenu()) { $application_menu = $controller->buildApplicationMenu(); if ($application_menu) { $this->setApplicationMenu($application_menu); } } $viewer = $this->getUser(); if ($viewer && $viewer->getPHID()) { $object_phids = $this->pageObjects; foreach ($object_phids as $object_phid) { PhabricatorFeedStoryNotification::updateObjectNotificationViews( $viewer, $object_phid); } } if ($this->getRequest()->isQuicksand()) { $content = $this->renderForQuicksand(); $response = id(new AphrontAjaxResponse()) ->setContent($content); } else { $content = $this->render(); $response = id(new AphrontWebpageResponse()) ->setContent($content) ->setFrameable($this->getFrameable()); } return $response; } } diff --git a/webroot/rsrc/css/application/base/standard-page-view.css b/webroot/rsrc/css/application/base/standard-page-view.css index 5fc0d41b7e..36294ca288 100644 --- a/webroot/rsrc/css/application/base/standard-page-view.css +++ b/webroot/rsrc/css/application/base/standard-page-view.css @@ -1,187 +1,176 @@ /** * @provides phabricator-standard-page-view */ .phabricator-anchor-view, .phabricator-anchor-navigation-marker { position: absolute; margin-top: -15px; } .phabricator-chromeless-page .phabricator-standard-page { background: transparent; border-width: 0px; } .phabricator-standard-page-body { clear: both; } -.main-page-background { - position: absolute; - top: 44px; - bottom: 0; - left: 0; - right: 0; - overflow: scroll; - z-index: -1; - background: {$page.background}; -} - -.main-page-background.white-background { +body.white-background { background: #fff; } .phabricator-standard-page-footer { text-align: right; margin: 44px 16px 16px; padding: 12px 0; border-top: 1px solid rgba({$alphagrey},.1); color: {$greytext}; } .with-durable-column .phabricator-standard-page-footer { margin: 36px 16px 28px; } .device .phabricator-standard-page-footer { margin: 24px 8px 16px; } !print .phabricator-standard-page-footer { display: none; } .device-desktop .has-local-nav + .phabricator-standard-page-footer { margin-left: 221px; } .device .phabricator-side-menu-home + .phabricator-standard-page-footer { display: none; } .keyboard-shortcut-help td, .keyboard-shortcut-help th { padding: 8px; vertical-align: middle; } .keyboard-shortcut-help th { white-space: nowrap; color: {$greytext}; } .keyboard-focus-focus-reticle { background: #ffffd3; position: absolute; border: 1px solid #999900; } a.handle-status-closed { text-decoration: line-through; color: #676767; } a.handle-status-closed:hover { text-decoration: line-through; color: #19558D; } a.handle-availability-disabled, a.handle-availability-none, a.handle-availability-partial { padding-left: 11px; background-repeat: no-repeat; background-position: -4px center; } a.handle-availability-none { background-image: url(/rsrc/image/icon/fatcow/bullet_red.png); } a.handle-availability-partial { background-image: url(/rsrc/image/icon/fatcow/bullet_orange.png); } a.handle-availability-disabled { background-image: url(/rsrc/image/icon/fatcow/bullet_black.png); } .aphront-developer-error-callout { position: relative; padding: 2em; background: #aa0000; color: white; text-align: center; font-size: {$smallerfontsize}; } .phui-handle .phui-icon-view { display: inline-block; margin: 2px 2px -2px 0; } .jx-scrollbar-frame { position: relative; overflow: hidden; } .jx-scrollbar-viewport { position: absolute; overflow-x: hidden; overflow-y: scroll; top: 0; bottom: 0; left: 0; right: 0; } .jx-scrollbar-test { position: absolute; left: -300px; } .jx-scrollbar-bar { position: absolute; top: 0; right: 0; bottom: 7px; width: 11px; } .jx-scrollbar-bar .jx-scrollbar-handle { position: absolute; right: 2px; -webkit-border-radius: 7px; -moz-border-radius: 7px; border-radius: 7px; min-height: 10px; width: 7px; opacity: 0; -webkit-transition: opacity 0.2s linear; -moz-transition: opacity 0.2s linear; -o-transition: opacity 0.2s linear; -ms-transition: opacity 0.2s linear; transition: opacity 0.2s linear; background: #6c6e71; -webkit-background-clip: padding-box; -moz-background-clip: padding; } .jx-scrollbar-bar:hover .jx-scrollbar-handle { opacity: 0.7; -webkit-transition: opacity 0 linear; -moz-transition: opacity 0 linear; -o-transition: opacity 0 linear; -ms-transition: opacity 0 linear; transition: opacity 0 linear; } .jx-scrollbar-bar .jx-scrollbar-visible { opacity: 0.7; } .jx-scrollbar-link { position: absolute; left: -50px; } diff --git a/webroot/rsrc/css/application/search/application-search-view.css b/webroot/rsrc/css/application/search/application-search-view.css index 71b47bb563..4a573f5111 100644 --- a/webroot/rsrc/css/application/search/application-search-view.css +++ b/webroot/rsrc/css/application/search/application-search-view.css @@ -1,65 +1,55 @@ /** * @provides application-search-view-css */ .application-search-view { background-color: #fff; } .application-search-view .application-search-results.phui-object-box { margin: 0; padding: 0 16px 24px; } -.device-phone .application-search-view - .application-search-results.phui-object-box { - padding: 0 8px 24px; -} - .application-search-view .application-search-results .phui-profile-header { padding: 16px 8px; border-bottom: 1px solid {$thinblueborder}; } .application-search-view .phui-object-box.phui-object-box-collapsed .phui-header-shell { padding: 20px 8px; } .application-search-results .phui-profile-header.phui-header-shell .phui-header-header { font-size: 20px; } .device-phone.application-search-view .application-search-results .phui-profile-header { padding: 12px 0; } .device-phone .application-search-results .phui-profile-header.phui-header-shell .phui-header-header { font-size: 16px; } .device-phone.application-search-view .application-search-results.phui-object-box { padding: 0 12px; } .application-search-view .phui-box-border { border: none; } .application-search-pager { margin: 0 16px 16px 16px; padding: 8px; } .device-phone .application-search-pager { margin: 12px; } - -.device-phone .application-search-view .application-search-results - .phui-profile-header { - padding-top: 12px; -} diff --git a/webroot/rsrc/css/core/core.css b/webroot/rsrc/css/core/core.css index f957a398c2..af6732260b 100644 --- a/webroot/rsrc/css/core/core.css +++ b/webroot/rsrc/css/core/core.css @@ -1,180 +1,175 @@ /** * @provides phabricator-core-css */ body, div, dl, dt, dd, ul, ol, li, h1, h2, h3, h4, h5, h6, pre, form, fieldset, p, blockquote, th, td, button { margin: 0; padding: 0; border: 0; } table { border-collapse: collapse; border-spacing: 0; } fieldset, img { border: 0; } address, caption, cite, code, dfn, th, var { font-style: normal; font-weight: normal; } ol, ul { list-style: none; } caption, th { text-align: left; } td, th { vertical-align: top; } h1, h2, h3, h4, h5, h6 { font-size: 100%; font-weight: bold; } -html{ - min-height: 100%; - position: relative; -} - body { font: {$basefont}; direction: ltr; text-align: left; unicode-bidi: embed; - height: 100%; + background: {$page.background}; /* By default, the iPhone zooms all text on the page by some percentage when you rotate from portrait mode to landscape mode. Disable this, since it breaks lots of things and prevents you from using landscape to see more columns in source code views. */ -webkit-text-size-adjust: none; /* Prevent content from resizing abruptly when shifting between scrollable and unscrollable pages. */ overflow-y: scroll; } textarea { font: inherit; } table { font-size: inherit; font: 100%; } h1 { font-size: 16px; } h2 { font-size: 14px; } a { -moz-outline-style: none; text-decoration: none; color: {$anchor}; cursor: pointer; } a:hover { text-decoration: underline; } img { display: block; } .busy { position: fixed; bottom: 8px; right: 8px; width: 32px; height: 32px; } .with-durable-column .busy { right: 308px; } .busy .phui-icon-view { font-size: 32px; } .grouped:after { content: ""; display: table; clear: both; } hr { height: 1px; background: #bbbbbb; border: none; } .aural-only { position: absolute !important; clip: rect(1px, 1px, 1px, 1px); /* NOTE: Without this, Safari sometimes lays these elements out at normal size. An example is the label on the comment action menu on timelines. */ width: 0; height: 0; overflow: hidden; } .visual-only { /* These elements are hidden by the 'aria-hidden' attribute. */ } .audible .aural-only { clip: auto; width: auto; height: auto; overflow: auto; background: #006699; color: #ffffff; } .audible .aural-only a { color: #ffffff; font-weight: bold; } .audible .visual-only { position: absolute !important; background: #990066; opacity: 0.25; } .routing-bar { position: fixed; top: 0; width: 100%; height: 2px; background: {$darkbluetext}; z-index: 80; box-shadow: 0 2px 1px rgba(0, 128, 255, 0.25); } .routing-progress { position: fixed; top: 0; left: 0; height: 2px; background: {$sky}; } diff --git a/webroot/rsrc/css/phui/phui-basic-nav-view.css b/webroot/rsrc/css/phui/phui-basic-nav-view.css index 109ba4252c..30647e3ece 100644 --- a/webroot/rsrc/css/phui/phui-basic-nav-view.css +++ b/webroot/rsrc/css/phui/phui-basic-nav-view.css @@ -1,110 +1,110 @@ /** * @provides phui-basic-nav-view-css */ .device-desktop .phui-navigation-shell, -.device .phabricator-home .phui-navigation-shell { +.phabricator-home.device .phui-navigation-shell { display: table; width: 100%; height: calc(100vh - {$menu.main.height}); } .device-desktop .phui-navigation-shell .phabricator-nav, -.device .phabricator-home .phui-navigation-shell .phabricator-nav { +.phabricator-home.device .phui-navigation-shell .phabricator-nav { display: table-row; } .device-desktop .phui-navigation-shell .phabricator-nav-local, -.device .phabricator-home .phui-navigation-shell .phabricator-nav-local { +.phabricator-home.device .phui-navigation-shell .phabricator-nav-local { display: table-cell; position: relative; vertical-align: top; width: {$menu.profile.width}; max-width: {$menu.profile.width}; margin-top: 0; overflow: hidden; } .phui-basic-nav.phui-navigation-shell .phabricator-nav-local { width: 205px; padding-top: 4px; padding-right: 8px; } .phui-basic-nav .phabricator-side-menu { background-color: {$page.sidenav}; } .phui-two-column-view .phui-basic-nav.phui-navigation-shell .phabricator-nav-local { width: {$menu.profile.width}; max-width: {$menu.profile.width}; padding-right: 0; padding-top: 0; } .phui-two-column-view .phui-basic-nav .phabricator-side-menu { background-color: #fff; } .phui-basic-nav .phabricator-side-menu { background-color: {$page.sidenav}; } .phui-basic-nav .phabricator-side-menu .phui-list-item-view { display: block; white-space: nowrap; text-decoration: none; font-size: 13px; -webkit-font-smoothing: antialiased; } .phui-basic-nav .phabricator-side-menu .phui-list-item-href { display: block; padding: 6px 8px 6px 24px; color: {$darkbluetext}; border-top-right-radius: 3px; border-bottom-right-radius: 3px; overflow: hidden; text-overflow: ellipsis } .phui-basic-nav .phabricator-side-menu .phui-list-item-icon { margin-left: -12px; text-align: center; width: 24px; } .phui-basic-nav .phabricator-side-menu .phui-list-item-selected { background-color: rgba({$alphablack},.05); border-left: 4px solid {$sky}; border-top-right-radius: 3px; border-bottom-right-radius: 3px; font-weight: bold; } .device-desktop .phui-basic-nav .phabricator-side-menu .phui-list-item-selected a.phui-list-item-href:hover { background-color: rgba({$alphablack},.05); } .phui-basic-nav .phabricator-side-menu .phui-list-item-selected .phui-list-item-href { padding-left: 20px; } .phui-basic-nav .phabricator-side-menu .phui-list-item-type-label { padding: 6px 8px 4px 12px; color: {$darkbluetext}; text-transform: uppercase; font-size: 12px; font-weight: bold; border-style: solid; } .device-desktop .phui-basic-nav .phabricator-side-menu a.phui-list-item-href:hover { text-decoration: none; background-color: rgba({$alphablack},.07); } diff --git a/webroot/rsrc/css/phui/workboards/phui-workboard-color.css b/webroot/rsrc/css/phui/workboards/phui-workboard-color.css index 185fa327b3..d983622a99 100644 --- a/webroot/rsrc/css/phui/workboards/phui-workboard-color.css +++ b/webroot/rsrc/css/phui/workboards/phui-workboard-color.css @@ -1,152 +1,152 @@ /** * @provides phui-workboard-color-css */ .phui-workboard-color .phabricator-nav-content .phui-workboard-view-shadow { background-color: transparent; } .phui-workboard-color .phui-crumbs-view { background-color: rgba({$alphagrey},.15); border: none; color: rgba({$alphawhite},.8); } .phui-workboard-color .phui-crumbs-view a, .phui-workboard-color .phui-crumbs-view .phui-icon-view { color: rgba({$alphawhite},.85); } .phui-workboard-color .phui-crumbs-view a:hover, .phui-workboard-color .phui-crumbs-view a:hover .phui-icon-view { color: #fff; } .phui-workboard-color .phuix-dropdown-menu { background-color: rgba({$alphawhite},.9); } .phui-workboard-color .phui-workpanel-view .phui-box-grey { background-color: rgba({$alphawhite},.6); } -body .phui-workboard-color .phui-profile-menu .phabricator-side-menu { +body.phui-workboard-color .phui-profile-menu .phabricator-side-menu { background-color: rgba({$alphagrey},.3); } -body .phui-workboard-color .phabricator-side-menu .phui-profile-menu-footer-1 { +body.phui-workboard-color .phabricator-side-menu .phui-profile-menu-footer-1 { background-color: transparent; } .phui-workboard-color .phui-profile-menu .phabricator-side-menu { box-shadow: none; } .phui-workboard-color-preview { width: 50px; height: 50px; font-size: 34px; } /* Gradients */ .phui-workboard-gradient-red { background-color: #e53935; background-image: linear-gradient(to left, #e53935, #e35d5b); } .phui-workboard-gradient-orange { background-color: #f46b45; background-image: linear-gradient(to left, #f46b45, #eea849); } .phui-workboard-gradient-yellow { background-color: #FF8008; background-image: linear-gradient(to left, #FF8008, #FFC837); } .phui-workboard-gradient-green { background-color: #2fa0ac; background-image: linear-gradient(90deg, #2fa0ac 0, #58cca6); } .phui-workboard-gradient-blue { background-color: #73a5c3; background-image: linear-gradient(90deg, #73a5c3 0, #6875be); } .phui-workboard-gradient-bluegrey { background-color: #517fa4; background-image: linear-gradient(to left, #517fa4, #243949); } .phui-workboard-gradient-indigo { background-color: #4776E6; background-image: linear-gradient(to left, #4776E6, #8E54E9); } .phui-workboard-gradient-violet { background-color: #9f73c3; background-image: linear-gradient(90deg, #9f73c3 0, #6875be); } .phui-workboard-gradient-sky { background-color: #7474BF; background-image: linear-gradient(to left, #7474BF, #348AC7); } .phui-workboard-gradient-pink { background-color: #EA2A90; background-image: linear-gradient(to left, #EA2A90, #79164B); } .phui-workboard-gradient-grey { background-color: #283048; background-image: linear-gradient(to left, #283048, #859398); } /* Colors */ .phui-workboard-red { background-color: {$red}; } .phui-workboard-orange { background-color: {$orange}; } .phui-workboard-yellow { background-color: {$yellow}; } .phui-workboard-green { background-color: {$green}; } .phui-workboard-blue { background-color: {$blue}; } .phui-workboard-indigo { background-color: {$indigo}; } .phui-workboard-violet { background-color: {$violet}; } .phui-workboard-sky { background-color: {$sky}; } .phui-workboard-pink { background-color: {$pink}; } .phui-workboard-fire { background-color: {$fire}; } .phui-workboard-grey { background-color: {$greytext}; } diff --git a/webroot/rsrc/css/phui/workboards/phui-workboard.css b/webroot/rsrc/css/phui/workboards/phui-workboard.css index 0df8be4732..df51e7623d 100644 --- a/webroot/rsrc/css/phui/workboards/phui-workboard.css +++ b/webroot/rsrc/css/phui/workboards/phui-workboard.css @@ -1,98 +1,95 @@ /** * @provides phui-workboard-view-css */ .phui-workboard-view { width: 100%; } .device-phone .phui-workboard-view { width: auto; } .device-desktop .phui-workboard-view-shadow { overflow-x: auto; overflow-y: hidden; position: absolute; - top: 32px; + top: 79px; bottom: 0; left: 0; right: 0; padding: 16px; + background-color: #fff; } .phui-workboard-view-shadow::-webkit-scrollbar { height: 8px; width: 8px; background: rgba(200,200,200,.6); } .phui-workboard-view-shadow::-webkit-scrollbar-thumb { background: {$lightbluetext}; } .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}; } !print .project-board-wrapper .phui-workboard-view-shadow { position: static; } !print .project-board-wrapper .aphront-multi-column-column-outer { display: block; margin: 0 0 18px; page-break-inside: avoid; } .device-desktop .phui-workboard-view .aphront-multi-column-fixed .aphront-multi-column-inner { margin-left: 0; } .device .project-board-wrapper { margin: 16px; } .device-desktop .phui-workboard-view .aphront-multi-column-view { pointer-events: none; } .device-desktop .phui-workpanel-view { pointer-events: auto; cursor: auto; } /* Fullscreen */ .device-desktop .phui-workboard-fullscreen .phabricator-main-menu { display: none; } -.device-desktop .phui-workboard-fullscreen .main-page-background { - top: 0; -} - .device-desktop .phui-workboard-fullscreen .phui-profile-menu .phui-workboard-view-shadow { - top: 32px; + top: 35px; left: 0; } .device-desktop .phui-workboard-fullscreen .phui-workpanel-body-content { max-height: calc(100vh - 120px); } .device-desktop .phui-workboard-fullscreen .phui-profile-menu .phabricator-nav-local { display: none; } .device .phui-workboard-expand-icon { display: none; }