diff --git a/resources/celerity/map.php b/resources/celerity/map.php index d558032906..434aa5b65a 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -41,7 +41,7 @@ return array( 'rsrc/css/application/conduit/conduit-api.css' => '7bc725c4', 'rsrc/css/application/config/config-options.css' => '0ede4c9b', 'rsrc/css/application/config/config-page.css' => '8798e14f', - 'rsrc/css/application/config/config-template.css' => '8e6c6fcd', + 'rsrc/css/application/config/config-template.css' => '8f18fa41', 'rsrc/css/application/config/setup-issue.css' => 'f794cfc3', 'rsrc/css/application/config/unhandled-exception.css' => '4c96257a', 'rsrc/css/application/conpherence/durable-column.css' => '86396117', @@ -777,7 +777,7 @@ return array( 'phabricator-dashboard-css' => 'bc6f2127', 'phabricator-drag-and-drop-file-upload' => '58dea2fa', 'phabricator-draggable-list' => '5a13c79f', - 'phabricator-fatal-config-template-css' => '8e6c6fcd', + 'phabricator-fatal-config-template-css' => '8f18fa41', 'phabricator-feed-css' => 'ecd4ec57', 'phabricator-file-upload' => '680ea2c8', 'phabricator-filetree-view-css' => 'fccf9f82', diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index b6591a961c..b3051e2a26 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -2685,6 +2685,7 @@ phutil_register_library_map(array( 'PhabricatorImageMacroRemarkupRule' => 'applications/macro/markup/PhabricatorImageMacroRemarkupRule.php', 'PhabricatorImageTransformer' => 'applications/files/PhabricatorImageTransformer.php', 'PhabricatorImagemagickSetupCheck' => 'applications/config/check/PhabricatorImagemagickSetupCheck.php', + 'PhabricatorInFlightErrorView' => 'applications/config/view/PhabricatorInFlightErrorView.php', 'PhabricatorIndexEngine' => 'applications/search/index/PhabricatorIndexEngine.php', 'PhabricatorIndexEngineExtension' => 'applications/search/index/PhabricatorIndexEngineExtension.php', 'PhabricatorIndexEngineExtensionModule' => 'applications/search/index/PhabricatorIndexEngineExtensionModule.php', @@ -7509,6 +7510,7 @@ phutil_register_library_map(array( 'PhabricatorImageMacroRemarkupRule' => 'PhutilRemarkupRule', 'PhabricatorImageTransformer' => 'Phobject', 'PhabricatorImagemagickSetupCheck' => 'PhabricatorSetupCheck', + 'PhabricatorInFlightErrorView' => 'AphrontView', 'PhabricatorIndexEngine' => 'Phobject', 'PhabricatorIndexEngineExtension' => 'Phobject', 'PhabricatorIndexEngineExtensionModule' => 'PhabricatorConfigModule', diff --git a/src/applications/config/check/PhabricatorSetupCheck.php b/src/applications/config/check/PhabricatorSetupCheck.php index ad779ed63f..0c9888cd77 100644 --- a/src/applications/config/check/PhabricatorSetupCheck.php +++ b/src/applications/config/check/PhabricatorSetupCheck.php @@ -192,6 +192,21 @@ abstract class PhabricatorSetupCheck extends Phobject { } } + /** + * Test if we've survived through setup on at least one normal request + * without fataling. + * + * If we've made it through setup without hitting any fatals, we switch + * to render a more friendly error page when encountering issues like + * database connection failures. This gives users a smoother experience in + * the face of intermittent failures. + * + * @return bool True if we've made it through setup since the last restart. + */ + final public static function isInFlight() { + return (self::getOpenSetupIssueKeys() !== null); + } + final public static function loadAllChecks() { return id(new PhutilClassMapQuery()) ->setAncestorClass(__CLASS__) diff --git a/src/applications/config/response/PhabricatorConfigResponse.php b/src/applications/config/response/PhabricatorConfigResponse.php index d4d2effdf5..588f60255f 100644 --- a/src/applications/config/response/PhabricatorConfigResponse.php +++ b/src/applications/config/response/PhabricatorConfigResponse.php @@ -25,11 +25,21 @@ final class PhabricatorConfigResponse extends AphrontStandaloneHTMLResponse { } protected function getResponseBodyClass() { - return 'setup-fatal'; + if (PhabricatorSetupCheck::isInFlight()) { + return 'setup-fatal in-flight'; + } else { + return 'setup-fatal'; + } } protected function getResponseBody() { - return $this->view->render(); + $view = $this->view; + + if (PhabricatorSetupCheck::isInFlight()) { + return $view->renderInFlight(); + } else { + return $view->render(); + } } protected function buildPlainTextResponseString() { diff --git a/src/applications/config/view/PhabricatorInFlightErrorView.php b/src/applications/config/view/PhabricatorInFlightErrorView.php new file mode 100644 index 0000000000..2f1ad7bc33 --- /dev/null +++ b/src/applications/config/view/PhabricatorInFlightErrorView.php @@ -0,0 +1,41 @@ +message = $message; + return $this; + } + + public function getMessage() { + return $this->message; + } + + public function render() { + return phutil_tag( + 'div', + array( + 'class' => 'in-flight-error-detail', + ), + array( + phutil_tag( + 'h1', + array( + 'class' => 'in-flight-error-title', + ), + pht('A Troublesome Encounter!')), + phutil_tag( + 'div', + array( + 'class' => 'in-flight-error-body', + ), + pht( + 'Woe! This request had its journey cut short by unexpected '. + 'circumstances (%s).', + $this->getMessage())), + )); + } + +} diff --git a/src/applications/config/view/PhabricatorSetupIssueView.php b/src/applications/config/view/PhabricatorSetupIssueView.php index a2a703c436..ca6397133d 100644 --- a/src/applications/config/view/PhabricatorSetupIssueView.php +++ b/src/applications/config/view/PhabricatorSetupIssueView.php @@ -13,6 +13,14 @@ final class PhabricatorSetupIssueView extends AphrontView { return $this->issue; } + public function renderInFlight() { + $issue = $this->getIssue(); + + return id(new PhabricatorInFlightErrorView()) + ->setMessage($issue->getName()) + ->render(); + } + public function render() { $issue = $this->getIssue(); diff --git a/webroot/rsrc/css/application/config/config-template.css b/webroot/rsrc/css/application/config/config-template.css index bb8db22c93..13ce56488a 100644 --- a/webroot/rsrc/css/application/config/config-template.css +++ b/webroot/rsrc/css/application/config/config-template.css @@ -11,3 +11,27 @@ body { text-align: left; -webkit-text-size-adjust: none; } + +body.in-flight { + background: #41506e; + color: #e0e0e0; +} + +.in-flight-error-detail { + max-width: 760px; + margin: 72px auto; + background: rgba(255, 255, 255, 0.25); + border-radius: 3px; + padding: 8px 16px; +} + +.in-flight-error-title { + padding: 12px 8px; + font-size: 24px; + font-weight: 500; + margin: 0; +} + +.in-flight-error-body { + padding: 4px 12px 12px; +}