diff --git a/resources/celerity/map.php b/resources/celerity/map.php --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -9,7 +9,7 @@ 'names' => array( 'conpherence.pkg.css' => 'e68cf1fa', 'conpherence.pkg.js' => 'b5b51108', - 'core.pkg.css' => '042e1782', + 'core.pkg.css' => 'ebbf04f7', 'core.pkg.js' => '6c085267', 'darkconsole.pkg.js' => '1f9a31bc', 'differential.pkg.css' => '45951e9e', @@ -142,7 +142,7 @@ 'rsrc/css/phui/phui-badge.css' => '22c0cf4f', 'rsrc/css/phui/phui-basic-nav-view.css' => '98c11ab3', 'rsrc/css/phui/phui-big-info-view.css' => 'acc3492c', - 'rsrc/css/phui/phui-box.css' => '4165eb0d', + 'rsrc/css/phui/phui-box.css' => '9f3745fb', 'rsrc/css/phui/phui-chart.css' => '6bf6f78e', 'rsrc/css/phui/phui-cms.css' => '504b4b23', 'rsrc/css/phui/phui-comment-form.css' => 'ac68149f', @@ -157,7 +157,7 @@ 'rsrc/css/phui/phui-form-view.css' => 'ae9f8d16', 'rsrc/css/phui/phui-form.css' => '7aaa04e3', 'rsrc/css/phui/phui-head-thing.css' => 'fd311e5f', - 'rsrc/css/phui/phui-header-view.css' => '3c722648', + 'rsrc/css/phui/phui-header-view.css' => '369275d6', 'rsrc/css/phui/phui-hovercard.css' => 'f0592bcf', 'rsrc/css/phui/phui-icon-set-selector.css' => '87db8fee', 'rsrc/css/phui/phui-icon.css' => '5c4a5de6', @@ -820,7 +820,7 @@ 'phui-badge-view-css' => '22c0cf4f', 'phui-basic-nav-view-css' => '98c11ab3', 'phui-big-info-view-css' => 'acc3492c', - 'phui-box-css' => '4165eb0d', + 'phui-box-css' => '9f3745fb', 'phui-button-bar-css' => 'f1ff5494', 'phui-button-css' => '1863cc6e', 'phui-button-simple-css' => '8e1baf68', @@ -843,7 +843,7 @@ 'phui-form-css' => '7aaa04e3', 'phui-form-view-css' => 'ae9f8d16', 'phui-head-thing-view-css' => 'fd311e5f', - 'phui-header-view-css' => '3c722648', + 'phui-header-view-css' => '369275d6', 'phui-hovercard' => '1bd28176', 'phui-hovercard-view-css' => 'f0592bcf', 'phui-icon-set-selector-css' => '87db8fee', diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -843,7 +843,6 @@ 'DiffusionRepositoryController' => 'applications/diffusion/controller/DiffusionRepositoryController.php', 'DiffusionRepositoryDatasource' => 'applications/diffusion/typeahead/DiffusionRepositoryDatasource.php', 'DiffusionRepositoryDefaultController' => 'applications/diffusion/controller/DiffusionRepositoryDefaultController.php', - 'DiffusionRepositoryDocumentationManagementPanel' => 'applications/diffusion/management/DiffusionRepositoryDocumentationManagementPanel.php', 'DiffusionRepositoryEditActivateController' => 'applications/diffusion/controller/DiffusionRepositoryEditActivateController.php', 'DiffusionRepositoryEditConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionRepositoryEditConduitAPIMethod.php', 'DiffusionRepositoryEditController' => 'applications/diffusion/controller/DiffusionRepositoryEditController.php', @@ -864,7 +863,6 @@ 'DiffusionRepositoryRemarkupRule' => 'applications/diffusion/remarkup/DiffusionRepositoryRemarkupRule.php', 'DiffusionRepositorySearchConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionRepositorySearchConduitAPIMethod.php', 'DiffusionRepositoryStagingManagementPanel' => 'applications/diffusion/management/DiffusionRepositoryStagingManagementPanel.php', - 'DiffusionRepositoryStatusManagementPanel' => 'applications/diffusion/management/DiffusionRepositoryStatusManagementPanel.php', 'DiffusionRepositoryStorageManagementPanel' => 'applications/diffusion/management/DiffusionRepositoryStorageManagementPanel.php', 'DiffusionRepositorySubversionManagementPanel' => 'applications/diffusion/management/DiffusionRepositorySubversionManagementPanel.php', 'DiffusionRepositorySymbolsManagementPanel' => 'applications/diffusion/management/DiffusionRepositorySymbolsManagementPanel.php', @@ -5863,7 +5861,6 @@ 'DiffusionRepositoryController' => 'DiffusionController', 'DiffusionRepositoryDatasource' => 'PhabricatorTypeaheadDatasource', 'DiffusionRepositoryDefaultController' => 'DiffusionController', - 'DiffusionRepositoryDocumentationManagementPanel' => 'DiffusionRepositoryManagementPanel', 'DiffusionRepositoryEditActivateController' => 'DiffusionRepositoryManageController', 'DiffusionRepositoryEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', 'DiffusionRepositoryEditController' => 'DiffusionRepositoryManageController', @@ -5884,7 +5881,6 @@ 'DiffusionRepositoryRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'DiffusionRepositorySearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod', 'DiffusionRepositoryStagingManagementPanel' => 'DiffusionRepositoryManagementPanel', - 'DiffusionRepositoryStatusManagementPanel' => 'DiffusionRepositoryManagementPanel', 'DiffusionRepositoryStorageManagementPanel' => 'DiffusionRepositoryManagementPanel', 'DiffusionRepositorySubversionManagementPanel' => 'DiffusionRepositoryManagementPanel', 'DiffusionRepositorySymbolsManagementPanel' => 'DiffusionRepositoryManagementPanel', diff --git a/src/applications/diffusion/controller/DiffusionRepositoryEditUpdateController.php b/src/applications/diffusion/controller/DiffusionRepositoryEditUpdateController.php --- a/src/applications/diffusion/controller/DiffusionRepositoryEditUpdateController.php +++ b/src/applications/diffusion/controller/DiffusionRepositoryEditUpdateController.php @@ -13,7 +13,7 @@ $drequest = $this->getDiffusionRequest(); $repository = $drequest->getRepository(); - $panel_uri = id(new DiffusionRepositoryStatusManagementPanel()) + $panel_uri = id(new DiffusionRepositoryBasicsManagementPanel()) ->setRepository($repository) ->getPanelURI(); diff --git a/src/applications/diffusion/controller/DiffusionRepositoryManageController.php b/src/applications/diffusion/controller/DiffusionRepositoryManageController.php --- a/src/applications/diffusion/controller/DiffusionRepositoryManageController.php +++ b/src/applications/diffusion/controller/DiffusionRepositoryManageController.php @@ -22,4 +22,20 @@ return $crumbs; } + public function newBox($title, $content, $action = null) { + $header = id(new PHUIHeaderView()) + ->setHeader($title); + + if ($action) { + $header->addActionItem($action); + } + + $view = id(new PHUIObjectBoxView()) + ->setHeader($header) + ->appendChild($content) + ->setBackground(PHUIObjectBoxView::WHITE_CONFIG); + + return $view; + } + } diff --git a/src/applications/diffusion/controller/DiffusionRepositoryManagePanelsController.php b/src/applications/diffusion/controller/DiffusionRepositoryManagePanelsController.php --- a/src/applications/diffusion/controller/DiffusionRepositoryManagePanelsController.php +++ b/src/applications/diffusion/controller/DiffusionRepositoryManagePanelsController.php @@ -53,6 +53,10 @@ $panel = $panels[$selected]; + $crumbs = $this->buildApplicationCrumbs(); + $crumbs->addTextCrumb($panel->getManagementPanelLabel()); + $crumbs->setBorder(true); + $content = $panel->buildManagementPanelContent(); $title = array( @@ -60,45 +64,17 @@ $repository->getDisplayName(), ); - $crumbs = $this->buildApplicationCrumbs(); - $crumbs->addTextCrumb($panel->getManagementPanelLabel()); - $crumbs->setBorder(true); - - $header_text = pht( - '%s: %s', - $repository->getDisplayName(), - $panel->getManagementPanelLabel()); - - $header = id(new PHUIHeaderView()) - ->setHeader($header_text) - ->setHeaderIcon('fa-pencil'); - if ($repository->isTracked()) { - $header->setStatus('fa-check', 'bluegrey', pht('Active')); - } else { - $header->setStatus('fa-ban', 'dark', pht('Inactive')); - } - - $header->addActionLink( - id(new PHUIButtonView()) - ->setTag('a') - ->setText(pht('View Repository')) - ->setHref($repository->getURI()) - ->setIcon('fa-code') - ->setColor(PHUIButtonView::GREEN)); + $header = $this->buildHeaderView($repository->getDisplayName()); $view = id(new PHUITwoColumnView()) ->setHeader($header) + ->setNavigation($nav) + ->setFixed(true) ->setMainColumn($content); - $curtain = $panel->buildManagementPanelCurtain(); - if ($curtain) { - $view->setCurtain($curtain); - } - return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) - ->setNavigation($nav) ->appendChild($view); } @@ -113,12 +89,6 @@ $nav = id(new AphrontSideNavFilterView()) ->setBaseURI($base_uri); - $item = id(new PHUIListItemView()) - ->setName(pht('manage')) - ->setType(PHUIListItemView::TYPE_LABEL); - - $nav->addMenuItem($item); - foreach ($panels as $panel) { $key = $panel->getManagementPanelKey(); $label = $panel->getManagementPanelLabel(); @@ -140,6 +110,46 @@ return $nav; } + public function buildHeaderView($title) { + $viewer = $this->getViewer(); + + $drequest = $this->getDiffusionRequest(); + $repository = $drequest->getRepository(); + + $header = id(new PHUIHeaderView()) + ->setHeader($title) + ->setProfileHeader(true) + ->setHref($repository->getURI()) + ->setImage($repository->getProfileImageURI()); + + if ($repository->isTracked()) { + $header->setStatus('fa-check', 'bluegrey', pht('Active')); + } else { + $header->setStatus('fa-ban', 'dark', pht('Inactive')); + } + + $doc_href = PhabricatorEnv::getDoclink( + 'Diffusion User Guide: Managing Repositories'); + + $header->addActionLink( + id(new PHUIButtonView()) + ->setTag('a') + ->setText(pht('View Repository')) + ->setHref($repository->getURI()) + ->setIcon('fa-code') + ->setColor(PHUIButtonView::GREY)); + + $header->addActionLink( + id(new PHUIButtonView()) + ->setTag('a') + ->setIcon('fa-book') + ->setHref($doc_href) + ->setText(pht('Help')) + ->setColor(PHUIButtonView::GREY)); + + return $header; + } + public function newTimeline(PhabricatorRepository $repository) { $timeline = $this->buildTransactionTimeline( $repository, diff --git a/src/applications/diffusion/management/DiffusionRepositoryActionsManagementPanel.php b/src/applications/diffusion/management/DiffusionRepositoryActionsManagementPanel.php --- a/src/applications/diffusion/management/DiffusionRepositoryActionsManagementPanel.php +++ b/src/applications/diffusion/management/DiffusionRepositoryActionsManagementPanel.php @@ -14,20 +14,7 @@ } public function getManagementPanelIcon() { - $repository = $this->getRepository(); - - $has_any = - $repository->getDetail('herald-disabled') || - $repository->getDetail('disable-autoclose'); - - // NOTE: Any value here really means something is disabled, so try to - // hint that a little bit with the icon. - - if ($has_any) { - return 'fa-comment-o'; - } else { - return 'fa-commenting grey'; - } + return 'fa-flash'; } protected function getEditEngineFieldKeys() { @@ -37,29 +24,6 @@ ); } - public function buildManagementPanelCurtain() { - $repository = $this->getRepository(); - $viewer = $this->getViewer(); - $action_list = $this->getNewActionList(); - - $can_edit = PhabricatorPolicyFilter::hasCapability( - $viewer, - $repository, - PhabricatorPolicyCapability::CAN_EDIT); - - $actions_uri = $this->getEditPageURI(); - - $action_list->addAction( - id(new PhabricatorActionView()) - ->setIcon('fa-pencil') - ->setName(pht('Edit Actions')) - ->setHref($actions_uri) - ->setDisabled(!$can_edit) - ->setWorkflow(!$can_edit)); - - return $this->getNewCurtainView($action_list); - } - public function buildManagementPanelContent() { $repository = $this->getRepository(); $viewer = $this->getViewer(); @@ -79,7 +43,22 @@ $autoclose = phutil_tag('em', array(), $autoclose); $view->addProperty(pht('Autoclose'), $autoclose); - return $this->newBox(pht('Actions'), $view); + $can_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + $repository, + PhabricatorPolicyCapability::CAN_EDIT); + + $actions_uri = $this->getEditPageURI(); + + $button = id(new PHUIButtonView()) + ->setTag('a') + ->setIcon('fa-pencil') + ->setText(pht('Edit')) + ->setHref($actions_uri) + ->setDisabled(!$can_edit) + ->setWorkflow(!$can_edit); + + return $this->newBox(pht('Actions'), $view, array($button)); } } diff --git a/src/applications/diffusion/management/DiffusionRepositoryAutomationManagementPanel.php b/src/applications/diffusion/management/DiffusionRepositoryAutomationManagementPanel.php --- a/src/applications/diffusion/management/DiffusionRepositoryAutomationManagementPanel.php +++ b/src/applications/diffusion/management/DiffusionRepositoryAutomationManagementPanel.php @@ -27,59 +27,18 @@ public function getManagementPanelIcon() { $repository = $this->getRepository(); - if (!$repository->canPerformAutomation()) { - return 'fa-truck grey'; - } - $blueprint_phids = $repository->getAutomationBlueprintPHIDs(); - if (!$blueprint_phids) { - return 'fa-truck grey'; - } $is_authorized = DrydockAuthorizationQuery::isFullyAuthorized( $repository->getPHID(), $blueprint_phids); if (!$is_authorized) { - return 'fa-exclamation-triangle yellow'; + return 'fa-exclamation-triangle'; } return 'fa-truck'; } - public function buildManagementPanelCurtain() { - $repository = $this->getRepository(); - $viewer = $this->getViewer(); - $action_list = $this->getNewActionList(); - - $can_edit = PhabricatorPolicyFilter::hasCapability( - $viewer, - $repository, - PhabricatorPolicyCapability::CAN_EDIT); - - $can_test = $can_edit && $repository->canPerformAutomation(); - - $automation_uri = $this->getEditPageURI(); - $test_uri = $repository->getPathURI('edit/testautomation/'); - - $action_list->addAction( - id(new PhabricatorActionView()) - ->setIcon('fa-pencil') - ->setName(pht('Edit Automation')) - ->setHref($automation_uri) - ->setDisabled(!$can_edit) - ->setWorkflow(!$can_edit)); - - $action_list->addAction( - id(new PhabricatorActionView()) - ->setIcon('fa-gamepad') - ->setName(pht('Test Configuration')) - ->setWorkflow(true) - ->setDisabled(!$can_test) - ->setHref($test_uri)); - - return $this->getNewCurtainView($action_list); - } - public function buildManagementPanelContent() { $repository = $this->getRepository(); $viewer = $this->getViewer(); @@ -99,7 +58,33 @@ $view->addProperty(pht('Automation'), $blueprint_view); - return $this->newBox(pht('Automation'), $view); + $can_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + $repository, + PhabricatorPolicyCapability::CAN_EDIT); + + $can_test = $can_edit && $repository->canPerformAutomation(); + + $automation_uri = $this->getEditPageURI(); + $test_uri = $repository->getPathURI('edit/testautomation/'); + + $edit = id(new PHUIButtonView()) + ->setTag('a') + ->setIcon('fa-pencil') + ->setText(pht('Edit')) + ->setHref($automation_uri) + ->setDisabled(!$can_edit) + ->setWorkflow(!$can_edit); + + $test = id(new PHUIButtonView()) + ->setTag('a') + ->setIcon('fa-gamepad') + ->setText(pht('Test Config')) + ->setWorkflow(true) + ->setDisabled(!$can_test) + ->setHref($test_uri); + + return $this->newBox(pht('Automation'), $view, array($edit, $test)); } } diff --git a/src/applications/diffusion/management/DiffusionRepositoryBasicsManagementPanel.php b/src/applications/diffusion/management/DiffusionRepositoryBasicsManagementPanel.php --- a/src/applications/diffusion/management/DiffusionRepositoryBasicsManagementPanel.php +++ b/src/applications/diffusion/management/DiffusionRepositoryBasicsManagementPanel.php @@ -14,13 +14,7 @@ } public function getManagementPanelIcon() { - $repository = $this->getRepository(); - - if (!$repository->isTracked()) { - return 'fa-ban indigo'; - } else { - return 'fa-code'; - } + return 'fa-code'; } protected function getEditEngineFieldKeys() { @@ -33,10 +27,11 @@ ); } - public function buildManagementPanelCurtain() { + private function buildActionMenu() { $repository = $this->getRepository(); $viewer = $this->getViewer(); - $action_list = $this->getNewActionList(); + $action_list = id(new PhabricatorActionListView()) + ->setViewer($viewer); $can_edit = PhabricatorPolicyFilter::hasCapability( $viewer, @@ -50,27 +45,22 @@ $dangerous_uri = $repository->getPathURI('edit/dangerous/'); if ($repository->isTracked()) { - $activate_icon = 'fa-pause'; $activate_label = pht('Deactivate Repository'); } else { - $activate_icon = 'fa-play'; $activate_label = pht('Activate Repository'); } $should_dangerous = $repository->shouldAllowDangerousChanges(); if ($should_dangerous) { - $dangerous_icon = 'fa-shield'; $dangerous_name = pht('Prevent Dangerous Changes'); $can_dangerous = $can_edit; } else { - $dangerous_icon = 'fa-bullseye'; $dangerous_name = pht('Allow Dangerous Changes'); $can_dangerous = ($can_edit && $repository->canAllowDangerousChanges()); } $action_list->addAction( id(new PhabricatorActionView()) - ->setIcon('fa-pencil') ->setName(pht('Edit Basic Information')) ->setHref($edit_uri) ->setDisabled(!$can_edit) @@ -78,7 +68,6 @@ $action_list->addAction( id(new PhabricatorActionView()) - ->setIcon('fa-text-width') ->setName(pht('Edit Text Encoding')) ->setHref($encoding_uri) ->setDisabled(!$can_edit) @@ -86,7 +75,6 @@ $action_list->addAction( id(new PhabricatorActionView()) - ->setIcon($dangerous_icon) ->setName($dangerous_name) ->setHref($dangerous_uri) ->setDisabled(!$can_dangerous) @@ -95,26 +83,37 @@ $action_list->addAction( id(new PhabricatorActionView()) ->setHref($activate_uri) - ->setIcon($activate_icon) ->setName($activate_label) ->setDisabled(!$can_edit) ->setWorkflow(true)); + $action_list->addAction( + id(new PhabricatorActionView()) + ->setType(PhabricatorActionView::TYPE_DIVIDER)); + $action_list->addAction( id(new PhabricatorActionView()) ->setName(pht('Delete Repository')) - ->setIcon('fa-times') ->setHref($delete_uri) + ->setColor(PhabricatorActionView::RED) ->setDisabled(true) ->setWorkflow(true)); - return $this->getNewCurtainView($action_list); + return $action_list; } public function buildManagementPanelContent() { - $result = array(); - $basics = $this->newBox(pht('Repository Basics'), $this->buildBasics()); + $button = id(new PHUIButtonView()) + ->setTag('a') + ->setText(pht('Actions')) + ->setHref('#') + ->setIcon('fa-bars') + ->addClass('phui-mobile-menu') + ->setDropdownMenu($this->buildActionMenu()); + + $basics = $this->buildBasics(); + $basics = $this->newBox(pht('Properties'), $basics, array($button)); $repository = $this->getRepository(); $is_new = $repository->isNewlyInitialized(); @@ -144,14 +143,13 @@ ->setErrors($messages); } - $result[] = $basics; - $description = $this->buildDescription(); if ($description) { - $result[] = $this->newBox(pht('Description'), $description); + $description = $this->newBox(pht('Description'), $description); } + $status = $this->buildStatus(); - return array($info_view, $result); + return array($info_view, $basics, $description, $status); } private function buildBasics() { @@ -213,7 +211,7 @@ $view = id(new PHUIPropertyListView()) ->setViewer($viewer); if (!strlen($description)) { - $description = phutil_tag('em', array(), pht('No description provided.')); + return null; } else { $description = new PHUIRemarkupView($viewer, $description); } @@ -222,4 +220,471 @@ return $view; } + private function buildStatus() { + $repository = $this->getRepository(); + $viewer = $this->getViewer(); + $update_uri = $repository->getPathURI('edit/update/'); + + $view = id(new PHUIPropertyListView()) + ->setViewer($viewer); + + $view->addProperty( + pht('Update Frequency'), + $this->buildRepositoryUpdateInterval($repository)); + + $messages = $this->loadStatusMessages($repository); + + $status = $this->buildRepositoryStatus($repository, $messages); + $raw_error = $this->buildRepositoryRawError($repository, $messages); + + $view->addProperty(pht('Status'), $status); + if ($raw_error) { + $view->addSectionHeader(pht('Raw Error')); + $view->addTextContent($raw_error); + } + + $can_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + $repository, + PhabricatorPolicyCapability::CAN_EDIT); + + $button = id(new PHUIButtonView()) + ->setTag('a') + ->setIcon('fa-refresh') + ->setText(pht('Update Now')) + ->setWorkflow(true) + ->setDisabled(!$can_edit) + ->setHref($update_uri); + + return $this->newBox(pht('Status'), $view, array($button)); + } + + private function buildRepositoryUpdateInterval( + PhabricatorRepository $repository) { + + $smart_wait = $repository->loadUpdateInterval(); + + $doc_href = PhabricatorEnv::getDoclink( + 'Diffusion User Guide: Repository Updates'); + + return array( + phutil_format_relative_time_detailed($smart_wait), + " \xC2\xB7 ", + phutil_tag( + 'a', + array( + 'href' => $doc_href, + 'target' => '_blank', + ), + pht('Learn More')), + ); + } + + private function buildRepositoryStatus( + PhabricatorRepository $repository, + array $messages) { + + $viewer = $this->getViewer(); + $is_cluster = $repository->getAlmanacServicePHID(); + + $view = new PHUIStatusListView(); + + if ($repository->isTracked()) { + $view->addItem( + id(new PHUIStatusItemView()) + ->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green') + ->setTarget(pht('Repository Active'))); + } else { + $view->addItem( + id(new PHUIStatusItemView()) + ->setIcon(PHUIStatusItemView::ICON_WARNING, 'bluegrey') + ->setTarget(pht('Repository Inactive')) + ->setNote( + pht('Activate this repository to begin or resume import.'))); + return $view; + } + + $binaries = array(); + $svnlook_check = false; + switch ($repository->getVersionControlSystem()) { + case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: + $binaries[] = 'git'; + break; + case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: + $binaries[] = 'svn'; + break; + case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: + $binaries[] = 'hg'; + break; + } + + if ($repository->isHosted()) { + $proto_https = PhabricatorRepositoryURI::BUILTIN_PROTOCOL_HTTPS; + $proto_http = PhabricatorRepositoryURI::BUILTIN_PROTOCOL_HTTP; + $can_http = $repository->canServeProtocol($proto_http, false) || + $repository->canServeProtocol($proto_https, false); + + if ($can_http) { + switch ($repository->getVersionControlSystem()) { + case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: + $binaries[] = 'git-http-backend'; + break; + case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: + $binaries[] = 'svnserve'; + $binaries[] = 'svnadmin'; + $binaries[] = 'svnlook'; + $svnlook_check = true; + break; + case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: + $binaries[] = 'hg'; + break; + } + } + + + $proto_ssh = PhabricatorRepositoryURI::BUILTIN_PROTOCOL_SSH; + $can_ssh = $repository->canServeProtocol($proto_ssh, false); + + if ($can_ssh) { + switch ($repository->getVersionControlSystem()) { + case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: + $binaries[] = 'git-receive-pack'; + $binaries[] = 'git-upload-pack'; + break; + case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: + $binaries[] = 'svnserve'; + $binaries[] = 'svnadmin'; + $binaries[] = 'svnlook'; + $svnlook_check = true; + break; + case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: + $binaries[] = 'hg'; + break; + } + } + } + + $binaries = array_unique($binaries); + if (!$is_cluster) { + // We're only checking for binaries if we aren't running with a cluster + // configuration. In theory, we could check for binaries on the + // repository host machine, but we'd need to make this more complicated + // to do that. + + foreach ($binaries as $binary) { + $where = Filesystem::resolveBinary($binary); + if (!$where) { + $view->addItem( + id(new PHUIStatusItemView()) + ->setIcon(PHUIStatusItemView::ICON_WARNING, 'red') + ->setTarget( + pht('Missing Binary %s', phutil_tag('tt', array(), $binary))) + ->setNote(pht( + "Unable to find this binary in the webserver's PATH. You may ". + "need to configure %s.", + $this->getEnvConfigLink()))); + } else { + $view->addItem( + id(new PHUIStatusItemView()) + ->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green') + ->setTarget( + pht('Found Binary %s', phutil_tag('tt', array(), $binary))) + ->setNote(phutil_tag('tt', array(), $where))); + } + } + + // This gets checked generically above. However, for svn commit hooks, we + // need this to be in environment.append-paths because subversion strips + // PATH. + if ($svnlook_check) { + $where = Filesystem::resolveBinary('svnlook'); + if ($where) { + $path = substr($where, 0, strlen($where) - strlen('svnlook')); + $dirs = PhabricatorEnv::getEnvConfig('environment.append-paths'); + $in_path = false; + foreach ($dirs as $dir) { + if (Filesystem::isDescendant($path, $dir)) { + $in_path = true; + break; + } + } + if (!$in_path) { + $view->addItem( + id(new PHUIStatusItemView()) + ->setIcon(PHUIStatusItemView::ICON_WARNING, 'red') + ->setTarget( + pht('Missing Binary %s', phutil_tag('tt', array(), $binary))) + ->setNote(pht( + 'Unable to find this binary in `%s`. '. + 'You need to configure %s and include %s.', + 'environment.append-paths', + $this->getEnvConfigLink(), + $path))); + } + } + } + } + + $doc_href = PhabricatorEnv::getDoclink('Managing Daemons with phd'); + + $daemon_instructions = pht( + 'Use %s to start daemons. See %s.', + phutil_tag('tt', array(), 'bin/phd start'), + phutil_tag( + 'a', + array( + 'href' => $doc_href, + ), + pht('Managing Daemons with phd'))); + + + $pull_daemon = id(new PhabricatorDaemonLogQuery()) + ->setViewer(PhabricatorUser::getOmnipotentUser()) + ->withStatus(PhabricatorDaemonLogQuery::STATUS_ALIVE) + ->withDaemonClasses(array('PhabricatorRepositoryPullLocalDaemon')) + ->setLimit(1) + ->execute(); + + if ($pull_daemon) { + + // TODO: In a cluster environment, we need a daemon on this repository's + // host, specifically, and we aren't checking for that right now. This + // is a reasonable proxy for things being more-or-less correctly set up, + // though. + + $view->addItem( + id(new PHUIStatusItemView()) + ->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green') + ->setTarget(pht('Pull Daemon Running'))); + } else { + $view->addItem( + id(new PHUIStatusItemView()) + ->setIcon(PHUIStatusItemView::ICON_WARNING, 'red') + ->setTarget(pht('Pull Daemon Not Running')) + ->setNote($daemon_instructions)); + } + + + $task_daemon = id(new PhabricatorDaemonLogQuery()) + ->setViewer(PhabricatorUser::getOmnipotentUser()) + ->withStatus(PhabricatorDaemonLogQuery::STATUS_ALIVE) + ->withDaemonClasses(array('PhabricatorTaskmasterDaemon')) + ->setLimit(1) + ->execute(); + if ($task_daemon) { + $view->addItem( + id(new PHUIStatusItemView()) + ->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green') + ->setTarget(pht('Task Daemon Running'))); + } else { + $view->addItem( + id(new PHUIStatusItemView()) + ->setIcon(PHUIStatusItemView::ICON_WARNING, 'red') + ->setTarget(pht('Task Daemon Not Running')) + ->setNote($daemon_instructions)); + } + + + if ($is_cluster) { + // Just omit this status check for now in cluster environments. We + // could make a service call and pull it from the repository host + // eventually. + } else if ($repository->usesLocalWorkingCopy()) { + $local_parent = dirname($repository->getLocalPath()); + if (Filesystem::pathExists($local_parent)) { + $view->addItem( + id(new PHUIStatusItemView()) + ->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green') + ->setTarget(pht('Storage Directory OK')) + ->setNote(phutil_tag('tt', array(), $local_parent))); + } else { + $view->addItem( + id(new PHUIStatusItemView()) + ->setIcon(PHUIStatusItemView::ICON_WARNING, 'red') + ->setTarget(pht('No Storage Directory')) + ->setNote( + pht( + 'Storage directory %s does not exist, or is not readable by '. + 'the webserver. Create this directory or make it readable.', + phutil_tag('tt', array(), $local_parent)))); + return $view; + } + + $local_path = $repository->getLocalPath(); + $message = idx($messages, PhabricatorRepositoryStatusMessage::TYPE_INIT); + if ($message) { + switch ($message->getStatusCode()) { + case PhabricatorRepositoryStatusMessage::CODE_ERROR: + $view->addItem( + id(new PHUIStatusItemView()) + ->setIcon(PHUIStatusItemView::ICON_WARNING, 'red') + ->setTarget(pht('Initialization Error')) + ->setNote($message->getParameter('message'))); + return $view; + case PhabricatorRepositoryStatusMessage::CODE_OKAY: + if (Filesystem::pathExists($local_path)) { + $view->addItem( + id(new PHUIStatusItemView()) + ->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green') + ->setTarget(pht('Working Copy OK')) + ->setNote(phutil_tag('tt', array(), $local_path))); + } else { + $view->addItem( + id(new PHUIStatusItemView()) + ->setIcon(PHUIStatusItemView::ICON_WARNING, 'red') + ->setTarget(pht('Working Copy Error')) + ->setNote( + pht( + 'Working copy %s has been deleted, or is not '. + 'readable by the webserver. Make this directory '. + 'readable. If it has been deleted, the daemons should '. + 'restore it automatically.', + phutil_tag('tt', array(), $local_path)))); + return $view; + } + break; + default: + $view->addItem( + id(new PHUIStatusItemView()) + ->setIcon(PHUIStatusItemView::ICON_CLOCK, 'green') + ->setTarget(pht('Initializing Working Copy')) + ->setNote(pht('Daemons are initializing the working copy.'))); + return $view; + } + } else { + $view->addItem( + id(new PHUIStatusItemView()) + ->setIcon(PHUIStatusItemView::ICON_CLOCK, 'orange') + ->setTarget(pht('No Working Copy Yet')) + ->setNote( + pht('Waiting for daemons to build a working copy.'))); + return $view; + } + } + + $message = idx($messages, PhabricatorRepositoryStatusMessage::TYPE_FETCH); + if ($message) { + switch ($message->getStatusCode()) { + case PhabricatorRepositoryStatusMessage::CODE_ERROR: + $message = $message->getParameter('message'); + + $suggestion = null; + if (preg_match('/Permission denied \(publickey\)./', $message)) { + $suggestion = pht( + 'Public Key Error: This error usually indicates that the '. + 'keypair you have configured does not have permission to '. + 'access the repository.'); + } + + $view->addItem( + id(new PHUIStatusItemView()) + ->setIcon(PHUIStatusItemView::ICON_WARNING, 'red') + ->setTarget(pht('Update Error')) + ->setNote($suggestion)); + return $view; + case PhabricatorRepositoryStatusMessage::CODE_OKAY: + $ago = (PhabricatorTime::getNow() - $message->getEpoch()); + $view->addItem( + id(new PHUIStatusItemView()) + ->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green') + ->setTarget(pht('Updates OK')) + ->setNote( + pht( + 'Last updated %s (%s ago).', + phabricator_datetime($message->getEpoch(), $viewer), + phutil_format_relative_time_detailed($ago)))); + break; + } + } else { + $view->addItem( + id(new PHUIStatusItemView()) + ->setIcon(PHUIStatusItemView::ICON_CLOCK, 'orange') + ->setTarget(pht('Waiting For Update')) + ->setNote( + pht('Waiting for daemons to read updates.'))); + } + + if ($repository->isImporting()) { + $ratio = $repository->loadImportProgress(); + $percentage = sprintf('%.2f%%', 100 * $ratio); + + $view->addItem( + id(new PHUIStatusItemView()) + ->setIcon(PHUIStatusItemView::ICON_CLOCK, 'green') + ->setTarget(pht('Importing')) + ->setNote( + pht('%s Complete', $percentage))); + } else { + $view->addItem( + id(new PHUIStatusItemView()) + ->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green') + ->setTarget(pht('Fully Imported'))); + } + + if (idx($messages, PhabricatorRepositoryStatusMessage::TYPE_NEEDS_UPDATE)) { + $view->addItem( + id(new PHUIStatusItemView()) + ->setIcon(PHUIStatusItemView::ICON_UP, 'indigo') + ->setTarget(pht('Prioritized')) + ->setNote(pht('This repository will be updated soon!'))); + } + + return $view; + } + + private function buildRepositoryRawError( + PhabricatorRepository $repository, + array $messages) { + $viewer = $this->getViewer(); + + $can_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + $repository, + PhabricatorPolicyCapability::CAN_EDIT); + + $raw_error = null; + + $message = idx($messages, PhabricatorRepositoryStatusMessage::TYPE_FETCH); + if ($message) { + switch ($message->getStatusCode()) { + case PhabricatorRepositoryStatusMessage::CODE_ERROR: + $raw_error = $message->getParameter('message'); + break; + } + } + + if ($raw_error !== null) { + if (!$can_edit) { + $raw_message = pht( + 'You must be able to edit a repository to see raw error messages '. + 'because they sometimes disclose sensitive information.'); + $raw_message = phutil_tag('em', array(), $raw_message); + } else { + $raw_message = phutil_escape_html_newlines($raw_error); + } + } else { + $raw_message = null; + } + + return $raw_message; + } + + private function loadStatusMessages(PhabricatorRepository $repository) { + $messages = id(new PhabricatorRepositoryStatusMessage()) + ->loadAllWhere('repositoryID = %d', $repository->getID()); + $messages = mpull($messages, null, 'getStatusType'); + + return $messages; + } + + private function getEnvConfigLink() { + $config_href = '/config/edit/environment.append-paths/'; + return phutil_tag( + 'a', + array( + 'href' => $config_href, + ), + 'environment.append-paths'); + } + } diff --git a/src/applications/diffusion/management/DiffusionRepositoryBranchesManagementPanel.php b/src/applications/diffusion/management/DiffusionRepositoryBranchesManagementPanel.php --- a/src/applications/diffusion/management/DiffusionRepositoryBranchesManagementPanel.php +++ b/src/applications/diffusion/management/DiffusionRepositoryBranchesManagementPanel.php @@ -19,18 +19,7 @@ } public function getManagementPanelIcon() { - $repository = $this->getRepository(); - - $has_any = - $repository->getDetail('default-branch') || - $repository->getDetail('branch-filter') || - $repository->getDetail('close-commits-filter'); - - if ($has_any) { - return 'fa-code-fork'; - } else { - return 'fa-code-fork grey'; - } + return 'fa-code-fork'; } protected function getEditEngineFieldKeys() { @@ -41,29 +30,6 @@ ); } - public function buildManagementPanelCurtain() { - $repository = $this->getRepository(); - $viewer = $this->getViewer(); - $action_list = $this->getNewActionList(); - - $can_edit = PhabricatorPolicyFilter::hasCapability( - $viewer, - $repository, - PhabricatorPolicyCapability::CAN_EDIT); - - $branches_uri = $this->getEditPageURI(); - - $action_list->addAction( - id(new PhabricatorActionView()) - ->setIcon('fa-pencil') - ->setName(pht('Edit Branches')) - ->setHref($branches_uri) - ->setDisabled(!$can_edit) - ->setWorkflow(!$can_edit)); - - return $this->getNewCurtainView($action_list); - } - public function buildManagementPanelContent() { $repository = $this->getRepository(); $viewer = $this->getViewer(); @@ -94,7 +60,23 @@ } $view->addProperty(pht('Autoclose Only'), $autoclose_only); - $content[] = $this->newBox(pht('Branches'), $view); + + $can_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + $repository, + PhabricatorPolicyCapability::CAN_EDIT); + + $branches_uri = $this->getEditPageURI(); + + $button = id(new PHUIButtonView()) + ->setTag('a') + ->setIcon('fa-pencil') + ->setText(pht('Edit')) + ->setHref($branches_uri) + ->setDisabled(!$can_edit) + ->setWorkflow(!$can_edit); + + $content[] = $this->newBox(pht('Branches'), $view, array($button)); // Branch Autoclose Table if (!$repository->isImporting()) { @@ -176,11 +158,8 @@ true, )); - $box = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Branch Status')) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) - ->setTable($branch_table) - ->setPager($pager); + $box = $this->newBox(pht('Branch Status'), $branch_table); + $box->setPager($pager); $content[] = $box; } else { $content[] = id(new PHUIInfoView()) diff --git a/src/applications/diffusion/management/DiffusionRepositoryDocumentationManagementPanel.php b/src/applications/diffusion/management/DiffusionRepositoryDocumentationManagementPanel.php deleted file mode 100644 --- a/src/applications/diffusion/management/DiffusionRepositoryDocumentationManagementPanel.php +++ /dev/null @@ -1,33 +0,0 @@ -newTimeline(); } - public function buildManagementPanelCurtain() { - return null; - } - } diff --git a/src/applications/diffusion/management/DiffusionRepositoryManagementPanel.php b/src/applications/diffusion/management/DiffusionRepositoryManagementPanel.php --- a/src/applications/diffusion/management/DiffusionRepositoryManagementPanel.php +++ b/src/applications/diffusion/management/DiffusionRepositoryManagementPanel.php @@ -41,7 +41,6 @@ abstract public function getManagementPanelLabel(); abstract public function getManagementPanelOrder(); abstract public function buildManagementPanelContent(); - abstract public function buildManagementPanelCurtain(); public function getManagementPanelIcon() { return 'fa-pencil'; @@ -56,22 +55,6 @@ return true; } - public function getNewActionList() { - $viewer = $this->getViewer(); - $action_id = celerity_generate_unique_node_id(); - - return id(new PhabricatorActionListView()) - ->setViewer($viewer) - ->setID($action_id); - } - - public function getNewCurtainView(PhabricatorActionListView $action_list) { - $viewer = $this->getViewer(); - return id(new PHUICurtainView()) - ->setViewer($viewer) - ->setActionList($action_list); - } - public static function getAllPanels() { return id(new PhutilClassMapQuery()) ->setAncestorClass(__CLASS__) @@ -80,11 +63,20 @@ ->execute(); } - final protected function newBox($header_text, $body) { - return id(new PHUIObjectBoxView()) - ->setHeaderText($header_text) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) + final protected function newBox($header_text, $body, $button = array()) { + $header = id(new PHUIHeaderView()) + ->setHeader($header_text); + + foreach ($button as $link) { + $header->addActionLink($link); + } + + $view = id(new PHUIObjectBoxView()) + ->setHeader($header) + ->setBackground(PHUIObjectBoxView::WHITE_CONFIG) ->appendChild($body); + + return $view; } final protected function newTimeline() { diff --git a/src/applications/diffusion/management/DiffusionRepositoryPoliciesManagementPanel.php b/src/applications/diffusion/management/DiffusionRepositoryPoliciesManagementPanel.php --- a/src/applications/diffusion/management/DiffusionRepositoryPoliciesManagementPanel.php +++ b/src/applications/diffusion/management/DiffusionRepositoryPoliciesManagementPanel.php @@ -14,35 +14,7 @@ } public function getManagementPanelIcon() { - $viewer = $this->getViewer(); - $repository = $this->getRepository(); - - $can_view = PhabricatorPolicyCapability::CAN_VIEW; - $can_edit = PhabricatorPolicyCapability::CAN_EDIT; - $can_push = DiffusionPushCapability::CAPABILITY; - - $actual_values = array( - 'spacePHID' => $repository->getSpacePHID(), - 'view' => $repository->getPolicy($can_view), - 'edit' => $repository->getPolicy($can_edit), - 'push' => $repository->getPolicy($can_push), - ); - - $default = PhabricatorRepository::initializeNewRepository( - $viewer); - - $default_values = array( - 'spacePHID' => $default->getSpacePHID(), - 'view' => $default->getPolicy($can_view), - 'edit' => $default->getPolicy($can_edit), - 'push' => $default->getPolicy($can_push), - ); - - if ($actual_values === $default_values) { - return 'fa-lock grey'; - } else { - return 'fa-lock'; - } + return 'fa-lock'; } protected function getEditEngineFieldKeys() { @@ -54,29 +26,6 @@ ); } - public function buildManagementPanelCurtain() { - $repository = $this->getRepository(); - $viewer = $this->getViewer(); - $action_list = $this->getNewActionList(); - - $can_edit = PhabricatorPolicyFilter::hasCapability( - $viewer, - $repository, - PhabricatorPolicyCapability::CAN_EDIT); - - $edit_uri = $this->getEditPageURI(); - - $action_list->addAction( - id(new PhabricatorActionView()) - ->setIcon('fa-pencil') - ->setName(pht('Edit Policies')) - ->setHref($edit_uri) - ->setDisabled(!$can_edit) - ->setWorkflow(!$can_edit)); - - return $this->getNewCurtainView($action_list); - } - public function buildManagementPanelContent() { $repository = $this->getRepository(); $viewer = $this->getViewer(); @@ -109,7 +58,22 @@ : phutil_tag('em', array(), pht('Not a Hosted Repository')); $view->addProperty(pht('Pushable By'), $pushable); - return $this->newBox(pht('Policies'), $view); + $can_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + $repository, + PhabricatorPolicyCapability::CAN_EDIT); + + $edit_uri = $this->getEditPageURI(); + + $button = id(new PHUIButtonView()) + ->setTag('a') + ->setIcon('fa-pencil') + ->setText(pht('Edit')) + ->setHref($edit_uri) + ->setDisabled(!$can_edit) + ->setWorkflow(!$can_edit); + + return $this->newBox(pht('Policies'), $view, array($button)); } } diff --git a/src/applications/diffusion/management/DiffusionRepositoryStagingManagementPanel.php b/src/applications/diffusion/management/DiffusionRepositoryStagingManagementPanel.php --- a/src/applications/diffusion/management/DiffusionRepositoryStagingManagementPanel.php +++ b/src/applications/diffusion/management/DiffusionRepositoryStagingManagementPanel.php @@ -20,15 +20,7 @@ public function getManagementPanelIcon() { - $repository = $this->getRepository(); - - $staging_uri = $repository->getStagingURI(); - - if ($staging_uri) { - return 'fa-upload'; - } else { - return 'fa-upload grey'; - } + return 'fa-upload'; } protected function getEditEngineFieldKeys() { @@ -37,29 +29,6 @@ ); } - public function buildManagementPanelCurtain() { - $repository = $this->getRepository(); - $viewer = $this->getViewer(); - $action_list = $this->getNewActionList(); - - $can_edit = PhabricatorPolicyFilter::hasCapability( - $viewer, - $repository, - PhabricatorPolicyCapability::CAN_EDIT); - - $staging_uri = $this->getEditPageURI(); - - $action_list->addAction( - id(new PhabricatorActionView()) - ->setIcon('fa-pencil') - ->setName(pht('Edit Staging')) - ->setHref($staging_uri) - ->setDisabled(!$can_edit) - ->setWorkflow(!$can_edit)); - - return $this->getNewCurtainView($action_list); - } - public function buildManagementPanelContent() { $repository = $this->getRepository(); $viewer = $this->getViewer(); @@ -74,7 +43,22 @@ $view->addProperty(pht('Staging Area URI'), $staging_uri); - return $this->newBox(pht('Staging Area'), $view); + $can_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + $repository, + PhabricatorPolicyCapability::CAN_EDIT); + + $staging_uri = $this->getEditPageURI(); + + $button = id(new PHUIButtonView()) + ->setTag('a') + ->setIcon('fa-pencil') + ->setText(pht('Edit')) + ->setHref($staging_uri) + ->setDisabled(!$can_edit) + ->setWorkflow(!$can_edit); + + return $this->newBox(pht('Staging Area'), $view, array($button)); } } diff --git a/src/applications/diffusion/management/DiffusionRepositoryStatusManagementPanel.php b/src/applications/diffusion/management/DiffusionRepositoryStatusManagementPanel.php deleted file mode 100644 --- a/src/applications/diffusion/management/DiffusionRepositoryStatusManagementPanel.php +++ /dev/null @@ -1,507 +0,0 @@ -getRepository(); - - // TODO: We could try to show a warning icon in more cases, but just - // raise in the most serious cases for now. - $messages = $this->loadStatusMessages($repository); - - $raw_error = $this->buildRepositoryRawError($repository, $messages); - if ($raw_error) { - return 'fa-exclamation-triangle red'; - } - - return 'fa-check grey'; - } - - public function buildManagementPanelCurtain() { - $repository = $this->getRepository(); - $viewer = $this->getViewer(); - $action_list = $this->getNewActionList(); - - $can_edit = PhabricatorPolicyFilter::hasCapability( - $viewer, - $repository, - PhabricatorPolicyCapability::CAN_EDIT); - - $update_uri = $repository->getPathURI('edit/update/'); - - $action_list->addAction( - id(new PhabricatorActionView()) - ->setIcon('fa-refresh') - ->setName(pht('Update Now')) - ->setWorkflow(true) - ->setDisabled(!$can_edit) - ->setHref($update_uri)); - - return $this->getNewCurtainView($action_list); - } - - public function buildManagementPanelContent() { - $repository = $this->getRepository(); - $viewer = $this->getViewer(); - - $view = id(new PHUIPropertyListView()) - ->setViewer($viewer); - - $view->addProperty( - pht('Update Frequency'), - $this->buildRepositoryUpdateInterval($repository)); - - $messages = $this->loadStatusMessages($repository); - - $status = $this->buildRepositoryStatus($repository, $messages); - $raw_error = $this->buildRepositoryRawError($repository, $messages); - - $view->addProperty(pht('Status'), $status); - if ($raw_error) { - $view->addSectionHeader(pht('Raw Error')); - $view->addTextContent($raw_error); - } - - return $this->newBox(pht('Status'), $view); - } - - private function buildRepositoryUpdateInterval( - PhabricatorRepository $repository) { - - $smart_wait = $repository->loadUpdateInterval(); - - $doc_href = PhabricatorEnv::getDoclink( - 'Diffusion User Guide: Repository Updates'); - - return array( - phutil_format_relative_time_detailed($smart_wait), - " \xC2\xB7 ", - phutil_tag( - 'a', - array( - 'href' => $doc_href, - 'target' => '_blank', - ), - pht('Learn More')), - ); - } - - private function buildRepositoryStatus( - PhabricatorRepository $repository, - array $messages) { - - $viewer = $this->getViewer(); - $is_cluster = $repository->getAlmanacServicePHID(); - - $view = new PHUIStatusListView(); - - if ($repository->isTracked()) { - $view->addItem( - id(new PHUIStatusItemView()) - ->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green') - ->setTarget(pht('Repository Active'))); - } else { - $view->addItem( - id(new PHUIStatusItemView()) - ->setIcon(PHUIStatusItemView::ICON_WARNING, 'bluegrey') - ->setTarget(pht('Repository Inactive')) - ->setNote( - pht('Activate this repository to begin or resume import.'))); - return $view; - } - - $binaries = array(); - $svnlook_check = false; - switch ($repository->getVersionControlSystem()) { - case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: - $binaries[] = 'git'; - break; - case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: - $binaries[] = 'svn'; - break; - case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: - $binaries[] = 'hg'; - break; - } - - if ($repository->isHosted()) { - $proto_https = PhabricatorRepositoryURI::BUILTIN_PROTOCOL_HTTPS; - $proto_http = PhabricatorRepositoryURI::BUILTIN_PROTOCOL_HTTP; - $can_http = $repository->canServeProtocol($proto_http, false) || - $repository->canServeProtocol($proto_https, false); - - if ($can_http) { - switch ($repository->getVersionControlSystem()) { - case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: - $binaries[] = 'git-http-backend'; - break; - case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: - $binaries[] = 'svnserve'; - $binaries[] = 'svnadmin'; - $binaries[] = 'svnlook'; - $svnlook_check = true; - break; - case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: - $binaries[] = 'hg'; - break; - } - } - - - $proto_ssh = PhabricatorRepositoryURI::BUILTIN_PROTOCOL_SSH; - $can_ssh = $repository->canServeProtocol($proto_ssh, false); - - if ($can_ssh) { - switch ($repository->getVersionControlSystem()) { - case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: - $binaries[] = 'git-receive-pack'; - $binaries[] = 'git-upload-pack'; - break; - case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: - $binaries[] = 'svnserve'; - $binaries[] = 'svnadmin'; - $binaries[] = 'svnlook'; - $svnlook_check = true; - break; - case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: - $binaries[] = 'hg'; - break; - } - } - } - - $binaries = array_unique($binaries); - if (!$is_cluster) { - // We're only checking for binaries if we aren't running with a cluster - // configuration. In theory, we could check for binaries on the - // repository host machine, but we'd need to make this more complicated - // to do that. - - foreach ($binaries as $binary) { - $where = Filesystem::resolveBinary($binary); - if (!$where) { - $view->addItem( - id(new PHUIStatusItemView()) - ->setIcon(PHUIStatusItemView::ICON_WARNING, 'red') - ->setTarget( - pht('Missing Binary %s', phutil_tag('tt', array(), $binary))) - ->setNote(pht( - "Unable to find this binary in the webserver's PATH. You may ". - "need to configure %s.", - $this->getEnvConfigLink()))); - } else { - $view->addItem( - id(new PHUIStatusItemView()) - ->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green') - ->setTarget( - pht('Found Binary %s', phutil_tag('tt', array(), $binary))) - ->setNote(phutil_tag('tt', array(), $where))); - } - } - - // This gets checked generically above. However, for svn commit hooks, we - // need this to be in environment.append-paths because subversion strips - // PATH. - if ($svnlook_check) { - $where = Filesystem::resolveBinary('svnlook'); - if ($where) { - $path = substr($where, 0, strlen($where) - strlen('svnlook')); - $dirs = PhabricatorEnv::getEnvConfig('environment.append-paths'); - $in_path = false; - foreach ($dirs as $dir) { - if (Filesystem::isDescendant($path, $dir)) { - $in_path = true; - break; - } - } - if (!$in_path) { - $view->addItem( - id(new PHUIStatusItemView()) - ->setIcon(PHUIStatusItemView::ICON_WARNING, 'red') - ->setTarget( - pht('Missing Binary %s', phutil_tag('tt', array(), $binary))) - ->setNote(pht( - 'Unable to find this binary in `%s`. '. - 'You need to configure %s and include %s.', - 'environment.append-paths', - $this->getEnvConfigLink(), - $path))); - } - } - } - } - - $doc_href = PhabricatorEnv::getDoclink('Managing Daemons with phd'); - - $daemon_instructions = pht( - 'Use %s to start daemons. See %s.', - phutil_tag('tt', array(), 'bin/phd start'), - phutil_tag( - 'a', - array( - 'href' => $doc_href, - ), - pht('Managing Daemons with phd'))); - - - $pull_daemon = id(new PhabricatorDaemonLogQuery()) - ->setViewer(PhabricatorUser::getOmnipotentUser()) - ->withStatus(PhabricatorDaemonLogQuery::STATUS_ALIVE) - ->withDaemonClasses(array('PhabricatorRepositoryPullLocalDaemon')) - ->setLimit(1) - ->execute(); - - if ($pull_daemon) { - - // TODO: In a cluster environment, we need a daemon on this repository's - // host, specifically, and we aren't checking for that right now. This - // is a reasonable proxy for things being more-or-less correctly set up, - // though. - - $view->addItem( - id(new PHUIStatusItemView()) - ->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green') - ->setTarget(pht('Pull Daemon Running'))); - } else { - $view->addItem( - id(new PHUIStatusItemView()) - ->setIcon(PHUIStatusItemView::ICON_WARNING, 'red') - ->setTarget(pht('Pull Daemon Not Running')) - ->setNote($daemon_instructions)); - } - - - $task_daemon = id(new PhabricatorDaemonLogQuery()) - ->setViewer(PhabricatorUser::getOmnipotentUser()) - ->withStatus(PhabricatorDaemonLogQuery::STATUS_ALIVE) - ->withDaemonClasses(array('PhabricatorTaskmasterDaemon')) - ->setLimit(1) - ->execute(); - if ($task_daemon) { - $view->addItem( - id(new PHUIStatusItemView()) - ->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green') - ->setTarget(pht('Task Daemon Running'))); - } else { - $view->addItem( - id(new PHUIStatusItemView()) - ->setIcon(PHUIStatusItemView::ICON_WARNING, 'red') - ->setTarget(pht('Task Daemon Not Running')) - ->setNote($daemon_instructions)); - } - - - if ($is_cluster) { - // Just omit this status check for now in cluster environments. We - // could make a service call and pull it from the repository host - // eventually. - } else if ($repository->usesLocalWorkingCopy()) { - $local_parent = dirname($repository->getLocalPath()); - if (Filesystem::pathExists($local_parent)) { - $view->addItem( - id(new PHUIStatusItemView()) - ->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green') - ->setTarget(pht('Storage Directory OK')) - ->setNote(phutil_tag('tt', array(), $local_parent))); - } else { - $view->addItem( - id(new PHUIStatusItemView()) - ->setIcon(PHUIStatusItemView::ICON_WARNING, 'red') - ->setTarget(pht('No Storage Directory')) - ->setNote( - pht( - 'Storage directory %s does not exist, or is not readable by '. - 'the webserver. Create this directory or make it readable.', - phutil_tag('tt', array(), $local_parent)))); - return $view; - } - - $local_path = $repository->getLocalPath(); - $message = idx($messages, PhabricatorRepositoryStatusMessage::TYPE_INIT); - if ($message) { - switch ($message->getStatusCode()) { - case PhabricatorRepositoryStatusMessage::CODE_ERROR: - $view->addItem( - id(new PHUIStatusItemView()) - ->setIcon(PHUIStatusItemView::ICON_WARNING, 'red') - ->setTarget(pht('Initialization Error')) - ->setNote($message->getParameter('message'))); - return $view; - case PhabricatorRepositoryStatusMessage::CODE_OKAY: - if (Filesystem::pathExists($local_path)) { - $view->addItem( - id(new PHUIStatusItemView()) - ->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green') - ->setTarget(pht('Working Copy OK')) - ->setNote(phutil_tag('tt', array(), $local_path))); - } else { - $view->addItem( - id(new PHUIStatusItemView()) - ->setIcon(PHUIStatusItemView::ICON_WARNING, 'red') - ->setTarget(pht('Working Copy Error')) - ->setNote( - pht( - 'Working copy %s has been deleted, or is not '. - 'readable by the webserver. Make this directory '. - 'readable. If it has been deleted, the daemons should '. - 'restore it automatically.', - phutil_tag('tt', array(), $local_path)))); - return $view; - } - break; - default: - $view->addItem( - id(new PHUIStatusItemView()) - ->setIcon(PHUIStatusItemView::ICON_CLOCK, 'green') - ->setTarget(pht('Initializing Working Copy')) - ->setNote(pht('Daemons are initializing the working copy.'))); - return $view; - } - } else { - $view->addItem( - id(new PHUIStatusItemView()) - ->setIcon(PHUIStatusItemView::ICON_CLOCK, 'orange') - ->setTarget(pht('No Working Copy Yet')) - ->setNote( - pht('Waiting for daemons to build a working copy.'))); - return $view; - } - } - - $message = idx($messages, PhabricatorRepositoryStatusMessage::TYPE_FETCH); - if ($message) { - switch ($message->getStatusCode()) { - case PhabricatorRepositoryStatusMessage::CODE_ERROR: - $message = $message->getParameter('message'); - - $suggestion = null; - if (preg_match('/Permission denied \(publickey\)./', $message)) { - $suggestion = pht( - 'Public Key Error: This error usually indicates that the '. - 'keypair you have configured does not have permission to '. - 'access the repository.'); - } - - $view->addItem( - id(new PHUIStatusItemView()) - ->setIcon(PHUIStatusItemView::ICON_WARNING, 'red') - ->setTarget(pht('Update Error')) - ->setNote($suggestion)); - return $view; - case PhabricatorRepositoryStatusMessage::CODE_OKAY: - $ago = (PhabricatorTime::getNow() - $message->getEpoch()); - $view->addItem( - id(new PHUIStatusItemView()) - ->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green') - ->setTarget(pht('Updates OK')) - ->setNote( - pht( - 'Last updated %s (%s ago).', - phabricator_datetime($message->getEpoch(), $viewer), - phutil_format_relative_time_detailed($ago)))); - break; - } - } else { - $view->addItem( - id(new PHUIStatusItemView()) - ->setIcon(PHUIStatusItemView::ICON_CLOCK, 'orange') - ->setTarget(pht('Waiting For Update')) - ->setNote( - pht('Waiting for daemons to read updates.'))); - } - - if ($repository->isImporting()) { - $ratio = $repository->loadImportProgress(); - $percentage = sprintf('%.2f%%', 100 * $ratio); - - $view->addItem( - id(new PHUIStatusItemView()) - ->setIcon(PHUIStatusItemView::ICON_CLOCK, 'green') - ->setTarget(pht('Importing')) - ->setNote( - pht('%s Complete', $percentage))); - } else { - $view->addItem( - id(new PHUIStatusItemView()) - ->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green') - ->setTarget(pht('Fully Imported'))); - } - - if (idx($messages, PhabricatorRepositoryStatusMessage::TYPE_NEEDS_UPDATE)) { - $view->addItem( - id(new PHUIStatusItemView()) - ->setIcon(PHUIStatusItemView::ICON_UP, 'indigo') - ->setTarget(pht('Prioritized')) - ->setNote(pht('This repository will be updated soon!'))); - } - - return $view; - } - - private function buildRepositoryRawError( - PhabricatorRepository $repository, - array $messages) { - $viewer = $this->getViewer(); - - $can_edit = PhabricatorPolicyFilter::hasCapability( - $viewer, - $repository, - PhabricatorPolicyCapability::CAN_EDIT); - - $raw_error = null; - - $message = idx($messages, PhabricatorRepositoryStatusMessage::TYPE_FETCH); - if ($message) { - switch ($message->getStatusCode()) { - case PhabricatorRepositoryStatusMessage::CODE_ERROR: - $raw_error = $message->getParameter('message'); - break; - } - } - - if ($raw_error !== null) { - if (!$can_edit) { - $raw_message = pht( - 'You must be able to edit a repository to see raw error messages '. - 'because they sometimes disclose sensitive information.'); - $raw_message = phutil_tag('em', array(), $raw_message); - } else { - $raw_message = phutil_escape_html_newlines($raw_error); - } - } else { - $raw_message = null; - } - - return $raw_message; - } - - private function loadStatusMessages(PhabricatorRepository $repository) { - $messages = id(new PhabricatorRepositoryStatusMessage()) - ->loadAllWhere('repositoryID = %d', $repository->getID()); - $messages = mpull($messages, null, 'getStatusType'); - - return $messages; - } - - private function getEnvConfigLink() { - $config_href = '/config/edit/environment.append-paths/'; - return phutil_tag( - 'a', - array( - 'href' => $config_href, - ), - 'environment.append-paths'); - } - -} diff --git a/src/applications/diffusion/management/DiffusionRepositoryStorageManagementPanel.php b/src/applications/diffusion/management/DiffusionRepositoryStorageManagementPanel.php --- a/src/applications/diffusion/management/DiffusionRepositoryStorageManagementPanel.php +++ b/src/applications/diffusion/management/DiffusionRepositoryStorageManagementPanel.php @@ -14,31 +14,7 @@ } public function getManagementPanelIcon() { - $repository = $this->getRepository(); - - if ($repository->getAlmanacServicePHID()) { - return 'fa-sitemap'; - } else if ($repository->isHosted()) { - return 'fa-folder'; - } else { - return 'fa-download'; - } - } - - public function buildManagementPanelCurtain() { - $repository = $this->getRepository(); - $viewer = $this->getViewer(); - $action_list = $this->getNewActionList(); - - $doc_href = PhabricatorEnv::getDoclink('Cluster: Repositories'); - - $action_list->addAction( - id(new PhabricatorActionView()) - ->setIcon('fa-book') - ->setHref($doc_href) - ->setName(pht('Cluster Documentation'))); - - return $this->getNewCurtainView($action_list); + return 'fa-database'; } public function buildManagementPanelContent() { @@ -71,9 +47,15 @@ $view->addProperty(pht('Storage Path'), $storage_path); $view->addProperty(pht('Storage Cluster'), $storage_service); - $box = $this->newBox(pht('Storage'), null); - $box->addPropertyList($view); - return $box; + $doc_href = PhabricatorEnv::getDoclink('Cluster: Repositories'); + + $button = id(new PHUIButtonView()) + ->setTag('a') + ->setIcon('fa-book') + ->setHref($doc_href) + ->setText(pht('Help')); + + return $this->newBox(pht('Storage'), $view, array($button)); } private function buildClusterStatusPanel() { @@ -243,9 +225,7 @@ 'date', )); - $box = $this->newBox(pht('Cluster Status'), null); - $box->setTable($table); - return $box; + return $this->newBox(pht('Cluster Status'), $table); } } diff --git a/src/applications/diffusion/management/DiffusionRepositorySubversionManagementPanel.php b/src/applications/diffusion/management/DiffusionRepositorySubversionManagementPanel.php --- a/src/applications/diffusion/management/DiffusionRepositorySubversionManagementPanel.php +++ b/src/applications/diffusion/management/DiffusionRepositorySubversionManagementPanel.php @@ -19,15 +19,7 @@ } public function getManagementPanelIcon() { - $repository = $this->getRepository(); - - $has_any = (bool)$repository->getDetail('svn-subpath'); - - if ($has_any) { - return 'fa-database'; - } else { - return 'fa-database grey'; - } + return 'fa-folder'; } protected function getEditEngineFieldKeys() { @@ -36,29 +28,6 @@ ); } - public function buildManagementPanelCurtain() { - $repository = $this->getRepository(); - $viewer = $this->getViewer(); - $action_list = $this->getNewActionList(); - - $can_edit = PhabricatorPolicyFilter::hasCapability( - $viewer, - $repository, - PhabricatorPolicyCapability::CAN_EDIT); - - $subversion_uri = $this->getEditPageURI(); - - $action_list->addAction( - id(new PhabricatorActionView()) - ->setIcon('fa-pencil') - ->setName(pht('Edit Properties')) - ->setHref($subversion_uri) - ->setDisabled(!$can_edit) - ->setWorkflow(!$can_edit)); - - return $this->getNewCurtainView($action_list); - } - public function buildManagementPanelContent() { $repository = $this->getRepository(); $viewer = $this->getViewer(); @@ -71,8 +40,22 @@ phutil_tag('em', array(), pht('Import Entire Repository'))); $view->addProperty(pht('Import Only'), $default_branch); + $can_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + $repository, + PhabricatorPolicyCapability::CAN_EDIT); + + $subversion_uri = $this->getEditPageURI(); + + $button = id(new PHUIButtonView()) + ->setTag('a') + ->setIcon('fa-pencil') + ->setText(pht('Edit')) + ->setHref($subversion_uri) + ->setDisabled(!$can_edit) + ->setWorkflow(!$can_edit); - return $this->newBox(pht('Subversion'), $view); + return $this->newBox(pht('Subversion'), $view, array($button)); } } diff --git a/src/applications/diffusion/management/DiffusionRepositorySymbolsManagementPanel.php b/src/applications/diffusion/management/DiffusionRepositorySymbolsManagementPanel.php --- a/src/applications/diffusion/management/DiffusionRepositorySymbolsManagementPanel.php +++ b/src/applications/diffusion/management/DiffusionRepositorySymbolsManagementPanel.php @@ -14,17 +14,7 @@ } public function getManagementPanelIcon() { - $repository = $this->getRepository(); - - $has_any = - $repository->getSymbolLanguages() || - $repository->getSymbolSources(); - - if ($has_any) { - return 'fa-link'; - } else { - return 'fa-link grey'; - } + return 'fa-bullseye'; } protected function getEditEngineFieldKeys() { @@ -34,29 +24,6 @@ ); } - public function buildManagementPanelCurtain() { - $repository = $this->getRepository(); - $viewer = $this->getViewer(); - $action_list = $this->getNewActionList(); - - $can_edit = PhabricatorPolicyFilter::hasCapability( - $viewer, - $repository, - PhabricatorPolicyCapability::CAN_EDIT); - - $symbols_uri = $this->getEditPageURI(); - - $action_list->addAction( - id(new PhabricatorActionView()) - ->setIcon('fa-pencil') - ->setName(pht('Edit Symbols')) - ->setHref($symbols_uri) - ->setDisabled(!$can_edit) - ->setWorkflow(!$can_edit)); - - return $this->getNewCurtainView($action_list); - } - public function buildManagementPanelContent() { $repository = $this->getRepository(); $viewer = $this->getViewer(); @@ -80,7 +47,22 @@ } $view->addProperty(pht('Uses Symbols From'), $sources); - return $this->newBox(pht('Symbols'), $view); + $can_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + $repository, + PhabricatorPolicyCapability::CAN_EDIT); + + $symbols_uri = $this->getEditPageURI(); + + $button = id(new PHUIButtonView()) + ->setTag('a') + ->setIcon('fa-pencil') + ->setText(pht('Edit')) + ->setHref($symbols_uri) + ->setDisabled(!$can_edit) + ->setWorkflow(!$can_edit); + + return $this->newBox(pht('Symbols'), $view, array($button)); } } diff --git a/src/applications/diffusion/management/DiffusionRepositoryURIsManagementPanel.php b/src/applications/diffusion/management/DiffusionRepositoryURIsManagementPanel.php --- a/src/applications/diffusion/management/DiffusionRepositoryURIsManagementPanel.php +++ b/src/applications/diffusion/management/DiffusionRepositoryURIsManagementPanel.php @@ -10,42 +10,13 @@ } public function getManagementPanelIcon() { - return 'fa-cogs'; + return 'fa-globe'; } public function getManagementPanelOrder() { return 400; } - public function buildManagementPanelCurtain() { - $repository = $this->getRepository(); - $viewer = $this->getViewer(); - $action_list = $this->getNewActionList(); - - $can_edit = PhabricatorPolicyFilter::hasCapability( - $viewer, - $repository, - PhabricatorPolicyCapability::CAN_EDIT); - - $doc_href = PhabricatorEnv::getDoclink('Diffusion User Guide: URIs'); - $add_href = $repository->getPathURI('uri/edit/'); - - $action_list->addAction( - id(new PhabricatorActionView()) - ->setIcon('fa-plus') - ->setHref($add_href) - ->setDisabled(!$can_edit) - ->setName(pht('Add New URI'))); - - $action_list->addAction( - id(new PhabricatorActionView()) - ->setIcon('fa-book') - ->setHref($doc_href) - ->setName(pht('URI Documentation'))); - - return $this->getNewCurtainView($action_list); - } - public function buildManagementPanelContent() { $repository = $this->getRepository(); $viewer = $this->getViewer(); @@ -151,10 +122,30 @@ ->setSeverity(PHUIInfoView::SEVERITY_NOTICE) ->setErrors($messages); - $box = $this->newBox(pht('Repository URIs'), null); - $box->setTable($table); + $can_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + $repository, + PhabricatorPolicyCapability::CAN_EDIT); + + $doc_href = PhabricatorEnv::getDoclink('Diffusion User Guide: URIs'); + $add_href = $repository->getPathURI('uri/edit/'); + + $add = id(new PHUIButtonView()) + ->setTag('a') + ->setIcon('fa-plus') + ->setHref($add_href) + ->setDisabled(!$can_edit) + ->setText(pht('New URI')); + + $help = id(new PHUIButtonView()) + ->setTag('a') + ->setIcon('fa-book') + ->setHref($doc_href) + ->setText(pht('Help')); + + $box = $this->newBox(pht('Repository URIs'), $table, array($add, $help)); - return array($info_view, $box); + return array($box, $info_view); } } diff --git a/webroot/rsrc/css/phui/phui-box.css b/webroot/rsrc/css/phui/phui-box.css --- a/webroot/rsrc/css/phui/phui-box.css +++ b/webroot/rsrc/css/phui/phui-box.css @@ -136,3 +136,8 @@ .phui-box-white-config .phui-header-header { color: {$bluetext}; } + +.phui-box-white-config .phui-header-action-links .button { + margin-top: 0; + margin-bottom: 0; +} diff --git a/webroot/rsrc/css/phui/phui-header-view.css b/webroot/rsrc/css/phui/phui-header-view.css --- a/webroot/rsrc/css/phui/phui-header-view.css +++ b/webroot/rsrc/css/phui/phui-header-view.css @@ -337,6 +337,10 @@ color: {$blacktext}; } +.phui-profile-header.phui-header-shell .phui-header-header a { + color: {$blacktext}; +} + .phui-profile-header .phui-header-col3 { vertical-align: top; }